diff options
Diffstat (limited to 'Doc/includes')
59 files changed, 2274 insertions, 1370 deletions
diff --git a/Doc/includes/capsulethunk.h b/Doc/includes/capsulethunk.h new file mode 100644 index 0000000..6b20564 --- /dev/null +++ b/Doc/includes/capsulethunk.h @@ -0,0 +1,134 @@ +#ifndef __CAPSULETHUNK_H +#define __CAPSULETHUNK_H + +#if ( (PY_VERSION_HEX < 0x02070000) \ + || ((PY_VERSION_HEX >= 0x03000000) \ + && (PY_VERSION_HEX < 0x03010000)) ) + +#define __PyCapsule_GetField(capsule, field, default_value) \ + ( PyCapsule_CheckExact(capsule) \ + ? (((PyCObject *)capsule)->field) \ + : (default_value) \ + ) \ + +#define __PyCapsule_SetField(capsule, field, value) \ + ( PyCapsule_CheckExact(capsule) \ + ? (((PyCObject *)capsule)->field = value), 1 \ + : 0 \ + ) \ + + +#define PyCapsule_Type PyCObject_Type + +#define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) +#define PyCapsule_IsValid(capsule, name) (PyCObject_Check(capsule)) + + +#define PyCapsule_New(pointer, name, destructor) \ + (PyCObject_FromVoidPtr(pointer, destructor)) + + +#define PyCapsule_GetPointer(capsule, name) \ + (PyCObject_AsVoidPtr(capsule)) + +/* Don't call PyCObject_SetPointer here, it fails if there's a destructor */ +#define PyCapsule_SetPointer(capsule, pointer) \ + __PyCapsule_SetField(capsule, cobject, pointer) + + +#define PyCapsule_GetDestructor(capsule) \ + __PyCapsule_GetField(capsule, destructor) + +#define PyCapsule_SetDestructor(capsule, dtor) \ + __PyCapsule_SetField(capsule, destructor, dtor) + + +/* + * Sorry, there's simply no place + * to store a Capsule "name" in a CObject. + */ +#define PyCapsule_GetName(capsule) NULL + +static int +PyCapsule_SetName(PyObject *capsule, const char *unused) +{ + unused = unused; + PyErr_SetString(PyExc_NotImplementedError, + "can't use PyCapsule_SetName with CObjects"); + return 1; +} + + + +#define PyCapsule_GetContext(capsule) \ + __PyCapsule_GetField(capsule, descr) + +#define PyCapsule_SetContext(capsule, context) \ + __PyCapsule_SetField(capsule, descr, context) + + +static void * +PyCapsule_Import(const char *name, int no_block) +{ + PyObject *object = NULL; + void *return_value = NULL; + char *trace; + size_t name_length = (strlen(name) + 1) * sizeof(char); + char *name_dup = (char *)PyMem_MALLOC(name_length); + + if (!name_dup) { + return NULL; + } + + memcpy(name_dup, name, name_length); + + trace = name_dup; + while (trace) { + char *dot = strchr(trace, '.'); + if (dot) { + *dot++ = '\0'; + } + + if (object == NULL) { + if (no_block) { + object = PyImport_ImportModuleNoBlock(trace); + } else { + object = PyImport_ImportModule(trace); + if (!object) { + PyErr_Format(PyExc_ImportError, + "PyCapsule_Import could not " + "import module \"%s\"", trace); + } + } + } else { + PyObject *object2 = PyObject_GetAttrString(object, trace); + Py_DECREF(object); + object = object2; + } + if (!object) { + goto EXIT; + } + + trace = dot; + } + + if (PyCObject_Check(object)) { + PyCObject *cobject = (PyCObject *)object; + return_value = cobject->cobject; + } else { + PyErr_Format(PyExc_AttributeError, + "PyCapsule_Import \"%s\" is not valid", + name); + } + +EXIT: + Py_XDECREF(object); + if (name_dup) { + PyMem_FREE(name_dup); + } + return return_value; +} + +#endif /* #if PY_VERSION_HEX < 0x02070000 */ + +#endif /* __CAPSULETHUNK_H */ diff --git a/Doc/includes/custom.c b/Doc/includes/custom.c deleted file mode 100644 index bda32e2..0000000 --- a/Doc/includes/custom.c +++ /dev/null @@ -1,45 +0,0 @@ -#define PY_SSIZE_T_CLEAN -#include <Python.h> - -typedef struct { - PyObject_HEAD - /* Type-specific fields go here. */ -} CustomObject; - -static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "custom.Custom", - .tp_doc = "Custom objects", - .tp_basicsize = sizeof(CustomObject), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_new = PyType_GenericNew, -}; - -static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, - .m_name = "custom", - .m_doc = "Example module that creates an extension type.", - .m_size = -1, -}; - -PyMODINIT_FUNC -PyInit_custom(void) -{ - PyObject *m; - if (PyType_Ready(&CustomType) < 0) - return NULL; - - m = PyModule_Create(&custommodule); - if (m == NULL) - return NULL; - - Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { - Py_DECREF(&CustomType); - PY_DECREF(m); - return NULL; - } - - return m; -} diff --git a/Doc/includes/custom2.c b/Doc/includes/custom2.c deleted file mode 100644 index 5bacab7..0000000 --- a/Doc/includes/custom2.c +++ /dev/null @@ -1,138 +0,0 @@ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; /* first name */ - PyObject *last; /* last name */ - int number; -} CustomObject; - -static void -Custom_dealloc(CustomObject *self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject *) self); -} - -static PyObject * -Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - CustomObject *self; - self = (CustomObject *) type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - self->number = 0; - } - return (PyObject *) self; -} - -static int -Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"first", "last", "number", NULL}; - PyObject *first = NULL, *last = NULL, *tmp; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_XDECREF(tmp); - } - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_XDECREF(tmp); - } - return 0; -} - -static PyMemberDef Custom_members[] = { - {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0, - "last name"}, - {"number", T_INT, offsetof(CustomObject, number), 0, - "custom number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) -{ - if (self->first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); - return NULL; - } - if (self->last == NULL) { - PyErr_SetString(PyExc_AttributeError, "last"); - return NULL; - } - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Custom_methods[] = { - {"name", (PyCFunction) Custom_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "custom2.Custom", - .tp_doc = "Custom objects", - .tp_basicsize = sizeof(CustomObject), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_new = Custom_new, - .tp_init = (initproc) Custom_init, - .tp_dealloc = (destructor) Custom_dealloc, - .tp_members = Custom_members, - .tp_methods = Custom_methods, -}; - -static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, - .m_name = "custom2", - .m_doc = "Example module that creates an extension type.", - .m_size = -1, -}; - -PyMODINIT_FUNC -PyInit_custom2(void) -{ - PyObject *m; - if (PyType_Ready(&CustomType) < 0) - return NULL; - - m = PyModule_Create(&custommodule); - if (m == NULL) - return NULL; - - Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { - Py_DECREF(&CustomType); - Py_DECREF(m); - return NULL; - } - - return m; -} diff --git a/Doc/includes/custom3.c b/Doc/includes/custom3.c deleted file mode 100644 index 2b7a99e..0000000 --- a/Doc/includes/custom3.c +++ /dev/null @@ -1,189 +0,0 @@ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; /* first name */ - PyObject *last; /* last name */ - int number; -} CustomObject; - -static void -Custom_dealloc(CustomObject *self) -{ - Py_XDECREF(self->first); - Py_XDECREF(self->last); - Py_TYPE(self)->tp_free((PyObject *) self); -} - -static PyObject * -Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - CustomObject *self; - self = (CustomObject *) type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - self->number = 0; - } - return (PyObject *) self; -} - -static int -Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"first", "last", "number", NULL}; - PyObject *first = NULL, *last = NULL, *tmp; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - return 0; -} - -static PyMemberDef Custom_members[] = { - {"number", T_INT, offsetof(CustomObject, number), 0, - "custom number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Custom_getfirst(CustomObject *self, void *closure) -{ - Py_INCREF(self->first); - return self->first; -} - -static int -Custom_setfirst(CustomObject *self, PyObject *value, void *closure) -{ - PyObject *tmp; - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - if (!PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a string"); - return -1; - } - tmp = self->first; - Py_INCREF(value); - self->first = value; - Py_DECREF(tmp); - return 0; -} - -static PyObject * -Custom_getlast(CustomObject *self, void *closure) -{ - Py_INCREF(self->last); - return self->last; -} - -static int -Custom_setlast(CustomObject *self, PyObject *value, void *closure) -{ - PyObject *tmp; - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); - return -1; - } - if (!PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The last attribute value must be a string"); - return -1; - } - tmp = self->last; - Py_INCREF(value); - self->last = value; - Py_DECREF(tmp); - return 0; -} - -static PyGetSetDef Custom_getsetters[] = { - {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, - "first name", NULL}, - {"last", (getter) Custom_getlast, (setter) Custom_setlast, - "last name", NULL}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) -{ - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Custom_methods[] = { - {"name", (PyCFunction) Custom_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "custom3.Custom", - .tp_doc = "Custom objects", - .tp_basicsize = sizeof(CustomObject), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_new = Custom_new, - .tp_init = (initproc) Custom_init, - .tp_dealloc = (destructor) Custom_dealloc, - .tp_members = Custom_members, - .tp_methods = Custom_methods, - .tp_getset = Custom_getsetters, -}; - -static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, - .m_name = "custom3", - .m_doc = "Example module that creates an extension type.", - .m_size = -1, -}; - -PyMODINIT_FUNC -PyInit_custom3(void) -{ - PyObject *m; - if (PyType_Ready(&CustomType) < 0) - return NULL; - - m = PyModule_Create(&custommodule); - if (m == NULL) - return NULL; - - Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { - Py_DECREF(&CustomType); - Py_DECREF(m); - return NULL; - } - - return m; -} diff --git a/Doc/includes/custom4.c b/Doc/includes/custom4.c deleted file mode 100644 index 584992f..0000000 --- a/Doc/includes/custom4.c +++ /dev/null @@ -1,203 +0,0 @@ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "structmember.h" - -typedef struct { - PyObject_HEAD - PyObject *first; /* first name */ - PyObject *last; /* last name */ - int number; -} CustomObject; - -static int -Custom_traverse(CustomObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->first); - Py_VISIT(self->last); - return 0; -} - -static int -Custom_clear(CustomObject *self) -{ - Py_CLEAR(self->first); - Py_CLEAR(self->last); - return 0; -} - -static void -Custom_dealloc(CustomObject *self) -{ - PyObject_GC_UnTrack(self); - Custom_clear(self); - Py_TYPE(self)->tp_free((PyObject *) self); -} - -static PyObject * -Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - CustomObject *self; - self = (CustomObject *) type->tp_alloc(type, 0); - if (self != NULL) { - self->first = PyUnicode_FromString(""); - if (self->first == NULL) { - Py_DECREF(self); - return NULL; - } - self->last = PyUnicode_FromString(""); - if (self->last == NULL) { - Py_DECREF(self); - return NULL; - } - self->number = 0; - } - return (PyObject *) self; -} - -static int -Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"first", "last", "number", NULL}; - PyObject *first = NULL, *last = NULL, *tmp; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, - &first, &last, - &self->number)) - return -1; - - if (first) { - tmp = self->first; - Py_INCREF(first); - self->first = first; - Py_DECREF(tmp); - } - if (last) { - tmp = self->last; - Py_INCREF(last); - self->last = last; - Py_DECREF(tmp); - } - return 0; -} - -static PyMemberDef Custom_members[] = { - {"number", T_INT, offsetof(CustomObject, number), 0, - "custom number"}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Custom_getfirst(CustomObject *self, void *closure) -{ - Py_INCREF(self->first); - return self->first; -} - -static int -Custom_setfirst(CustomObject *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); - return -1; - } - if (!PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The first attribute value must be a string"); - return -1; - } - Py_INCREF(value); - Py_CLEAR(self->first); - self->first = value; - return 0; -} - -static PyObject * -Custom_getlast(CustomObject *self, void *closure) -{ - Py_INCREF(self->last); - return self->last; -} - -static int -Custom_setlast(CustomObject *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); - return -1; - } - if (!PyUnicode_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The last attribute value must be a string"); - return -1; - } - Py_INCREF(value); - Py_CLEAR(self->last); - self->last = value; - return 0; -} - -static PyGetSetDef Custom_getsetters[] = { - {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, - "first name", NULL}, - {"last", (getter) Custom_getlast, (setter) Custom_setlast, - "last name", NULL}, - {NULL} /* Sentinel */ -}; - -static PyObject * -Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) -{ - return PyUnicode_FromFormat("%S %S", self->first, self->last); -} - -static PyMethodDef Custom_methods[] = { - {"name", (PyCFunction) Custom_name, METH_NOARGS, - "Return the name, combining the first and last name" - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "custom4.Custom", - .tp_doc = "Custom objects", - .tp_basicsize = sizeof(CustomObject), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_new = Custom_new, - .tp_init = (initproc) Custom_init, - .tp_dealloc = (destructor) Custom_dealloc, - .tp_traverse = (traverseproc) Custom_traverse, - .tp_clear = (inquiry) Custom_clear, - .tp_members = Custom_members, - .tp_methods = Custom_methods, - .tp_getset = Custom_getsetters, -}; - -static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, - .m_name = "custom4", - .m_doc = "Example module that creates an extension type.", - .m_size = -1, -}; - -PyMODINIT_FUNC -PyInit_custom4(void) -{ - PyObject *m; - if (PyType_Ready(&CustomType) < 0) - return NULL; - - m = PyModule_Create(&custommodule); - if (m == NULL) - return NULL; - - Py_INCREF(&CustomType); - if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { - Py_DECREF(&CustomType); - Py_DECREF(m); - return NULL; - } - - return m; -} diff --git a/Doc/includes/dbpickle.py b/Doc/includes/dbpickle.py deleted file mode 100644 index b88ee87..0000000 --- a/Doc/includes/dbpickle.py +++ /dev/null @@ -1,87 +0,0 @@ -# Simple example presenting how persistent ID can be used to pickle -# external objects by reference. - -import pickle -import sqlite3 -from collections import namedtuple - -# Simple class representing a record in our database. -MemoRecord = namedtuple("MemoRecord", "key, task") - -class DBPickler(pickle.Pickler): - - def persistent_id(self, obj): - # Instead of pickling MemoRecord as a regular class instance, we emit a - # persistent ID. - if isinstance(obj, MemoRecord): - # Here, our persistent ID is simply a tuple, containing a tag and a - # key, which refers to a specific record in the database. - return ("MemoRecord", obj.key) - else: - # If obj does not have a persistent ID, return None. This means obj - # needs to be pickled as usual. - return None - - -class DBUnpickler(pickle.Unpickler): - - def __init__(self, file, connection): - super().__init__(file) - self.connection = connection - - def persistent_load(self, pid): - # This method is invoked whenever a persistent ID is encountered. - # Here, pid is the tuple returned by DBPickler. - cursor = self.connection.cursor() - type_tag, key_id = pid - if type_tag == "MemoRecord": - # Fetch the referenced record from the database and return it. - cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) - key, task = cursor.fetchone() - return MemoRecord(key, task) - else: - # Always raises an error if you cannot return the correct object. - # Otherwise, the unpickler will think None is the object referenced - # by the persistent ID. - raise pickle.UnpicklingError("unsupported persistent object") - - -def main(): - import io - import pprint - - # Initialize and populate our database. - conn = sqlite3.connect(":memory:") - cursor = conn.cursor() - cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") - tasks = ( - 'give food to fish', - 'prepare group meeting', - 'fight with a zebra', - ) - for task in tasks: - cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) - - # Fetch the records to be pickled. - cursor.execute("SELECT * FROM memos") - memos = [MemoRecord(key, task) for key, task in cursor] - # Save the records using our custom DBPickler. - file = io.BytesIO() - DBPickler(file).dump(memos) - - print("Pickled records:") - pprint.pprint(memos) - - # Update a record, just for good measure. - cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") - - # Load the records from the pickle data stream. - file.seek(0) - memos = DBUnpickler(file, conn).load() - - print("Unpickled records:") - pprint.pprint(memos) - - -if __name__ == '__main__': - main() diff --git a/Doc/includes/email-alternative.py b/Doc/includes/email-alternative.py index df7ca6f..ccecb42 100644..100755 --- a/Doc/includes/email-alternative.py +++ b/Doc/includes/email-alternative.py @@ -1,56 +1,48 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python import smtplib -from email.message import EmailMessage -from email.headerregistry import Address -from email.utils import make_msgid +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText -# Create the base text message. -msg = EmailMessage() -msg['Subject'] = "Ayons asperges pour le déjeuner" -msg['From'] = Address("Pepé Le Pew", "pepe", "example.com") -msg['To'] = (Address("Penelope Pussycat", "penelope", "example.com"), - Address("Fabrette Pussycat", "fabrette", "example.com")) -msg.set_content("""\ -Salut! +# me == my email address +# you == recipient's email address +me = "my@email.com" +you = "your@email.com" -Cela ressemble à un excellent recipie[1] déjeuner. +# Create message container - the correct MIME type is multipart/alternative. +msg = MIMEMultipart('alternative') +msg['Subject'] = "Link" +msg['From'] = me +msg['To'] = you -[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718 - ---Pepé -""") - -# Add the html version. This converts the message into a multipart/alternative -# container, with the original text message as the first part and the new html -# message as the second part. -asparagus_cid = make_msgid() -msg.add_alternative("""\ +# Create the body of the message (a plain-text and an HTML version). +text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.python.org" +html = """\ <html> <head></head> <body> - <p>Salut!</p> - <p>Cela ressemble à un excellent - <a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718"> - recipie - </a> déjeuner. + <p>Hi!<br> + How are you?<br> + Here is the <a href="https://www.python.org">link</a> you wanted. </p> - <img src="cid:{asparagus_cid}" /> </body> </html> -""".format(asparagus_cid=asparagus_cid[1:-1]), subtype='html') -# note that we needed to peel the <> off the msgid for use in the html. +""" -# Now add the related image to the html part. -with open("roasted-asparagus.jpg", 'rb') as img: - msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg', - cid=asparagus_cid) +# Record the MIME types of both parts - text/plain and text/html. +part1 = MIMEText(text, 'plain') +part2 = MIMEText(html, 'html') -# Make a local copy of what we are going to send. -with open('outgoing.msg', 'wb') as f: - f.write(bytes(msg)) +# Attach parts into message container. +# According to RFC 2046, the last part of a multipart message, in this case +# the HTML message, is best and preferred. +msg.attach(part1) +msg.attach(part2) # Send the message via local SMTP server. -with smtplib.SMTP('localhost') as s: - s.send_message(msg) +s = smtplib.SMTP('localhost') +# sendmail function takes 3 arguments: sender's address, recipient's address +# and message to send - here it is sent as one string. +s.sendmail(me, you, msg.as_string()) +s.quit() diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py index 2fc1570..035442b 100644 --- a/Doc/includes/email-dir.py +++ b/Doc/includes/email-dir.py @@ -1,50 +1,66 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python """Send the contents of a directory as a MIME message.""" import os +import sys import smtplib # For guessing MIME type based on file name extension import mimetypes -from argparse import ArgumentParser +from optparse import OptionParser -from email.message import EmailMessage -from email.policy import SMTP +from email import encoders +from email.message import Message +from email.mime.audio import MIMEAudio +from email.mime.base import MIMEBase +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +COMMASPACE = ', ' def main(): - parser = ArgumentParser(description="""\ + parser = OptionParser(usage="""\ Send the contents of a directory as a MIME message. + +Usage: %prog [options] + Unless the -o option is given, the email is sent by forwarding to your local SMTP server, which then does the normal delivery process. Your local machine must be running an SMTP server. """) - parser.add_argument('-d', '--directory', - help="""Mail the contents of the specified directory, - otherwise use the current directory. Only the regular - files in the directory are sent, and we don't recurse to - subdirectories.""") - parser.add_argument('-o', '--output', - metavar='FILE', - help="""Print the composed message to FILE instead of - sending the message to the SMTP server.""") - parser.add_argument('-s', '--sender', required=True, - help='The value of the From: header (required)') - parser.add_argument('-r', '--recipient', required=True, - action='append', metavar='RECIPIENT', - default=[], dest='recipients', - help='A To: header value (at least one required)') - args = parser.parse_args() - directory = args.directory + parser.add_option('-d', '--directory', + type='string', action='store', + help="""Mail the contents of the specified directory, + otherwise use the current directory. Only the regular + files in the directory are sent, and we don't recurse to + subdirectories.""") + parser.add_option('-o', '--output', + type='string', action='store', metavar='FILE', + help="""Print the composed message to FILE instead of + sending the message to the SMTP server.""") + parser.add_option('-s', '--sender', + type='string', action='store', metavar='SENDER', + help='The value of the From: header (required)') + parser.add_option('-r', '--recipient', + type='string', action='append', metavar='RECIPIENT', + default=[], dest='recipients', + help='A To: header value (at least one required)') + opts, args = parser.parse_args() + if not opts.sender or not opts.recipients: + parser.print_help() + sys.exit(1) + directory = opts.directory if not directory: directory = '.' - # Create the message - msg = EmailMessage() - msg['Subject'] = f'Contents of directory {os.path.abspath(directory)}' - msg['To'] = ', '.join(args.recipients) - msg['From'] = args.sender - msg.preamble = 'You will not see this in a MIME-aware mail reader.\n' + # Create the enclosing (outer) message + outer = MIMEMultipart() + outer['Subject'] = 'Contents of directory %s' % os.path.abspath(directory) + outer['To'] = COMMASPACE.join(opts.recipients) + outer['From'] = opts.sender + outer.preamble = 'You will not see this in a MIME-aware mail reader.\n' for filename in os.listdir(directory): path = os.path.join(directory, filename) @@ -59,18 +75,39 @@ must be running an SMTP server. # use a generic bag-of-bits type. ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) - with open(path, 'rb') as fp: - msg.add_attachment(fp.read(), - maintype=maintype, - subtype=subtype, - filename=filename) + if maintype == 'text': + fp = open(path) + # Note: we should handle calculating the charset + msg = MIMEText(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'image': + fp = open(path, 'rb') + msg = MIMEImage(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'audio': + fp = open(path, 'rb') + msg = MIMEAudio(fp.read(), _subtype=subtype) + fp.close() + else: + fp = open(path, 'rb') + msg = MIMEBase(maintype, subtype) + msg.set_payload(fp.read()) + fp.close() + # Encode the payload using Base64 + encoders.encode_base64(msg) + # Set the filename parameter + msg.add_header('Content-Disposition', 'attachment', filename=filename) + outer.attach(msg) # Now send or store the message - if args.output: - with open(args.output, 'wb') as fp: - fp.write(msg.as_bytes(policy=SMTP)) + composed = outer.as_string() + if opts.output: + fp = open(opts.output, 'w') + fp.write(composed) + fp.close() else: - with smtplib.SMTP('localhost') as s: - s.send_message(msg) + s = smtplib.SMTP('localhost') + s.sendmail(opts.sender, opts.recipients, composed) + s.quit() if __name__ == '__main__': diff --git a/Doc/includes/email-headers.py b/Doc/includes/email-headers.py index 2c42145..664c3ff 100644 --- a/Doc/includes/email-headers.py +++ b/Doc/includes/email-headers.py @@ -1,24 +1,17 @@ # Import the email modules we'll need -from email.parser import BytesParser, Parser -from email.policy import default +from email.parser import Parser -# If the e-mail headers are in a file, uncomment these two lines: -# with open(messagefile, 'rb') as fp: -# headers = BytesParser(policy=default).parse(fp) +# If the e-mail headers are in a file, uncomment this line: +#headers = Parser().parse(open(messagefile, 'r')) -# Or for parsing headers in a string (this is an uncommon operation), use: -headers = Parser(policy=default).parsestr( - 'From: Foo Bar <user@example.com>\n' +# Or for parsing headers in a string, use: +headers = Parser().parsestr('From: <user@example.com>\n' 'To: <someone_else@example.com>\n' 'Subject: Test message\n' '\n' 'Body would go here\n') # Now the header items can be accessed as a dictionary: -print('To: {}'.format(headers['to'])) -print('From: {}'.format(headers['from'])) -print('Subject: {}'.format(headers['subject'])) - -# You can also access the parts of the addresses: -print('Recipient username: {}'.format(headers['to'].addresses[0].username)) -print('Sender name: {}'.format(headers['from'].addresses[0].display_name)) +print 'To: %s' % headers['to'] +print 'From: %s' % headers['from'] +print 'Subject: %s' % headers['subject'] diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py index 6af2be0..7b1c028 100644 --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -1,29 +1,31 @@ # Import smtplib for the actual sending function import smtplib -# And imghdr to find the types of our images -import imghdr - # Here are the email package modules we'll need -from email.message import EmailMessage +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart + +COMMASPACE = ', ' -# Create the container email message. -msg = EmailMessage() +# Create the container (outer) email message. +msg = MIMEMultipart() msg['Subject'] = 'Our family reunion' # me == the sender's email address # family = the list of all recipients' email addresses msg['From'] = me -msg['To'] = ', '.join(family) -msg.preamble = 'You will not see this in a MIME-aware mail reader.\n' +msg['To'] = COMMASPACE.join(family) +msg.preamble = 'Our family reunion' -# Open the files in binary mode. Use imghdr to figure out the -# MIME subtype for each specific image. +# Assume we know that the image files are all in PNG format for file in pngfiles: - with open(file, 'rb') as fp: - img_data = fp.read() - msg.add_attachment(img_data, maintype='image', - subtype=imghdr.what(None, img_data)) + # Open the files in binary mode. Let the MIMEImage class automatically + # guess the specific image type. + fp = open(file, 'rb') + img = MIMEImage(fp.read()) + fp.close() + msg.attach(img) # Send the email via our own SMTP server. -with smtplib.SMTP('localhost') as s: - s.send_message(msg) +s = smtplib.SMTP('localhost') +s.sendmail(me, family, msg.as_string()) +s.quit() diff --git a/Doc/includes/email-read-alternative.py b/Doc/includes/email-read-alternative.py deleted file mode 100644 index 5ea84e6..0000000 --- a/Doc/includes/email-read-alternative.py +++ /dev/null @@ -1,75 +0,0 @@ -import os -import sys -import tempfile -import mimetypes -import webbrowser - -# Import the email modules we'll need -from email import policy -from email.parser import BytesParser - -# An imaginary module that would make this work and be safe. -from imaginary import magic_html_parser - -# In a real program you'd get the filename from the arguments. -with open('outgoing.msg', 'rb') as fp: - msg = BytesParser(policy=policy.default).parse(fp) - -# Now the header items can be accessed as a dictionary, and any non-ASCII will -# be converted to unicode: -print('To:', msg['to']) -print('From:', msg['from']) -print('Subject:', msg['subject']) - -# If we want to print a preview of the message content, we can extract whatever -# the least formatted payload is and print the first three lines. Of course, -# if the message has no plain text part printing the first three lines of html -# is probably useless, but this is just a conceptual example. -simplest = msg.get_body(preferencelist=('plain', 'html')) -print() -print(''.join(simplest.get_content().splitlines(keepends=True)[:3])) - -ans = input("View full message?") -if ans.lower()[0] == 'n': - sys.exit() - -# We can extract the richest alternative in order to display it: -richest = msg.get_body() -partfiles = {} -if richest['content-type'].maintype == 'text': - if richest['content-type'].subtype == 'plain': - for line in richest.get_content().splitlines(): - print(line) - sys.exit() - elif richest['content-type'].subtype == 'html': - body = richest - else: - print("Don't know how to display {}".format(richest.get_content_type())) - sys.exit() -elif richest['content-type'].content_type == 'multipart/related': - body = richest.get_body(preferencelist=('html')) - for part in richest.iter_attachments(): - fn = part.get_filename() - if fn: - extension = os.path.splitext(part.get_filename())[1] - else: - extension = mimetypes.guess_extension(part.get_content_type()) - with tempfile.NamedTemporaryFile(suffix=extension, delete=False) as f: - f.write(part.get_content()) - # again strip the <> to go from email form of cid to html form. - partfiles[part['content-id'][1:-1]] = f.name -else: - print("Don't know how to display {}".format(richest.get_content_type())) - sys.exit() -with tempfile.NamedTemporaryFile(mode='w', delete=False) as f: - # The magic_html_parser has to rewrite the href="cid:...." attributes to - # point to the filenames in partfiles. It also has to do a safety-sanitize - # of the html. It could be written using html.parser. - f.write(magic_html_parser(body.get_content(), partfiles)) -webbrowser.open(f.name) -os.remove(f.name) -for fn in partfiles.values(): - os.remove(fn) - -# Of course, there are lots of email messages that could break this simple -# minded program, but it will handle the most common ones. diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py index 07dc30f..29bd078 100644 --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -2,21 +2,23 @@ import smtplib # Import the email modules we'll need -from email.message import EmailMessage +from email.mime.text import MIMEText -# Open the plain text file whose name is in textfile for reading. -with open(textfile) as fp: - # Create a text/plain message - msg = EmailMessage() - msg.set_content(fp.read()) +# Open a plain text file for reading. For this example, assume that +# the text file contains only ASCII characters. +fp = open(textfile, 'rb') +# Create a text/plain message +msg = MIMEText(fp.read()) +fp.close() # me == the sender's email address # you == the recipient's email address -msg['Subject'] = f'The contents of {textfile}' +msg['Subject'] = 'The contents of %s' % textfile msg['From'] = me msg['To'] = you -# Send the message via our own SMTP server. +# Send the message via our own SMTP server, but don't include the +# envelope header. s = smtplib.SMTP('localhost') -s.send_message(msg) +s.sendmail(me, [you], msg.as_string()) s.quit() diff --git a/Doc/includes/email-unpack.py b/Doc/includes/email-unpack.py index c8cb0be..a8f712d 100644 --- a/Doc/includes/email-unpack.py +++ b/Doc/includes/email-unpack.py @@ -1,34 +1,48 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python """Unpack a MIME message into a directory of files.""" import os +import sys import email +import errno import mimetypes -from email.policy import default - -from argparse import ArgumentParser +from optparse import OptionParser def main(): - parser = ArgumentParser(description="""\ + parser = OptionParser(usage="""\ Unpack a MIME message into a directory of files. + +Usage: %prog [options] msgfile """) - parser.add_argument('-d', '--directory', required=True, - help="""Unpack the MIME message into the named - directory, which will be created if it doesn't already - exist.""") - parser.add_argument('msgfile') - args = parser.parse_args() + parser.add_option('-d', '--directory', + type='string', action='store', + help="""Unpack the MIME message into the named + directory, which will be created if it doesn't already + exist.""") + opts, args = parser.parse_args() + if not opts.directory: + parser.print_help() + sys.exit(1) - with open(args.msgfile, 'rb') as fp: - msg = email.message_from_binary_file(fp, policy=default) + try: + msgfile = args[0] + except IndexError: + parser.print_help() + sys.exit(1) try: - os.mkdir(args.directory) - except FileExistsError: - pass + os.mkdir(opts.directory) + except OSError as e: + # Ignore directory exists error + if e.errno != errno.EEXIST: + raise + + fp = open(msgfile) + msg = email.message_from_file(fp) + fp.close() counter = 1 for part in msg.walk(): @@ -43,10 +57,11 @@ Unpack a MIME message into a directory of files. if not ext: # Use a generic bag-of-bits extension ext = '.bin' - filename = f'part-{counter:03d}{ext}' + filename = 'part-%03d%s' % (counter, ext) counter += 1 - with open(os.path.join(args.directory, filename), 'wb') as fp: - fp.write(part.get_payload(decode=True)) + fp = open(os.path.join(opts.directory, filename), 'wb') + fp.write(part.get_payload(decode=True)) + fp.close() if __name__ == '__main__': diff --git a/Doc/includes/minidom-example.py b/Doc/includes/minidom-example.py index 5ee7682..4bca949 100644 --- a/Doc/includes/minidom-example.py +++ b/Doc/includes/minidom-example.py @@ -26,12 +26,12 @@ def getText(nodelist): return ''.join(rc) def handleSlideshow(slideshow): - print("<html>") + print "<html>" handleSlideshowTitle(slideshow.getElementsByTagName("title")[0]) slides = slideshow.getElementsByTagName("slide") handleToc(slides) handleSlides(slides) - print("</html>") + print "</html>" def handleSlides(slides): for slide in slides: @@ -42,23 +42,23 @@ def handleSlide(slide): handlePoints(slide.getElementsByTagName("point")) def handleSlideshowTitle(title): - print("<title>%s</title>" % getText(title.childNodes)) + print "<title>%s</title>" % getText(title.childNodes) def handleSlideTitle(title): - print("<h2>%s</h2>" % getText(title.childNodes)) + print "<h2>%s</h2>" % getText(title.childNodes) def handlePoints(points): - print("<ul>") + print "<ul>" for point in points: handlePoint(point) - print("</ul>") + print "</ul>" def handlePoint(point): - print("<li>%s</li>" % getText(point.childNodes)) + print "<li>%s</li>" % getText(point.childNodes) def handleToc(slides): for slide in slides: title = slide.getElementsByTagName("title")[0] - print("<p>%s</p>" % getText(title.childNodes)) + print "<p>%s</p>" % getText(title.childNodes) handleSlideshow(dom) diff --git a/Doc/includes/mp_benchmarks.py b/Doc/includes/mp_benchmarks.py new file mode 100644 index 0000000..16be77e --- /dev/null +++ b/Doc/includes/mp_benchmarks.py @@ -0,0 +1,238 @@ +# +# Simple benchmarks for the multiprocessing package +# +# Copyright (c) 2006-2008, R Oudkerk +# All rights reserved. +# + +import time, sys, multiprocessing, threading, Queue, gc + +if sys.platform == 'win32': + _timer = time.clock +else: + _timer = time.time + +delta = 1 + + +#### TEST_QUEUESPEED + +def queuespeed_func(q, c, iterations): + a = '0' * 256 + c.acquire() + c.notify() + c.release() + + for i in xrange(iterations): + q.put(a) + + q.put('STOP') + +def test_queuespeed(Process, q, c): + elapsed = 0 + iterations = 1 + + while elapsed < delta: + iterations *= 2 + + p = Process(target=queuespeed_func, args=(q, c, iterations)) + c.acquire() + p.start() + c.wait() + c.release() + + result = None + t = _timer() + + while result != 'STOP': + result = q.get() + + elapsed = _timer() - t + + p.join() + + print iterations, 'objects passed through the queue in', elapsed, 'seconds' + print 'average number/sec:', iterations/elapsed + + +#### TEST_PIPESPEED + +def pipe_func(c, cond, iterations): + a = '0' * 256 + cond.acquire() + cond.notify() + cond.release() + + for i in xrange(iterations): + c.send(a) + + c.send('STOP') + +def test_pipespeed(): + c, d = multiprocessing.Pipe() + cond = multiprocessing.Condition() + elapsed = 0 + iterations = 1 + + while elapsed < delta: + iterations *= 2 + + p = multiprocessing.Process(target=pipe_func, + args=(d, cond, iterations)) + cond.acquire() + p.start() + cond.wait() + cond.release() + + result = None + t = _timer() + + while result != 'STOP': + result = c.recv() + + elapsed = _timer() - t + p.join() + + print iterations, 'objects passed through connection in',elapsed,'seconds' + print 'average number/sec:', iterations/elapsed + + +#### TEST_SEQSPEED + +def test_seqspeed(seq): + elapsed = 0 + iterations = 1 + + while elapsed < delta: + iterations *= 2 + + t = _timer() + + for i in xrange(iterations): + a = seq[5] + + elapsed = _timer()-t + + print iterations, 'iterations in', elapsed, 'seconds' + print 'average number/sec:', iterations/elapsed + + +#### TEST_LOCK + +def test_lockspeed(l): + elapsed = 0 + iterations = 1 + + while elapsed < delta: + iterations *= 2 + + t = _timer() + + for i in xrange(iterations): + l.acquire() + l.release() + + elapsed = _timer()-t + + print iterations, 'iterations in', elapsed, 'seconds' + print 'average number/sec:', iterations/elapsed + + +#### TEST_CONDITION + +def conditionspeed_func(c, N): + c.acquire() + c.notify() + + for i in xrange(N): + c.wait() + c.notify() + + c.release() + +def test_conditionspeed(Process, c): + elapsed = 0 + iterations = 1 + + while elapsed < delta: + iterations *= 2 + + c.acquire() + p = Process(target=conditionspeed_func, args=(c, iterations)) + p.start() + + c.wait() + + t = _timer() + + for i in xrange(iterations): + c.notify() + c.wait() + + elapsed = _timer()-t + + c.release() + p.join() + + print iterations * 2, 'waits in', elapsed, 'seconds' + print 'average number/sec:', iterations * 2 / elapsed + +#### + +def test(): + manager = multiprocessing.Manager() + + gc.disable() + + print '\n\t######## testing Queue.Queue\n' + test_queuespeed(threading.Thread, Queue.Queue(), + threading.Condition()) + print '\n\t######## testing multiprocessing.Queue\n' + test_queuespeed(multiprocessing.Process, multiprocessing.Queue(), + multiprocessing.Condition()) + print '\n\t######## testing Queue managed by server process\n' + test_queuespeed(multiprocessing.Process, manager.Queue(), + manager.Condition()) + print '\n\t######## testing multiprocessing.Pipe\n' + test_pipespeed() + + print + + print '\n\t######## testing list\n' + test_seqspeed(range(10)) + print '\n\t######## testing list managed by server process\n' + test_seqspeed(manager.list(range(10))) + print '\n\t######## testing Array("i", ..., lock=False)\n' + test_seqspeed(multiprocessing.Array('i', range(10), lock=False)) + print '\n\t######## testing Array("i", ..., lock=True)\n' + test_seqspeed(multiprocessing.Array('i', range(10), lock=True)) + + print + + print '\n\t######## testing threading.Lock\n' + test_lockspeed(threading.Lock()) + print '\n\t######## testing threading.RLock\n' + test_lockspeed(threading.RLock()) + print '\n\t######## testing multiprocessing.Lock\n' + test_lockspeed(multiprocessing.Lock()) + print '\n\t######## testing multiprocessing.RLock\n' + test_lockspeed(multiprocessing.RLock()) + print '\n\t######## testing lock managed by server process\n' + test_lockspeed(manager.Lock()) + print '\n\t######## testing rlock managed by server process\n' + test_lockspeed(manager.RLock()) + + print + + print '\n\t######## testing threading.Condition\n' + test_conditionspeed(threading.Thread, threading.Condition()) + print '\n\t######## testing multiprocessing.Condition\n' + test_conditionspeed(multiprocessing.Process, multiprocessing.Condition()) + print '\n\t######## testing condition managed by a server process\n' + test_conditionspeed(multiprocessing.Process, manager.Condition()) + + gc.enable() + +if __name__ == '__main__': + multiprocessing.freeze_support() + test() diff --git a/Doc/includes/mp_newtype.py b/Doc/includes/mp_newtype.py index 1c796a5..1858696 100644 --- a/Doc/includes/mp_newtype.py +++ b/Doc/includes/mp_newtype.py @@ -1,27 +1,37 @@ +# +# This module shows how to use arbitrary callables with a subclass of +# `BaseManager`. +# +# Copyright (c) 2006-2008, R Oudkerk +# All rights reserved. +# + from multiprocessing import freeze_support from multiprocessing.managers import BaseManager, BaseProxy import operator ## -class Foo: +class Foo(object): def f(self): - print('you called Foo.f()') + print 'you called Foo.f()' def g(self): - print('you called Foo.g()') + print 'you called Foo.g()' def _h(self): - print('you called Foo._h()') + print 'you called Foo._h()' # A simple generator function def baz(): - for i in range(10): + for i in xrange(10): yield i*i # Proxy type for generator objects class GeneratorProxy(BaseProxy): - _exposed_ = ['__next__'] + _exposed_ = ('next', '__next__') def __iter__(self): return self + def next(self): + return self._callmethod('next') def __next__(self): return self._callmethod('__next__') @@ -52,7 +62,7 @@ def test(): manager = MyManager() manager.start() - print('-' * 20) + print '-' * 20 f1 = manager.Foo1() f1.f() @@ -60,7 +70,7 @@ def test(): assert not hasattr(f1, '_h') assert sorted(f1._exposed_) == sorted(['f', 'g']) - print('-' * 20) + print '-' * 20 f2 = manager.Foo2() f2.g() @@ -68,19 +78,21 @@ def test(): assert not hasattr(f2, 'f') assert sorted(f2._exposed_) == sorted(['g', '_h']) - print('-' * 20) + print '-' * 20 it = manager.baz() for i in it: - print('<%d>' % i, end=' ') - print() + print '<%d>' % i, + print - print('-' * 20) + print '-' * 20 op = manager.operator() - print('op.add(23, 45) =', op.add(23, 45)) - print('op.pow(2, 94) =', op.pow(2, 94)) - print('op._exposed_ =', op._exposed_) + print 'op.add(23, 45) =', op.add(23, 45) + print 'op.pow(2, 94) =', op.pow(2, 94) + print 'op.getslice(range(10), 2, 6) =', op.getslice(range(10), 2, 6) + print 'op.repeat(range(5), 3) =', op.repeat(range(5), 3) + print 'op._exposed_ =', op._exposed_ ## diff --git a/Doc/includes/mp_pool.py b/Doc/includes/mp_pool.py index 11101e1..0a3d92a 100644 --- a/Doc/includes/mp_pool.py +++ b/Doc/includes/mp_pool.py @@ -1,3 +1,10 @@ +# +# A test of `multiprocessing.Pool` class +# +# Copyright (c) 2006-2008, R Oudkerk +# All rights reserved. +# + import multiprocessing import time import random @@ -18,18 +25,18 @@ def calculatestar(args): return calculate(*args) def mul(a, b): - time.sleep(0.5 * random.random()) + time.sleep(0.5*random.random()) return a * b def plus(a, b): - time.sleep(0.5 * random.random()) + time.sleep(0.5*random.random()) return a + b def f(x): - return 1.0 / (x - 5.0) + return 1.0 / (x-5.0) def pow3(x): - return x ** 3 + return x**3 def noop(x): pass @@ -39,115 +46,269 @@ def noop(x): # def test(): + print 'cpu_count() = %d\n' % multiprocessing.cpu_count() + + # + # Create pool + # + PROCESSES = 4 - print('Creating pool with %d processes\n' % PROCESSES) + print 'Creating pool with %d processes\n' % PROCESSES + pool = multiprocessing.Pool(PROCESSES) + print 'pool = %s' % pool + print + + # + # Tests + # + + TASKS = [(mul, (i, 7)) for i in range(10)] + \ + [(plus, (i, 8)) for i in range(10)] + + results = [pool.apply_async(calculate, t) for t in TASKS] + imap_it = pool.imap(calculatestar, TASKS) + imap_unordered_it = pool.imap_unordered(calculatestar, TASKS) + + print 'Ordered results using pool.apply_async():' + for r in results: + print '\t', r.get() + print + + print 'Ordered results using pool.imap():' + for x in imap_it: + print '\t', x + print + + print 'Unordered results using pool.imap_unordered():' + for x in imap_unordered_it: + print '\t', x + print + + print 'Ordered results using pool.map() --- will block till complete:' + for x in pool.map(calculatestar, TASKS): + print '\t', x + print + + # + # Simple benchmarks + # + + N = 100000 + print 'def pow3(x): return x**3' - with multiprocessing.Pool(PROCESSES) as pool: - # - # Tests - # + t = time.time() + A = map(pow3, xrange(N)) + print '\tmap(pow3, xrange(%d)):\n\t\t%s seconds' % \ + (N, time.time() - t) - TASKS = [(mul, (i, 7)) for i in range(10)] + \ - [(plus, (i, 8)) for i in range(10)] + t = time.time() + B = pool.map(pow3, xrange(N)) + print '\tpool.map(pow3, xrange(%d)):\n\t\t%s seconds' % \ + (N, time.time() - t) - results = [pool.apply_async(calculate, t) for t in TASKS] - imap_it = pool.imap(calculatestar, TASKS) - imap_unordered_it = pool.imap_unordered(calculatestar, TASKS) + t = time.time() + C = list(pool.imap(pow3, xrange(N), chunksize=N//8)) + print '\tlist(pool.imap(pow3, xrange(%d), chunksize=%d)):\n\t\t%s' \ + ' seconds' % (N, N//8, time.time() - t) - print('Ordered results using pool.apply_async():') - for r in results: - print('\t', r.get()) - print() + assert A == B == C, (len(A), len(B), len(C)) + print - print('Ordered results using pool.imap():') - for x in imap_it: - print('\t', x) - print() + L = [None] * 1000000 + print 'def noop(x): pass' + print 'L = [None] * 1000000' - print('Unordered results using pool.imap_unordered():') - for x in imap_unordered_it: - print('\t', x) - print() + t = time.time() + A = map(noop, L) + print '\tmap(noop, L):\n\t\t%s seconds' % \ + (time.time() - t) - print('Ordered results using pool.map() --- will block till complete:') - for x in pool.map(calculatestar, TASKS): - print('\t', x) - print() + t = time.time() + B = pool.map(noop, L) + print '\tpool.map(noop, L):\n\t\t%s seconds' % \ + (time.time() - t) - # - # Test error handling - # + t = time.time() + C = list(pool.imap(noop, L, chunksize=len(L)//8)) + print '\tlist(pool.imap(noop, L, chunksize=%d)):\n\t\t%s seconds' % \ + (len(L)//8, time.time() - t) - print('Testing error handling:') + assert A == B == C, (len(A), len(B), len(C)) + print + del A, B, C, L + + # + # Test error handling + # + + print 'Testing error handling:' + + try: + print pool.apply(f, (5,)) + except ZeroDivisionError: + print '\tGot ZeroDivisionError as expected from pool.apply()' + else: + raise AssertionError('expected ZeroDivisionError') + + try: + print pool.map(f, range(10)) + except ZeroDivisionError: + print '\tGot ZeroDivisionError as expected from pool.map()' + else: + raise AssertionError('expected ZeroDivisionError') + + try: + print list(pool.imap(f, range(10))) + except ZeroDivisionError: + print '\tGot ZeroDivisionError as expected from list(pool.imap())' + else: + raise AssertionError('expected ZeroDivisionError') + + it = pool.imap(f, range(10)) + for i in range(10): try: - print(pool.apply(f, (5,))) + x = it.next() except ZeroDivisionError: - print('\tGot ZeroDivisionError as expected from pool.apply()') + if i == 5: + pass + except StopIteration: + break else: - raise AssertionError('expected ZeroDivisionError') + if i == 5: + raise AssertionError('expected ZeroDivisionError') + + assert i == 9 + print '\tGot ZeroDivisionError as expected from IMapIterator.next()' + print + # + # Testing timeouts + # + + print 'Testing ApplyResult.get() with timeout:', + res = pool.apply_async(calculate, TASKS[0]) + while 1: + sys.stdout.flush() try: - print(pool.map(f, list(range(10)))) - except ZeroDivisionError: - print('\tGot ZeroDivisionError as expected from pool.map()') - else: - raise AssertionError('expected ZeroDivisionError') + sys.stdout.write('\n\t%s' % res.get(0.02)) + break + except multiprocessing.TimeoutError: + sys.stdout.write('.') + print + print + print 'Testing IMapIterator.next() with timeout:', + it = pool.imap(calculatestar, TASKS) + while 1: + sys.stdout.flush() try: - print(list(pool.imap(f, list(range(10))))) - except ZeroDivisionError: - print('\tGot ZeroDivisionError as expected from list(pool.imap())') - else: - raise AssertionError('expected ZeroDivisionError') - - it = pool.imap(f, list(range(10))) - for i in range(10): - try: - x = next(it) - except ZeroDivisionError: - if i == 5: - pass - except StopIteration: - break - else: - if i == 5: - raise AssertionError('expected ZeroDivisionError') - - assert i == 9 - print('\tGot ZeroDivisionError as expected from IMapIterator.next()') - print() - - # - # Testing timeouts - # - - print('Testing ApplyResult.get() with timeout:', end=' ') - res = pool.apply_async(calculate, TASKS[0]) - while 1: - sys.stdout.flush() - try: - sys.stdout.write('\n\t%s' % res.get(0.02)) - break - except multiprocessing.TimeoutError: - sys.stdout.write('.') - print() - print() - - print('Testing IMapIterator.next() with timeout:', end=' ') - it = pool.imap(calculatestar, TASKS) - while 1: - sys.stdout.flush() - try: - sys.stdout.write('\n\t%s' % it.next(0.02)) - except StopIteration: - break - except multiprocessing.TimeoutError: - sys.stdout.write('.') - print() - print() + sys.stdout.write('\n\t%s' % it.next(0.02)) + except StopIteration: + break + except multiprocessing.TimeoutError: + sys.stdout.write('.') + print + print + + # + # Testing callback + # + + print 'Testing callback:' + + A = [] + B = [56, 0, 1, 8, 27, 64, 125, 216, 343, 512, 729] + + r = pool.apply_async(mul, (7, 8), callback=A.append) + r.wait() + + r = pool.map_async(pow3, range(10), callback=A.extend) + r.wait() + + if A == B: + print '\tcallbacks succeeded\n' + else: + print '\t*** callbacks failed\n\t\t%s != %s\n' % (A, B) + + # + # Check there are no outstanding tasks + # + + assert not pool._cache, 'cache = %r' % pool._cache + + # + # Check close() methods + # + + print 'Testing close():' + + for worker in pool._pool: + assert worker.is_alive() + + result = pool.apply_async(time.sleep, [0.5]) + pool.close() + pool.join() + + assert result.get() is None + + for worker in pool._pool: + assert not worker.is_alive() + + print '\tclose() succeeded\n' + + # + # Check terminate() method + # + + print 'Testing terminate():' + + pool = multiprocessing.Pool(2) + DELTA = 0.1 + ignore = pool.apply(pow3, [2]) + results = [pool.apply_async(time.sleep, [DELTA]) for i in range(100)] + pool.terminate() + pool.join() + + for worker in pool._pool: + assert not worker.is_alive() + + print '\tterminate() succeeded\n' + + # + # Check garbage collection + # + + print 'Testing garbage collection:' + + pool = multiprocessing.Pool(2) + DELTA = 0.1 + processes = pool._pool + ignore = pool.apply(pow3, [2]) + results = [pool.apply_async(time.sleep, [DELTA]) for i in range(100)] + + results = pool = None + + time.sleep(DELTA * 2) + + for worker in processes: + assert not worker.is_alive() + + print '\tgarbage collection succeeded\n' if __name__ == '__main__': multiprocessing.freeze_support() + + assert len(sys.argv) in (1, 2) + + if len(sys.argv) == 1 or sys.argv[1] == 'processes': + print ' Using processes '.center(79, '-') + elif sys.argv[1] == 'threads': + print ' Using threads '.center(79, '-') + import multiprocessing.dummy as multiprocessing + else: + print 'Usage:\n\t%s [processes | threads]' % sys.argv[0] + raise SystemExit(2) + test() diff --git a/Doc/includes/mp_synchronize.py b/Doc/includes/mp_synchronize.py new file mode 100644 index 0000000..fd2ae77 --- /dev/null +++ b/Doc/includes/mp_synchronize.py @@ -0,0 +1,276 @@ +# +# A test file for the `multiprocessing` package +# +# Copyright (c) 2006-2008, R Oudkerk +# All rights reserved. +# + +import time, sys, random +from Queue import Empty + +import multiprocessing # may get overwritten + + +#### TEST_VALUE + +def value_func(running, mutex): + random.seed() + time.sleep(random.random()*4) + + mutex.acquire() + print '\n\t\t\t' + str(multiprocessing.current_process()) + ' has finished' + running.value -= 1 + mutex.release() + +def test_value(): + TASKS = 10 + running = multiprocessing.Value('i', TASKS) + mutex = multiprocessing.Lock() + + for i in range(TASKS): + p = multiprocessing.Process(target=value_func, args=(running, mutex)) + p.start() + + while running.value > 0: + time.sleep(0.08) + mutex.acquire() + print running.value, + sys.stdout.flush() + mutex.release() + + print + print 'No more running processes' + + +#### TEST_QUEUE + +def queue_func(queue): + for i in range(30): + time.sleep(0.5 * random.random()) + queue.put(i*i) + queue.put('STOP') + +def test_queue(): + q = multiprocessing.Queue() + + p = multiprocessing.Process(target=queue_func, args=(q,)) + p.start() + + o = None + while o != 'STOP': + try: + o = q.get(timeout=0.3) + print o, + sys.stdout.flush() + except Empty: + print 'TIMEOUT' + + print + + +#### TEST_CONDITION + +def condition_func(cond): + cond.acquire() + print '\t' + str(cond) + time.sleep(2) + print '\tchild is notifying' + print '\t' + str(cond) + cond.notify() + cond.release() + +def test_condition(): + cond = multiprocessing.Condition() + + p = multiprocessing.Process(target=condition_func, args=(cond,)) + print cond + + cond.acquire() + print cond + cond.acquire() + print cond + + p.start() + + print 'main is waiting' + cond.wait() + print 'main has woken up' + + print cond + cond.release() + print cond + cond.release() + + p.join() + print cond + + +#### TEST_SEMAPHORE + +def semaphore_func(sema, mutex, running): + sema.acquire() + + mutex.acquire() + running.value += 1 + print running.value, 'tasks are running' + mutex.release() + + random.seed() + time.sleep(random.random()*2) + + mutex.acquire() + running.value -= 1 + print '%s has finished' % multiprocessing.current_process() + mutex.release() + + sema.release() + +def test_semaphore(): + sema = multiprocessing.Semaphore(3) + mutex = multiprocessing.RLock() + running = multiprocessing.Value('i', 0) + + processes = [ + multiprocessing.Process(target=semaphore_func, + args=(sema, mutex, running)) + for i in range(10) + ] + + for p in processes: + p.start() + + for p in processes: + p.join() + + +#### TEST_JOIN_TIMEOUT + +def join_timeout_func(): + print '\tchild sleeping' + time.sleep(5.5) + print '\n\tchild terminating' + +def test_join_timeout(): + p = multiprocessing.Process(target=join_timeout_func) + p.start() + + print 'waiting for process to finish' + + while 1: + p.join(timeout=1) + if not p.is_alive(): + break + print '.', + sys.stdout.flush() + + +#### TEST_EVENT + +def event_func(event): + print '\t%r is waiting' % multiprocessing.current_process() + event.wait() + print '\t%r has woken up' % multiprocessing.current_process() + +def test_event(): + event = multiprocessing.Event() + + processes = [multiprocessing.Process(target=event_func, args=(event,)) + for i in range(5)] + + for p in processes: + p.start() + + print 'main is sleeping' + time.sleep(2) + + print 'main is setting event' + event.set() + + for p in processes: + p.join() + + +#### TEST_SHAREDVALUES + +def sharedvalues_func(values, arrays, shared_values, shared_arrays): + for i in range(len(values)): + v = values[i][1] + sv = shared_values[i].value + assert v == sv + + for i in range(len(values)): + a = arrays[i][1] + sa = list(shared_arrays[i][:]) + assert a == sa + + print 'Tests passed' + +def test_sharedvalues(): + values = [ + ('i', 10), + ('h', -2), + ('d', 1.25) + ] + arrays = [ + ('i', range(100)), + ('d', [0.25 * i for i in range(100)]), + ('H', range(1000)) + ] + + shared_values = [multiprocessing.Value(id, v) for id, v in values] + shared_arrays = [multiprocessing.Array(id, a) for id, a in arrays] + + p = multiprocessing.Process( + target=sharedvalues_func, + args=(values, arrays, shared_values, shared_arrays) + ) + p.start() + p.join() + + assert p.exitcode == 0 + + +#### + +def test(namespace=multiprocessing): + global multiprocessing + + multiprocessing = namespace + + for func in [ test_value, test_queue, test_condition, + test_semaphore, test_join_timeout, test_event, + test_sharedvalues ]: + + print '\n\t######## %s\n' % func.__name__ + func() + + ignore = multiprocessing.active_children() # cleanup any old processes + if hasattr(multiprocessing, '_debug_info'): + info = multiprocessing._debug_info() + if info: + print info + raise ValueError('there should be no positive refcounts left') + + +if __name__ == '__main__': + multiprocessing.freeze_support() + + assert len(sys.argv) in (1, 2) + + if len(sys.argv) == 1 or sys.argv[1] == 'processes': + print ' Using processes '.center(79, '-') + namespace = multiprocessing + elif sys.argv[1] == 'manager': + print ' Using processes and a manager '.center(79, '-') + namespace = multiprocessing.Manager() + namespace.Process = multiprocessing.Process + namespace.current_process = multiprocessing.current_process + namespace.active_children = multiprocessing.active_children + elif sys.argv[1] == 'threads': + print ' Using threads '.center(79, '-') + import multiprocessing.dummy as namespace + else: + print 'Usage:\n\t%s [processes | manager | threads]' % sys.argv[0] + raise SystemExit(2) + + test(namespace) diff --git a/Doc/includes/mp_webserver.py b/Doc/includes/mp_webserver.py new file mode 100644 index 0000000..96d14c5 --- /dev/null +++ b/Doc/includes/mp_webserver.py @@ -0,0 +1,70 @@ +# +# Example where a pool of http servers share a single listening socket +# +# On Windows this module depends on the ability to pickle a socket +# object so that the worker processes can inherit a copy of the server +# object. (We import `multiprocessing.reduction` to enable this pickling.) +# +# Not sure if we should synchronize access to `socket.accept()` method by +# using a process-shared lock -- does not seem to be necessary. +# +# Copyright (c) 2006-2008, R Oudkerk +# All rights reserved. +# + +import os +import sys + +from multiprocessing import Process, current_process, freeze_support +from BaseHTTPServer import HTTPServer +from SimpleHTTPServer import SimpleHTTPRequestHandler + +if sys.platform == 'win32': + import multiprocessing.reduction # make sockets pickable/inheritable + + +def note(format, *args): + sys.stderr.write('[%s]\t%s\n' % (current_process().name, format%args)) + + +class RequestHandler(SimpleHTTPRequestHandler): + # we override log_message() to show which process is handling the request + def log_message(self, format, *args): + note(format, *args) + +def serve_forever(server): + note('starting server') + try: + server.serve_forever() + except KeyboardInterrupt: + pass + + +def runpool(address, number_of_processes): + # create a single server object -- children will each inherit a copy + server = HTTPServer(address, RequestHandler) + + # create child processes to act as workers + for i in range(number_of_processes-1): + Process(target=serve_forever, args=(server,)).start() + + # main process also acts as a worker + serve_forever(server) + + +def test(): + DIR = os.path.join(os.path.dirname(__file__), '..') + ADDRESS = ('localhost', 8000) + NUMBER_OF_PROCESSES = 4 + + print 'Serving at http://%s:%d using %d worker processes' % \ + (ADDRESS[0], ADDRESS[1], NUMBER_OF_PROCESSES) + print 'To exit press Ctrl-' + ['C', 'Break'][sys.platform=='win32'] + + os.chdir(DIR) + runpool(ADDRESS, NUMBER_OF_PROCESSES) + + +if __name__ == '__main__': + freeze_support() + test() diff --git a/Doc/includes/mp_workers.py b/Doc/includes/mp_workers.py index 3b92269..e64a156 100644 --- a/Doc/includes/mp_workers.py +++ b/Doc/includes/mp_workers.py @@ -1,3 +1,16 @@ +# +# Simple example which uses a pool of workers to carry out some tasks. +# +# Notice that the results will probably not come out of the output +# queue in the same in the same order as the corresponding tasks were +# put on the input queue. If it is important to get the results back +# in the original order then consider using `Pool.map()` or +# `Pool.imap()` (which will save on the amount of code needed anyway). +# +# Copyright (c) 2006-2008, R Oudkerk +# All rights reserved. +# + import time import random @@ -55,9 +68,9 @@ def test(): Process(target=worker, args=(task_queue, done_queue)).start() # Get and print results - print('Unordered results:') + print 'Unordered results:' for i in range(len(TASKS1)): - print('\t', done_queue.get()) + print '\t', done_queue.get() # Add more tasks using `put()` for task in TASKS2: @@ -65,7 +78,7 @@ def test(): # Get and print some more results for i in range(len(TASKS2)): - print('\t', done_queue.get()) + print '\t', done_queue.get() # Tell child processes to stop for i in range(NUMBER_OF_PROCESSES): diff --git a/Doc/includes/noddy.c b/Doc/includes/noddy.c new file mode 100644 index 0000000..9d80bbe --- /dev/null +++ b/Doc/includes/noddy.c @@ -0,0 +1,53 @@ +#include <Python.h> + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ +} noddy_NoddyObject; + +static PyTypeObject noddy_NoddyType = { + PyVarObject_HEAD_INIT(NULL, 0) + "noddy.Noddy", /* tp_name */ + sizeof(noddy_NoddyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "Noddy objects", /* tp_doc */ +}; + +static PyMethodDef noddy_methods[] = { + {NULL} /* Sentinel */ +}; + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC +initnoddy(void) +{ + PyObject* m; + + noddy_NoddyType.tp_new = PyType_GenericNew; + if (PyType_Ready(&noddy_NoddyType) < 0) + return; + + m = Py_InitModule3("noddy", noddy_methods, + "Example module that creates an extension type."); + + Py_INCREF(&noddy_NoddyType); + PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType); +} diff --git a/Doc/includes/noddy2.c b/Doc/includes/noddy2.c new file mode 100644 index 0000000..94b92be --- /dev/null +++ b/Doc/includes/noddy2.c @@ -0,0 +1,188 @@ +#include <Python.h> +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; /* first name */ + PyObject *last; /* last name */ + int number; +} Noddy; + +static void +Noddy_dealloc(Noddy* self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static PyObject * +Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Noddy *self; + + self = (Noddy *)type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyString_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + + self->last = PyString_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + + self->number = 0; + } + + return (PyObject *)self; +} + +static int +Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) +{ + PyObject *first=NULL, *last=NULL, *tmp; + + static char *kwlist[] = {"first", "last", "number", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + + return 0; +} + + +static PyMemberDef Noddy_members[] = { + {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, + "last name"}, + {"number", T_INT, offsetof(Noddy, number), 0, + "noddy number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Noddy_name(Noddy* self) +{ + static PyObject *format = NULL; + PyObject *args, *result; + + if (format == NULL) { + format = PyString_FromString("%s %s"); + if (format == NULL) + return NULL; + } + + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + + args = Py_BuildValue("OO", self->first, self->last); + if (args == NULL) + return NULL; + + result = PyString_Format(format, args); + Py_DECREF(args); + + return result; +} + +static PyMethodDef Noddy_methods[] = { + {"name", (PyCFunction)Noddy_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject NoddyType = { + PyVarObject_HEAD_INIT(NULL, 0) + "noddy.Noddy", /* tp_name */ + sizeof(Noddy), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Noddy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Noddy objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Noddy_methods, /* tp_methods */ + Noddy_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Noddy_init, /* tp_init */ + 0, /* tp_alloc */ + Noddy_new, /* tp_new */ +}; + +static PyMethodDef module_methods[] = { + {NULL} /* Sentinel */ +}; + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC +initnoddy2(void) +{ + PyObject* m; + + if (PyType_Ready(&NoddyType) < 0) + return; + + m = Py_InitModule3("noddy2", module_methods, + "Example module that creates an extension type."); + + if (m == NULL) + return; + + Py_INCREF(&NoddyType); + PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); +} diff --git a/Doc/includes/noddy3.c b/Doc/includes/noddy3.c new file mode 100644 index 0000000..43ec42b --- /dev/null +++ b/Doc/includes/noddy3.c @@ -0,0 +1,241 @@ +#include <Python.h> +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; + PyObject *last; + int number; +} Noddy; + +static void +Noddy_dealloc(Noddy* self) +{ + Py_XDECREF(self->first); + Py_XDECREF(self->last); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static PyObject * +Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Noddy *self; + + self = (Noddy *)type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyString_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + + self->last = PyString_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + + self->number = 0; + } + + return (PyObject *)self; +} + +static int +Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) +{ + PyObject *first=NULL, *last=NULL, *tmp; + + static char *kwlist[] = {"first", "last", "number", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_DECREF(tmp); + } + + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_DECREF(tmp); + } + + return 0; +} + +static PyMemberDef Noddy_members[] = { + {"number", T_INT, offsetof(Noddy, number), 0, + "noddy number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Noddy_getfirst(Noddy *self, void *closure) +{ + Py_INCREF(self->first); + return self->first; +} + +static int +Noddy_setfirst(Noddy *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + + if (! PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + + Py_DECREF(self->first); + Py_INCREF(value); + self->first = value; + + return 0; +} + +static PyObject * +Noddy_getlast(Noddy *self, void *closure) +{ + Py_INCREF(self->last); + return self->last; +} + +static int +Noddy_setlast(Noddy *self, PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + + if (! PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + + Py_DECREF(self->last); + Py_INCREF(value); + self->last = value; + + return 0; +} + +static PyGetSetDef Noddy_getseters[] = { + {"first", + (getter)Noddy_getfirst, (setter)Noddy_setfirst, + "first name", + NULL}, + {"last", + (getter)Noddy_getlast, (setter)Noddy_setlast, + "last name", + NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Noddy_name(Noddy* self) +{ + static PyObject *format = NULL; + PyObject *args, *result; + + if (format == NULL) { + format = PyString_FromString("%s %s"); + if (format == NULL) + return NULL; + } + + args = Py_BuildValue("OO", self->first, self->last); + if (args == NULL) + return NULL; + + result = PyString_Format(format, args); + Py_DECREF(args); + + return result; +} + +static PyMethodDef Noddy_methods[] = { + {"name", (PyCFunction)Noddy_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject NoddyType = { + PyVarObject_HEAD_INIT(NULL, 0) + "noddy.Noddy", /* tp_name */ + sizeof(Noddy), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Noddy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Noddy objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Noddy_methods, /* tp_methods */ + Noddy_members, /* tp_members */ + Noddy_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Noddy_init, /* tp_init */ + 0, /* tp_alloc */ + Noddy_new, /* tp_new */ +}; + +static PyMethodDef module_methods[] = { + {NULL} /* Sentinel */ +}; + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC +initnoddy3(void) +{ + PyObject* m; + + if (PyType_Ready(&NoddyType) < 0) + return; + + m = Py_InitModule3("noddy3", module_methods, + "Example module that creates an extension type."); + + if (m == NULL) + return; + + Py_INCREF(&NoddyType); + PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); +} diff --git a/Doc/includes/noddy4.c b/Doc/includes/noddy4.c new file mode 100644 index 0000000..0fd4dc3 --- /dev/null +++ b/Doc/includes/noddy4.c @@ -0,0 +1,224 @@ +#include <Python.h> +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *first; + PyObject *last; + int number; +} Noddy; + +static int +Noddy_traverse(Noddy *self, visitproc visit, void *arg) +{ + int vret; + + if (self->first) { + vret = visit(self->first, arg); + if (vret != 0) + return vret; + } + if (self->last) { + vret = visit(self->last, arg); + if (vret != 0) + return vret; + } + + return 0; +} + +static int +Noddy_clear(Noddy *self) +{ + PyObject *tmp; + + tmp = self->first; + self->first = NULL; + Py_XDECREF(tmp); + + tmp = self->last; + self->last = NULL; + Py_XDECREF(tmp); + + return 0; +} + +static void +Noddy_dealloc(Noddy* self) +{ + PyObject_GC_UnTrack(self); + Noddy_clear(self); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +static PyObject * +Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Noddy *self; + + self = (Noddy *)type->tp_alloc(type, 0); + if (self != NULL) { + self->first = PyString_FromString(""); + if (self->first == NULL) { + Py_DECREF(self); + return NULL; + } + + self->last = PyString_FromString(""); + if (self->last == NULL) { + Py_DECREF(self); + return NULL; + } + + self->number = 0; + } + + return (PyObject *)self; +} + +static int +Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) +{ + PyObject *first=NULL, *last=NULL, *tmp; + + static char *kwlist[] = {"first", "last", "number", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, + &first, &last, + &self->number)) + return -1; + + if (first) { + tmp = self->first; + Py_INCREF(first); + self->first = first; + Py_XDECREF(tmp); + } + + if (last) { + tmp = self->last; + Py_INCREF(last); + self->last = last; + Py_XDECREF(tmp); + } + + return 0; +} + + +static PyMemberDef Noddy_members[] = { + {"first", T_OBJECT_EX, offsetof(Noddy, first), 0, + "first name"}, + {"last", T_OBJECT_EX, offsetof(Noddy, last), 0, + "last name"}, + {"number", T_INT, offsetof(Noddy, number), 0, + "noddy number"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +Noddy_name(Noddy* self) +{ + static PyObject *format = NULL; + PyObject *args, *result; + + if (format == NULL) { + format = PyString_FromString("%s %s"); + if (format == NULL) + return NULL; + } + + if (self->first == NULL) { + PyErr_SetString(PyExc_AttributeError, "first"); + return NULL; + } + + if (self->last == NULL) { + PyErr_SetString(PyExc_AttributeError, "last"); + return NULL; + } + + args = Py_BuildValue("OO", self->first, self->last); + if (args == NULL) + return NULL; + + result = PyString_Format(format, args); + Py_DECREF(args); + + return result; +} + +static PyMethodDef Noddy_methods[] = { + {"name", (PyCFunction)Noddy_name, METH_NOARGS, + "Return the name, combining the first and last name" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject NoddyType = { + PyVarObject_HEAD_INIT(NULL, 0) + "noddy.Noddy", /* tp_name */ + sizeof(Noddy), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Noddy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, /* tp_flags */ + "Noddy objects", /* tp_doc */ + (traverseproc)Noddy_traverse, /* tp_traverse */ + (inquiry)Noddy_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Noddy_methods, /* tp_methods */ + Noddy_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Noddy_init, /* tp_init */ + 0, /* tp_alloc */ + Noddy_new, /* tp_new */ +}; + +static PyMethodDef module_methods[] = { + {NULL} /* Sentinel */ +}; + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC +initnoddy4(void) +{ + PyObject* m; + + if (PyType_Ready(&NoddyType) < 0) + return; + + m = Py_InitModule3("noddy4", module_methods, + "Example module that creates an extension type."); + + if (m == NULL) + return; + + Py_INCREF(&NoddyType); + PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); +} diff --git a/Doc/includes/run-func.c b/Doc/includes/run-func.c index 392f86d..8276b01 100644 --- a/Doc/includes/run-func.c +++ b/Doc/includes/run-func.c @@ -1,4 +1,3 @@ -#define PY_SSIZE_T_CLEAN #include <Python.h> int @@ -14,7 +13,7 @@ main(int argc, char *argv[]) } Py_Initialize(); - pName = PyUnicode_DecodeFSDefault(argv[1]); + pName = PyString_FromString(argv[1]); /* Error checking of pName left out */ pModule = PyImport_Import(pName); @@ -27,7 +26,7 @@ main(int argc, char *argv[]) if (pFunc && PyCallable_Check(pFunc)) { pArgs = PyTuple_New(argc - 3); for (i = 0; i < argc - 3; ++i) { - pValue = PyLong_FromLong(atoi(argv[i + 3])); + pValue = PyInt_FromLong(atoi(argv[i + 3])); if (!pValue) { Py_DECREF(pArgs); Py_DECREF(pModule); @@ -40,7 +39,7 @@ main(int argc, char *argv[]) pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); if (pValue != NULL) { - printf("Result of call: %ld\n", PyLong_AsLong(pValue)); + printf("Result of call: %ld\n", PyInt_AsLong(pValue)); Py_DECREF(pValue); } else { @@ -64,8 +63,6 @@ main(int argc, char *argv[]) fprintf(stderr, "Failed to load \"%s\"\n", argv[1]); return 1; } - if (Py_FinalizeEx() < 0) { - return 120; - } + Py_Finalize(); return 0; } diff --git a/Doc/includes/shoddy.c b/Doc/includes/shoddy.c new file mode 100644 index 0000000..4cb39db --- /dev/null +++ b/Doc/includes/shoddy.c @@ -0,0 +1,90 @@ +#include <Python.h> + +typedef struct { + PyListObject list; + int state; +} Shoddy; + + +static PyObject * +Shoddy_increment(Shoddy *self, PyObject *unused) +{ + self->state++; + return PyInt_FromLong(self->state); +} + + +static PyMethodDef Shoddy_methods[] = { + {"increment", (PyCFunction)Shoddy_increment, METH_NOARGS, + PyDoc_STR("increment state counter")}, + {NULL, NULL}, +}; + +static int +Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + + +static PyTypeObject ShoddyType = { + PyVarObject_HEAD_INIT(NULL, 0) + "shoddy.Shoddy", /* tp_name */ + sizeof(Shoddy), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Shoddy_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Shoddy_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +PyMODINIT_FUNC +initshoddy(void) +{ + PyObject *m; + + ShoddyType.tp_base = &PyList_Type; + if (PyType_Ready(&ShoddyType) < 0) + return; + + m = Py_InitModule3("shoddy", NULL, "Shoddy module"); + if (m == NULL) + return; + + Py_INCREF(&ShoddyType); + PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); +} diff --git a/Doc/includes/sqlite3/adapter_datetime.py b/Doc/includes/sqlite3/adapter_datetime.py index d5221d8..3460498 100644 --- a/Doc/includes/sqlite3/adapter_datetime.py +++ b/Doc/includes/sqlite3/adapter_datetime.py @@ -1,6 +1,5 @@ import sqlite3 -import datetime -import time +import datetime, time def adapt_datetime(ts): return time.mktime(ts.timetuple()) @@ -12,6 +11,4 @@ cur = con.cursor() now = datetime.datetime.now() cur.execute("select ?", (now,)) -print(cur.fetchone()[0]) - -con.close() +print cur.fetchone()[0] diff --git a/Doc/includes/sqlite3/adapter_point_1.py b/Doc/includes/sqlite3/adapter_point_1.py index 77daf8f..a741f6c 100644 --- a/Doc/includes/sqlite3/adapter_point_1.py +++ b/Doc/includes/sqlite3/adapter_point_1.py @@ -1,6 +1,6 @@ import sqlite3 -class Point: +class Point(object): def __init__(self, x, y): self.x, self.y = x, y @@ -13,6 +13,4 @@ cur = con.cursor() p = Point(4.0, -3.2) cur.execute("select ?", (p,)) -print(cur.fetchone()[0]) - -con.close() +print cur.fetchone()[0] diff --git a/Doc/includes/sqlite3/adapter_point_2.py b/Doc/includes/sqlite3/adapter_point_2.py index cb86331..200a064 100644 --- a/Doc/includes/sqlite3/adapter_point_2.py +++ b/Doc/includes/sqlite3/adapter_point_2.py @@ -1,6 +1,6 @@ import sqlite3 -class Point: +class Point(object): def __init__(self, x, y): self.x, self.y = x, y @@ -14,6 +14,4 @@ cur = con.cursor() p = Point(4.0, -3.2) cur.execute("select ?", (p,)) -print(cur.fetchone()[0]) - -con.close() +print cur.fetchone()[0] diff --git a/Doc/includes/sqlite3/collation_reverse.py b/Doc/includes/sqlite3/collation_reverse.py index 3504a35..e956402 100644 --- a/Doc/includes/sqlite3/collation_reverse.py +++ b/Doc/includes/sqlite3/collation_reverse.py @@ -1,12 +1,7 @@ import sqlite3 def collate_reverse(string1, string2): - if string1 == string2: - return 0 - elif string1 < string2: - return 1 - else: - return -1 + return -cmp(string1, string2) con = sqlite3.connect(":memory:") con.create_collation("reverse", collate_reverse) @@ -16,5 +11,5 @@ cur.execute("create table test(x)") cur.executemany("insert into test(x) values (?)", [("a",), ("b",)]) cur.execute("select x from test order by x collate reverse") for row in cur: - print(row) + print row con.close() diff --git a/Doc/includes/sqlite3/complete_statement.py b/Doc/includes/sqlite3/complete_statement.py index cd38d73..76ea7f6 100644 --- a/Doc/includes/sqlite3/complete_statement.py +++ b/Doc/includes/sqlite3/complete_statement.py @@ -8,11 +8,11 @@ cur = con.cursor() buffer = "" -print("Enter your SQL commands to execute in sqlite3.") -print("Enter a blank line to exit.") +print "Enter your SQL commands to execute in sqlite3." +print "Enter a blank line to exit." while True: - line = input() + line = raw_input() if line == "": break buffer += line @@ -22,9 +22,9 @@ while True: cur.execute(buffer) if buffer.lstrip().upper().startswith("SELECT"): - print(cur.fetchall()) + print cur.fetchall() except sqlite3.Error as e: - print("An error occurred:", e.args[0]) + print "An error occurred:", e.args[0] buffer = "" con.close() diff --git a/Doc/includes/sqlite3/connect_db_1.py b/Doc/includes/sqlite3/connect_db_1.py new file mode 100644 index 0000000..1b97523 --- /dev/null +++ b/Doc/includes/sqlite3/connect_db_1.py @@ -0,0 +1,3 @@ +import sqlite3 + +con = sqlite3.connect("mydb") diff --git a/Doc/includes/sqlite3/connect_db_2.py b/Doc/includes/sqlite3/connect_db_2.py new file mode 100644 index 0000000..f9728b36 --- /dev/null +++ b/Doc/includes/sqlite3/connect_db_2.py @@ -0,0 +1,3 @@ +import sqlite3 + +con = sqlite3.connect(":memory:") diff --git a/Doc/includes/sqlite3/converter_point.py b/Doc/includes/sqlite3/converter_point.py index 5df828e..e220e9b 100644 --- a/Doc/includes/sqlite3/converter_point.py +++ b/Doc/includes/sqlite3/converter_point.py @@ -1,6 +1,6 @@ import sqlite3 -class Point: +class Point(object): def __init__(self, x, y): self.x, self.y = x, y @@ -8,10 +8,10 @@ class Point: return "(%f;%f)" % (self.x, self.y) def adapt_point(point): - return ("%f;%f" % (point.x, point.y)).encode('ascii') + return "%f;%f" % (point.x, point.y) def convert_point(s): - x, y = list(map(float, s.split(b";"))) + x, y = map(float, s.split(";")) return Point(x, y) # Register the adapter @@ -30,7 +30,7 @@ cur.execute("create table test(p point)") cur.execute("insert into test(p) values (?)", (p,)) cur.execute("select p from test") -print("with declared types:", cur.fetchone()[0]) +print "with declared types:", cur.fetchone()[0] cur.close() con.close() @@ -42,6 +42,6 @@ cur.execute("create table test(p)") cur.execute("insert into test(p) values (?)", (p,)) cur.execute('select p as "p [point]" from test') -print("with column names:", cur.fetchone()[0]) +print "with column names:", cur.fetchone()[0] cur.close() con.close() diff --git a/Doc/includes/sqlite3/countcursors.py b/Doc/includes/sqlite3/countcursors.py index 112f477..df04cad 100644 --- a/Doc/includes/sqlite3/countcursors.py +++ b/Doc/includes/sqlite3/countcursors.py @@ -12,6 +12,4 @@ class CountCursorsConnection(sqlite3.Connection): con = sqlite3.connect(":memory:", factory=CountCursorsConnection) cur1 = con.cursor() cur2 = con.cursor() -print(con.numcursors) - -con.close() +print con.numcursors diff --git a/Doc/includes/sqlite3/ctx_manager.py b/Doc/includes/sqlite3/ctx_manager.py index 6db77d4..d6f27e6 100644 --- a/Doc/includes/sqlite3/ctx_manager.py +++ b/Doc/includes/sqlite3/ctx_manager.py @@ -13,8 +13,4 @@ try: with con: con.execute("insert into person(firstname) values (?)", ("Joe",)) except sqlite3.IntegrityError: - print("couldn't add Joe twice") - -# Connection object used as context manager only commits or rollbacks transactions, -# so the connection object should be closed manually -con.close() + print "couldn't add Joe twice" diff --git a/Doc/includes/sqlite3/execsql_fetchonerow.py b/Doc/includes/sqlite3/execsql_fetchonerow.py index 115bcb5..8044ecf 100644 --- a/Doc/includes/sqlite3/execsql_fetchonerow.py +++ b/Doc/includes/sqlite3/execsql_fetchonerow.py @@ -9,11 +9,9 @@ SELECT = "select name_last, age from people order by age, name_last" # resulting sequences to yield their elements (name_last, age): cur.execute(SELECT) for (name_last, age) in cur: - print('%s is %d years old.' % (name_last, age)) + print '%s is %d years old.' % (name_last, age) # 2. Equivalently: cur.execute(SELECT) for row in cur: - print('%s is %d years old.' % (row[0], row[1])) - -con.close() + print '%s is %d years old.' % (row[0], row[1]) diff --git a/Doc/includes/sqlite3/execsql_printall_1.py b/Doc/includes/sqlite3/execsql_printall_1.py index 19306e6..d27d735 100644 --- a/Doc/includes/sqlite3/execsql_printall_1.py +++ b/Doc/includes/sqlite3/execsql_printall_1.py @@ -10,6 +10,4 @@ cur = con.cursor() cur.execute("select * from people order by age") # Retrieve all rows as a sequence and print that sequence: -print(cur.fetchall()) - -con.close() +print cur.fetchall() diff --git a/Doc/includes/sqlite3/execute_1.py b/Doc/includes/sqlite3/execute_1.py index 3466b12..763167c 100644 --- a/Doc/includes/sqlite3/execute_1.py +++ b/Doc/includes/sqlite3/execute_1.py @@ -13,6 +13,4 @@ cur.execute("insert into people values (?, ?)", (who, age)) # And this is the named style: cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age}) -print(cur.fetchone()) - -con.close() +print cur.fetchone() diff --git a/Doc/includes/sqlite3/execute_3.py b/Doc/includes/sqlite3/execute_3.py new file mode 100644 index 0000000..b64621f --- /dev/null +++ b/Doc/includes/sqlite3/execute_3.py @@ -0,0 +1,12 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() + +who = "Yeltsin" +age = 72 + +cur.execute("select name_last, age from people where name_last=:who and age=:age", + locals()) +print cur.fetchone() diff --git a/Doc/includes/sqlite3/executemany_1.py b/Doc/includes/sqlite3/executemany_1.py index edf6f8b..24357c5 100644 --- a/Doc/includes/sqlite3/executemany_1.py +++ b/Doc/includes/sqlite3/executemany_1.py @@ -7,7 +7,7 @@ class IterChars: def __iter__(self): return self - def __next__(self): + def next(self): if self.count > ord('z'): raise StopIteration self.count += 1 @@ -21,6 +21,4 @@ theIter = IterChars() cur.executemany("insert into characters(c) values (?)", theIter) cur.execute("select c from characters") -print(cur.fetchall()) - -con.close() +print cur.fetchall() diff --git a/Doc/includes/sqlite3/executemany_2.py b/Doc/includes/sqlite3/executemany_2.py index 02a594c..0b12688 100644 --- a/Doc/includes/sqlite3/executemany_2.py +++ b/Doc/includes/sqlite3/executemany_2.py @@ -2,7 +2,7 @@ import sqlite3 import string def char_generator(): - for c in string.ascii_lowercase: + for c in string.lowercase: yield (c,) con = sqlite3.connect(":memory:") @@ -12,6 +12,4 @@ cur.execute("create table characters(c)") cur.executemany("insert into characters(c) values (?)", char_generator()) cur.execute("select c from characters") -print(cur.fetchall()) - -con.close() +print cur.fetchall() diff --git a/Doc/includes/sqlite3/executescript.py b/Doc/includes/sqlite3/executescript.py index aea8943..7e53581 100644 --- a/Doc/includes/sqlite3/executescript.py +++ b/Doc/includes/sqlite3/executescript.py @@ -22,4 +22,3 @@ cur.executescript(""" 1987 ); """) -con.close() diff --git a/Doc/includes/sqlite3/insert_more_people.py b/Doc/includes/sqlite3/insert_more_people.py index 10cf937..edbc79e 100644 --- a/Doc/includes/sqlite3/insert_more_people.py +++ b/Doc/includes/sqlite3/insert_more_people.py @@ -14,5 +14,3 @@ for person in newPeople: # The changes will not be saved unless the transaction is committed explicitly: con.commit() - -con.close() diff --git a/Doc/includes/sqlite3/load_extension.py b/Doc/includes/sqlite3/load_extension.py index 624cfe2..f1a92b3 100644 --- a/Doc/includes/sqlite3/load_extension.py +++ b/Doc/includes/sqlite3/load_extension.py @@ -23,6 +23,4 @@ con.executescript(""" insert into recipe (name, ingredients) values ('pumpkin pie', 'pumpkin sugar flour butter'); """) for row in con.execute("select rowid, name, ingredients from recipe where name match 'pie'"): - print(row) - -con.close() + print row diff --git a/Doc/includes/sqlite3/md5func.py b/Doc/includes/sqlite3/md5func.py index 16dc348..5769687 100644 --- a/Doc/includes/sqlite3/md5func.py +++ b/Doc/includes/sqlite3/md5func.py @@ -1,13 +1,11 @@ import sqlite3 -import hashlib +import md5 def md5sum(t): - return hashlib.md5(t).hexdigest() + return md5.md5(t).hexdigest() con = sqlite3.connect(":memory:") con.create_function("md5", 1, md5sum) cur = con.cursor() -cur.execute("select md5(?)", (b"foo",)) -print(cur.fetchone()[0]) - -con.close() +cur.execute("select md5(?)", ("foo",)) +print cur.fetchone()[0] diff --git a/Doc/includes/sqlite3/mysumaggr.py b/Doc/includes/sqlite3/mysumaggr.py index 11f9639..6d0cd55 100644 --- a/Doc/includes/sqlite3/mysumaggr.py +++ b/Doc/includes/sqlite3/mysumaggr.py @@ -17,6 +17,4 @@ cur.execute("create table test(i)") cur.execute("insert into test(i) values (1)") cur.execute("insert into test(i) values (2)") cur.execute("select mysum(i) from test") -print(cur.fetchone()[0]) - -con.close() +print cur.fetchone()[0] diff --git a/Doc/includes/sqlite3/parse_colnames.py b/Doc/includes/sqlite3/parse_colnames.py index 5f01dbf..fcded00 100644 --- a/Doc/includes/sqlite3/parse_colnames.py +++ b/Doc/includes/sqlite3/parse_colnames.py @@ -5,6 +5,4 @@ con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES) cur = con.cursor() cur.execute('select ? as "x [timestamp]"', (datetime.datetime.now(),)) dt = cur.fetchone()[0] -print(dt, type(dt)) - -con.close() +print dt, type(dt) diff --git a/Doc/includes/sqlite3/pysqlite_datetime.py b/Doc/includes/sqlite3/pysqlite_datetime.py index 5d843f9..efa4b06 100644 --- a/Doc/includes/sqlite3/pysqlite_datetime.py +++ b/Doc/includes/sqlite3/pysqlite_datetime.py @@ -11,12 +11,10 @@ now = datetime.datetime.now() cur.execute("insert into test(d, ts) values (?, ?)", (today, now)) cur.execute("select d, ts from test") row = cur.fetchone() -print(today, "=>", row[0], type(row[0])) -print(now, "=>", row[1], type(row[1])) +print today, "=>", row[0], type(row[0]) +print now, "=>", row[1], type(row[1]) cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"') row = cur.fetchone() -print("current_date", row[0], type(row[0])) -print("current_timestamp", row[1], type(row[1])) - -con.close() +print "current_date", row[0], type(row[0]) +print "current_timestamp", row[1], type(row[1]) diff --git a/Doc/includes/sqlite3/row_factory.py b/Doc/includes/sqlite3/row_factory.py index 9de6e7b..64676c8 100644 --- a/Doc/includes/sqlite3/row_factory.py +++ b/Doc/includes/sqlite3/row_factory.py @@ -10,6 +10,4 @@ con = sqlite3.connect(":memory:") con.row_factory = dict_factory cur = con.cursor() cur.execute("select 1 as a") -print(cur.fetchone()["a"]) - -con.close() +print cur.fetchone()["a"] diff --git a/Doc/includes/sqlite3/rowclass.py b/Doc/includes/sqlite3/rowclass.py index fc60287..92b5ad6 100644 --- a/Doc/includes/sqlite3/rowclass.py +++ b/Doc/includes/sqlite3/rowclass.py @@ -10,5 +10,3 @@ for row in cur: assert row["name"] == row["nAmE"] assert row[1] == row["age"] assert row[1] == row["AgE"] - -con.close() diff --git a/Doc/includes/sqlite3/shortcut_methods.py b/Doc/includes/sqlite3/shortcut_methods.py index 98a3941..e128a3b 100644 --- a/Doc/includes/sqlite3/shortcut_methods.py +++ b/Doc/includes/sqlite3/shortcut_methods.py @@ -15,10 +15,6 @@ con.executemany("insert into person(firstname, lastname) values (?, ?)", persons # Print the table contents for row in con.execute("select firstname, lastname from person"): - print(row) + print row -print("I just deleted", con.execute("delete from person").rowcount, "rows") - -# close is not a shortcut method and it's not called automatically, -# so the connection object should be closed manually -con.close() +print "I just deleted", con.execute("delete from person").rowcount, "rows" diff --git a/Doc/includes/sqlite3/simple_tableprinter.py b/Doc/includes/sqlite3/simple_tableprinter.py index 148a170..67ea6a2 100644 --- a/Doc/includes/sqlite3/simple_tableprinter.py +++ b/Doc/includes/sqlite3/simple_tableprinter.py @@ -11,9 +11,9 @@ cur.execute(SELECT) # Print a header. for fieldDesc in cur.description: - print(fieldDesc[0].ljust(FIELD_MAX_WIDTH), end=' ') -print() # Finish the header with a newline. -print('-' * 78) + print fieldDesc[0].ljust(FIELD_MAX_WIDTH) , +print # Finish the header with a newline. +print '-' * 78 # For each row, print the value of each field left-justified within # the maximum possible width of that field. @@ -21,8 +21,6 @@ fieldIndices = range(len(cur.description)) for row in cur: for fieldIndex in fieldIndices: fieldValue = str(row[fieldIndex]) - print(fieldValue.ljust(FIELD_MAX_WIDTH), end=' ') + print fieldValue.ljust(FIELD_MAX_WIDTH) , - print() # Finish the row with a newline. - -con.close() + print # Finish the row with a newline. diff --git a/Doc/includes/sqlite3/text_factory.py b/Doc/includes/sqlite3/text_factory.py index a857a15..577378f 100644 --- a/Doc/includes/sqlite3/text_factory.py +++ b/Doc/includes/sqlite3/text_factory.py @@ -3,7 +3,7 @@ import sqlite3 con = sqlite3.connect(":memory:") cur = con.cursor() -AUSTRIA = "\xd6sterreich" +AUSTRIA = u"\xd6sterreich" # by default, rows are returned as Unicode cur.execute("select ?", (AUSTRIA,)) @@ -11,19 +11,30 @@ row = cur.fetchone() assert row[0] == AUSTRIA # but we can make sqlite3 always return bytestrings ... -con.text_factory = bytes +con.text_factory = str cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() -assert type(row[0]) is bytes +assert type(row[0]) is str # the bytestrings will be encoded in UTF-8, unless you stored garbage in the # database ... assert row[0] == AUSTRIA.encode("utf-8") # we can also implement a custom text_factory ... -# here we implement one that appends "foo" to all strings -con.text_factory = lambda x: x.decode("utf-8") + "foo" -cur.execute("select ?", ("bar",)) +# here we implement one that will ignore Unicode characters that cannot be +# decoded from UTF-8 +con.text_factory = lambda x: unicode(x, "utf-8", "ignore") +cur.execute("select ?", ("this is latin1 and would normally create errors" + + u"\xe4\xf6\xfc".encode("latin1"),)) row = cur.fetchone() -assert row[0] == "barfoo" +assert type(row[0]) is unicode -con.close() +# sqlite3 offers a built-in optimized text_factory that will return bytestring +# objects, if the data is in ASCII only, and otherwise return unicode objects +con.text_factory = sqlite3.OptimizedUnicode +cur.execute("select ?", (AUSTRIA,)) +row = cur.fetchone() +assert type(row[0]) is unicode + +cur.execute("select ?", ("Germany",)) +row = cur.fetchone() +assert type(row[0]) is str diff --git a/Doc/includes/sublist.c b/Doc/includes/sublist.c deleted file mode 100644 index b2c26e7..0000000 --- a/Doc/includes/sublist.c +++ /dev/null @@ -1,69 +0,0 @@ -#define PY_SSIZE_T_CLEAN -#include <Python.h> - -typedef struct { - PyListObject list; - int state; -} SubListObject; - -static PyObject * -SubList_increment(SubListObject *self, PyObject *unused) -{ - self->state++; - return PyLong_FromLong(self->state); -} - -static PyMethodDef SubList_methods[] = { - {"increment", (PyCFunction) SubList_increment, METH_NOARGS, - PyDoc_STR("increment state counter")}, - {NULL}, -}; - -static int -SubList_init(SubListObject *self, PyObject *args, PyObject *kwds) -{ - if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0) - return -1; - self->state = 0; - return 0; -} - -static PyTypeObject SubListType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "sublist.SubList", - .tp_doc = "SubList objects", - .tp_basicsize = sizeof(SubListObject), - .tp_itemsize = 0, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_init = (initproc) SubList_init, - .tp_methods = SubList_methods, -}; - -static PyModuleDef sublistmodule = { - PyModuleDef_HEAD_INIT, - .m_name = "sublist", - .m_doc = "Example module that creates an extension type.", - .m_size = -1, -}; - -PyMODINIT_FUNC -PyInit_sublist(void) -{ - PyObject *m; - SubListType.tp_base = &PyList_Type; - if (PyType_Ready(&SubListType) < 0) - return NULL; - - m = PyModule_Create(&sublistmodule); - if (m == NULL) - return NULL; - - Py_INCREF(&SubListType); - if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType) < 0) { - Py_DECREF(&SubListType); - Py_DECREF(m); - return NULL; - } - - return m; -} diff --git a/Doc/includes/test.py b/Doc/includes/test.py index 09ebe3f..7ebf46a 100644 --- a/Doc/includes/test.py +++ b/Doc/includes/test.py @@ -1,168 +1,181 @@ -"""Test module for the custom examples +"""Test module for the noddy examples -Custom 1: +Noddy 1: ->>> import custom ->>> c1 = custom.Custom() ->>> c2 = custom.Custom() ->>> del c1 ->>> del c2 +>>> import noddy +>>> n1 = noddy.Noddy() +>>> n2 = noddy.Noddy() +>>> del n1 +>>> del n2 -Custom 2 +Noddy 2 ->>> import custom2 ->>> c1 = custom2.Custom('jim', 'fulton', 42) ->>> c1.first +>>> import noddy2 +>>> n1 = noddy2.Noddy('jim', 'fulton', 42) +>>> n1.first 'jim' ->>> c1.last +>>> n1.last 'fulton' ->>> c1.number +>>> n1.number 42 ->>> c1.name() +>>> n1.name() 'jim fulton' ->>> c1.first = 'will' ->>> c1.name() +>>> n1.first = 'will' +>>> n1.name() 'will fulton' ->>> c1.last = 'tell' ->>> c1.name() +>>> n1.last = 'tell' +>>> n1.name() 'will tell' ->>> del c1.first ->>> c1.name() +>>> del n1.first +>>> n1.name() Traceback (most recent call last): ... AttributeError: first ->>> c1.first +>>> n1.first Traceback (most recent call last): ... AttributeError: first ->>> c1.first = 'drew' ->>> c1.first +>>> n1.first = 'drew' +>>> n1.first 'drew' ->>> del c1.number +>>> del n1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> c1.number=2 ->>> c1.number +>>> n1.number=2 +>>> n1.number 2 ->>> c1.first = 42 ->>> c1.name() +>>> n1.first = 42 +>>> n1.name() '42 tell' ->>> c2 = custom2.Custom() ->>> c2.name() +>>> n2 = noddy2.Noddy() +>>> n2.name() ' ' ->>> c2.first +>>> n2.first '' ->>> c2.last +>>> n2.last '' ->>> del c2.first ->>> c2.first +>>> del n2.first +>>> n2.first Traceback (most recent call last): ... AttributeError: first ->>> c2.first +>>> n2.first Traceback (most recent call last): ... AttributeError: first ->>> c2.name() +>>> n2.name() Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: first ->>> c2.number +>>> n2.number 0 ->>> n3 = custom2.Custom('jim', 'fulton', 'waaa') +>>> n3 = noddy2.Noddy('jim', 'fulton', 'waaa') Traceback (most recent call last): File "<stdin>", line 1, in ? -TypeError: an integer is required (got type str) ->>> del c1 ->>> del c2 +TypeError: an integer is required +>>> del n1 +>>> del n2 -Custom 3 +Noddy 3 ->>> import custom3 ->>> c1 = custom3.Custom('jim', 'fulton', 42) ->>> c1 = custom3.Custom('jim', 'fulton', 42) ->>> c1.name() +>>> import noddy3 +>>> n1 = noddy3.Noddy('jim', 'fulton', 42) +>>> n1 = noddy3.Noddy('jim', 'fulton', 42) +>>> n1.name() 'jim fulton' ->>> del c1.first +>>> del n1.first Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: Cannot delete the first attribute ->>> c1.first = 42 +>>> n1.first = 42 Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: The first attribute value must be a string ->>> c1.first = 'will' ->>> c1.name() +>>> n1.first = 'will' +>>> n1.name() 'will fulton' ->>> c2 = custom3.Custom() ->>> c2 = custom3.Custom() ->>> c2 = custom3.Custom() ->>> n3 = custom3.Custom('jim', 'fulton', 'waaa') +>>> n2 = noddy3.Noddy() +>>> n2 = noddy3.Noddy() +>>> n2 = noddy3.Noddy() +>>> n3 = noddy3.Noddy('jim', 'fulton', 'waaa') Traceback (most recent call last): File "<stdin>", line 1, in ? -TypeError: an integer is required (got type str) ->>> del c1 ->>> del c2 +TypeError: an integer is required +>>> del n1 +>>> del n2 -Custom 4 +Noddy 4 ->>> import custom4 ->>> c1 = custom4.Custom('jim', 'fulton', 42) ->>> c1.first +>>> import noddy4 +>>> n1 = noddy4.Noddy('jim', 'fulton', 42) +>>> n1.first 'jim' ->>> c1.last +>>> n1.last 'fulton' ->>> c1.number +>>> n1.number 42 ->>> c1.name() +>>> n1.name() 'jim fulton' ->>> c1.first = 'will' ->>> c1.name() +>>> n1.first = 'will' +>>> n1.name() 'will fulton' ->>> c1.last = 'tell' ->>> c1.name() +>>> n1.last = 'tell' +>>> n1.name() 'will tell' ->>> del c1.first +>>> del n1.first +>>> n1.name() Traceback (most recent call last): ... -TypeError: Cannot delete the first attribute ->>> c1.name() -'will tell' ->>> c1.first = 'drew' ->>> c1.first +AttributeError: first +>>> n1.first +Traceback (most recent call last): +... +AttributeError: first +>>> n1.first = 'drew' +>>> n1.first 'drew' ->>> del c1.number +>>> del n1.number Traceback (most recent call last): ... TypeError: can't delete numeric/char attribute ->>> c1.number=2 ->>> c1.number +>>> n1.number=2 +>>> n1.number 2 ->>> c1.first = 42 -Traceback (most recent call last): -... -TypeError: The first attribute value must be a string ->>> c1.name() -'drew tell' ->>> c2 = custom4.Custom() ->>> c2 = custom4.Custom() ->>> c2 = custom4.Custom() ->>> c2 = custom4.Custom() ->>> c2.name() +>>> n1.first = 42 +>>> n1.name() +'42 tell' +>>> n2 = noddy4.Noddy() +>>> n2 = noddy4.Noddy() +>>> n2 = noddy4.Noddy() +>>> n2 = noddy4.Noddy() +>>> n2.name() ' ' ->>> c2.first +>>> n2.first '' ->>> c2.last +>>> n2.last '' ->>> c2.number -0 ->>> n3 = custom4.Custom('jim', 'fulton', 'waaa') +>>> del n2.first +>>> n2.first Traceback (most recent call last): ... -TypeError: an integer is required (got type str) +AttributeError: first +>>> n2.first +Traceback (most recent call last): +... +AttributeError: first +>>> n2.name() +Traceback (most recent call last): + File "<stdin>", line 1, in ? +AttributeError: first +>>> n2.number +0 +>>> n3 = noddy4.Noddy('jim', 'fulton', 'waaa') +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: an integer is required Test cyclic gc(?) @@ -170,14 +183,15 @@ Test cyclic gc(?) >>> import gc >>> gc.disable() ->>> class Subclass(custom4.Custom): pass -... ->>> s = Subclass() ->>> s.cycle = [s] ->>> s.cycle.append(s.cycle) ->>> x = object() ->>> s.x = x ->>> del s +>>> x = [] +>>> l = [x] +>>> n2.first = l +>>> n2.first +[[]] +>>> l.append(n2) +>>> del l +>>> del n1 +>>> del n2 >>> sys.getrefcount(x) 3 >>> ignore = gc.collect() @@ -190,7 +204,7 @@ Test cyclic gc(?) import os import sys from distutils.util import get_platform -PLAT_SPEC = "%s-%d.%d" % (get_platform(), *sys.version_info[:2]) +PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3]) src = os.path.join("build", "lib.%s" % PLAT_SPEC) sys.path.append(src) diff --git a/Doc/includes/turtle-star.py b/Doc/includes/turtle-star.py deleted file mode 100644 index 1a5db76..0000000 --- a/Doc/includes/turtle-star.py +++ /dev/null @@ -1,10 +0,0 @@ -from turtle import * -color('red', 'yellow') -begin_fill() -while True: - forward(200) - left(170) - if abs(pos()) < 1: - break -end_fill() -done() diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h index 9ada03c..0afe375 100644 --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -1,16 +1,15 @@ typedef struct _typeobject { PyObject_VAR_HEAD - const char *tp_name; /* For printing, in format "<module>.<name>" */ - Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ + char *tp_name; /* For printing, in format "<module>.<name>" */ + int tp_basicsize, tp_itemsize; /* For allocation */ /* Methods to implement standard operations */ destructor tp_dealloc; - Py_ssize_t tp_vectorcall_offset; + printfunc tp_print; getattrfunc tp_getattr; setattrfunc tp_setattr; - PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2) - or tp_reserved (Python 3) */ + cmpfunc tp_compare; reprfunc tp_repr; /* Method suites for standard classes */ @@ -31,22 +30,25 @@ typedef struct _typeobject { PyBufferProcs *tp_as_buffer; /* Flags to define presence of optional/expanded features */ - unsigned long tp_flags; + long tp_flags; - const char *tp_doc; /* Documentation string */ + char *tp_doc; /* Documentation string */ + /* Assigned meaning in release 2.0 */ /* call function for all accessible objects */ traverseproc tp_traverse; /* delete references to contained objects */ inquiry tp_clear; + /* Assigned meaning in release 2.1 */ /* rich comparisons */ richcmpfunc tp_richcompare; /* weak reference enabler */ - Py_ssize_t tp_weaklistoffset; + long tp_weaklistoffset; + /* Added in release 2.2 */ /* Iterators */ getiterfunc tp_iter; iternextfunc tp_iternext; @@ -59,7 +61,7 @@ typedef struct _typeobject { PyObject *tp_dict; descrgetfunc tp_descr_get; descrsetfunc tp_descr_set; - Py_ssize_t tp_dictoffset; + long tp_dictoffset; initproc tp_init; allocfunc tp_alloc; newfunc tp_new; @@ -70,11 +72,5 @@ typedef struct _typeobject { PyObject *tp_cache; PyObject *tp_subclasses; PyObject *tp_weaklist; - destructor tp_del; - - /* Type attribute cache version tag. Added in version 2.6 */ - unsigned int tp_version_tag; - - destructor tp_finalize; } PyTypeObject; diff --git a/Doc/includes/tzinfo_examples.py b/Doc/includes/tzinfo-examples.py index 9b9e32a..5132429 100644 --- a/Doc/includes/tzinfo_examples.py +++ b/Doc/includes/tzinfo-examples.py @@ -2,12 +2,45 @@ from datetime import tzinfo, timedelta, datetime ZERO = timedelta(0) HOUR = timedelta(hours=1) -SECOND = timedelta(seconds=1) + +# A UTC class. + +class UTC(tzinfo): + """UTC""" + + def utcoffset(self, dt): + return ZERO + + def tzname(self, dt): + return "UTC" + + def dst(self, dt): + return ZERO + +utc = UTC() + +# A class building tzinfo objects for fixed-offset time zones. +# Note that FixedOffset(0, "UTC") is a different way to build a +# UTC tzinfo object. + +class FixedOffset(tzinfo): + """Fixed offset in minutes east from UTC.""" + + def __init__(self, offset, name): + self.__offset = timedelta(minutes = offset) + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return ZERO # A class capturing the platform's idea of local time. -# (May result in wrong values on historical times in -# timezones where UTC offset and/or the DST rules had -# changed in the past.) + import time as _time STDOFFSET = timedelta(seconds = -_time.timezone) @@ -20,16 +53,6 @@ DSTDIFF = DSTOFFSET - STDOFFSET class LocalTimezone(tzinfo): - def fromutc(self, dt): - assert dt.tzinfo is self - stamp = (dt - datetime(1970, 1, 1, tzinfo=self)) // SECOND - args = _time.localtime(stamp)[:6] - dst_diff = DSTDIFF // SECOND - # Detect fold - fold = (args == _time.localtime(stamp - dst_diff)) - return datetime(*args, microsecond=dt.microsecond, - tzinfo=self, fold=fold) - def utcoffset(self, dt): if self._isdst(dt): return DSTOFFSET @@ -76,37 +99,20 @@ def first_sunday_on_or_after(dt): # In the US, since 2007, DST starts at 2am (standard time) on the second # Sunday in March, which is the first Sunday on or after Mar 8. DSTSTART_2007 = datetime(1, 3, 8, 2) -# and ends at 2am (DST time) on the first Sunday of Nov. -DSTEND_2007 = datetime(1, 11, 1, 2) +# and ends at 2am (DST time; 1am standard time) on the first Sunday of Nov. +DSTEND_2007 = datetime(1, 11, 1, 1) # From 1987 to 2006, DST used to start at 2am (standard time) on the first -# Sunday in April and to end at 2am (DST time) on the last +# Sunday in April and to end at 2am (DST time; 1am standard time) on the last # Sunday of October, which is the first Sunday on or after Oct 25. DSTSTART_1987_2006 = datetime(1, 4, 1, 2) -DSTEND_1987_2006 = datetime(1, 10, 25, 2) +DSTEND_1987_2006 = datetime(1, 10, 25, 1) # From 1967 to 1986, DST used to start at 2am (standard time) on the last -# Sunday in April (the one on or after April 24) and to end at 2am (DST time) -# on the last Sunday of October, which is the first Sunday +# Sunday in April (the one on or after April 24) and to end at 2am (DST time; +# 1am standard time) on the last Sunday of October, which is the first Sunday # on or after Oct 25. DSTSTART_1967_1986 = datetime(1, 4, 24, 2) DSTEND_1967_1986 = DSTEND_1987_2006 -def us_dst_range(year): - # Find start and end times for US DST. For years before 1967, return - # start = end for no DST. - if 2006 < year: - dststart, dstend = DSTSTART_2007, DSTEND_2007 - elif 1986 < year < 2007: - dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006 - elif 1966 < year < 1987: - dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986 - else: - return (datetime(year, 1, 1), ) * 2 - - start = first_sunday_on_or_after(dststart.replace(year=year)) - end = first_sunday_on_or_after(dstend.replace(year=year)) - return start, end - - class USTimeZone(tzinfo): def __init__(self, hours, reprname, stdname, dstname): @@ -135,39 +141,27 @@ class USTimeZone(tzinfo): # implementation) passes a datetime with dt.tzinfo is self. return ZERO assert dt.tzinfo is self - start, end = us_dst_range(dt.year) + + # Find start and end times for US DST. For years before 1967, return + # ZERO for no DST. + if 2006 < dt.year: + dststart, dstend = DSTSTART_2007, DSTEND_2007 + elif 1986 < dt.year < 2007: + dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006 + elif 1966 < dt.year < 1987: + dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986 + else: + return ZERO + + start = first_sunday_on_or_after(dststart.replace(year=dt.year)) + end = first_sunday_on_or_after(dstend.replace(year=dt.year)) + # Can't compare naive to aware objects, so strip the timezone from # dt first. - dt = dt.replace(tzinfo=None) - if start + HOUR <= dt < end - HOUR: - # DST is in effect. + if start <= dt.replace(tzinfo=None) < end: return HOUR - if end - HOUR <= dt < end: - # Fold (an ambiguous hour): use dt.fold to disambiguate. - return ZERO if dt.fold else HOUR - if start <= dt < start + HOUR: - # Gap (a non-existent hour): reverse the fold rule. - return HOUR if dt.fold else ZERO - # DST is off. - return ZERO - - def fromutc(self, dt): - assert dt.tzinfo is self - start, end = us_dst_range(dt.year) - start = start.replace(tzinfo=self) - end = end.replace(tzinfo=self) - std_time = dt + self.stdoffset - dst_time = std_time + HOUR - if end <= dst_time < end + HOUR: - # Repeated hour - return std_time.replace(fold=1) - if std_time < start or dst_time >= end: - # Standard time - return std_time - if start <= std_time < end - HOUR: - # Daylight saving time - return dst_time - + else: + return ZERO Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") Central = USTimeZone(-6, "Central", "CST", "CDT") |