diff options
Diffstat (limited to 'Doc/includes')
44 files changed, 2121 insertions, 0 deletions
diff --git a/Doc/includes/email-dir.py b/Doc/includes/email-dir.py new file mode 100644 index 0000000..c04f57d --- /dev/null +++ b/Doc/includes/email-dir.py @@ -0,0 +1,115 @@ +#!/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 optparse import OptionParser + +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 = 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_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 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) + if not os.path.isfile(path): + continue + # Guess the content type based on the file's extension. Encoding + # will be ignored, although we should check for simple things like + # gzip'd or compressed files. + ctype, encoding = mimetypes.guess_type(path) + if ctype is None or encoding is not None: + # No guess could be made, or the file is encoded (compressed), so + # use a generic bag-of-bits type. + ctype = 'application/octet-stream' + maintype, subtype = ctype.split('/', 1) + 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 + composed = outer.as_string() + if opts.output: + fp = open(opts.output, 'w') + fp.write(composed) + fp.close() + else: + s = smtplib.SMTP() + s.connect() + s.sendmail(opts.sender, opts.recipients, composed) + s.close() + + +if __name__ == '__main__': + main() diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py new file mode 100644 index 0000000..5097253 --- /dev/null +++ b/Doc/includes/email-mime.py @@ -0,0 +1,32 @@ +# Import smtplib for the actual sending function +import smtplib + +# Here are the email package modules we'll need +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart + +COMMASPACE = ', ' + +# 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'] = COMMASPACE.join(family) +msg.preamble = 'Our family reunion' + +# Assume we know that the image files are all in PNG format +for file in pngfiles: + # 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. +s = smtplib.SMTP() +s.connect() +s.sendmail(me, family, msg.as_string()) +s.close() diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py new file mode 100644 index 0000000..44152a4 --- /dev/null +++ b/Doc/includes/email-simple.py @@ -0,0 +1,25 @@ +# Import smtplib for the actual sending function +import smtplib + +# Import the email modules we'll need +from email.mime.text import MIMEText + +# 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'] = 'The contents of %s' % textfile +msg['From'] = me +msg['To'] = you + +# Send the message via our own SMTP server, but don't include the +# envelope header. +s = smtplib.SMTP() +s.connect() +s.sendmail(me, [you], msg.as_string()) +s.close() diff --git a/Doc/includes/email-unpack.py b/Doc/includes/email-unpack.py new file mode 100644 index 0000000..e596b98 --- /dev/null +++ b/Doc/includes/email-unpack.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +"""Unpack a MIME message into a directory of files.""" + +import os +import sys +import email +import errno +import mimetypes + +from optparse import OptionParser + + +def main(): + parser = OptionParser(usage="""\ +Unpack a MIME message into a directory of files. + +Usage: %prog [options] msgfile +""") + 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) + + try: + msgfile = args[0] + except IndexError: + parser.print_help() + sys.exit(1) + + try: + 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(): + # multipart/* are just containers + if part.get_content_maintype() == 'multipart': + continue + # Applications should really sanitize the given filename so that an + # email message can't be used to overwrite important files + filename = part.get_filename() + if not filename: + ext = mimetypes.guess_extension(part.get_type()) + if not ext: + # Use a generic bag-of-bits extension + ext = '.bin' + filename = 'part-%03d%s' % (counter, ext) + counter += 1 + fp = open(os.path.join(opts.directory, filename), 'wb') + fp.write(part.get_payload(decode=True)) + fp.close() + + +if __name__ == '__main__': + main() diff --git a/Doc/includes/minidom-example.py b/Doc/includes/minidom-example.py new file mode 100644 index 0000000..c30c4e0 --- /dev/null +++ b/Doc/includes/minidom-example.py @@ -0,0 +1,64 @@ +import xml.dom.minidom + +document = """\ +<slideshow> +<title>Demo slideshow</title> +<slide><title>Slide title</title> +<point>This is a demo</point> +<point>Of a program for processing slides</point> +</slide> + +<slide><title>Another demo slide</title> +<point>It is important</point> +<point>To have more than</point> +<point>one slide</point> +</slide> +</slideshow> +""" + +dom = xml.dom.minidom.parseString(document) + +def getText(nodelist): + rc = "" + for node in nodelist: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc + +def handleSlideshow(slideshow): + print "<html>" + handleSlideshowTitle(slideshow.getElementsByTagName("title")[0]) + slides = slideshow.getElementsByTagName("slide") + handleToc(slides) + handleSlides(slides) + print "</html>" + +def handleSlides(slides): + for slide in slides: + handleSlide(slide) + +def handleSlide(slide): + handleSlideTitle(slide.getElementsByTagName("title")[0]) + handlePoints(slide.getElementsByTagName("point")) + +def handleSlideshowTitle(title): + print "<title>%s</title>" % getText(title.childNodes) + +def handleSlideTitle(title): + print "<h2>%s</h2>" % getText(title.childNodes) + +def handlePoints(points): + print "<ul>" + for point in points: + handlePoint(point) + print "</ul>" + +def handlePoint(point): + 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) + +handleSlideshow(dom) diff --git a/Doc/includes/noddy.c b/Doc/includes/noddy.c new file mode 100644 index 0000000..ec2d669 --- /dev/null +++ b/Doc/includes/noddy.c @@ -0,0 +1,54 @@ +#include <Python.h> + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ +} noddy_NoddyObject; + +static PyTypeObject noddy_NoddyType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "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..2caf985 --- /dev/null +++ b/Doc/includes/noddy2.c @@ -0,0 +1,190 @@ +#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); + self->ob_type->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 = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "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..60260ad --- /dev/null +++ b/Doc/includes/noddy3.c @@ -0,0 +1,243 @@ +#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); + self->ob_type->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 = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "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..878e086 --- /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) +{ + Noddy_clear(self); + self->ob_type->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 = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "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 new file mode 100644 index 0000000..5a7df0d --- /dev/null +++ b/Doc/includes/run-func.c @@ -0,0 +1,68 @@ +#include <Python.h> + +int +main(int argc, char *argv[]) +{ + PyObject *pName, *pModule, *pDict, *pFunc; + PyObject *pArgs, *pValue; + int i; + + if (argc < 3) { + fprintf(stderr,"Usage: call pythonfile funcname [args]\n"); + return 1; + } + + Py_Initialize(); + pName = PyString_FromString(argv[1]); + /* Error checking of pName left out */ + + pModule = PyImport_Import(pName); + Py_DECREF(pName); + + if (pModule != NULL) { + pFunc = PyObject_GetAttrString(pModule, argv[2]); + /* pFunc is a new reference */ + + if (pFunc && PyCallable_Check(pFunc)) { + pArgs = PyTuple_New(argc - 3); + for (i = 0; i < argc - 3; ++i) { + pValue = PyInt_FromLong(atoi(argv[i + 3])); + if (!pValue) { + Py_DECREF(pArgs); + Py_DECREF(pModule); + fprintf(stderr, "Cannot convert argument\n"); + return 1; + } + /* pValue reference stolen here: */ + PyTuple_SetItem(pArgs, i, pValue); + } + pValue = PyObject_CallObject(pFunc, pArgs); + Py_DECREF(pArgs); + if (pValue != NULL) { + printf("Result of call: %ld\n", PyInt_AsLong(pValue)); + Py_DECREF(pValue); + } + else { + Py_DECREF(pFunc); + Py_DECREF(pModule); + PyErr_Print(); + fprintf(stderr,"Call failed\n"); + return 1; + } + } + else { + if (PyErr_Occurred()) + PyErr_Print(); + fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]); + } + Py_XDECREF(pFunc); + Py_DECREF(pModule); + } + else { + PyErr_Print(); + fprintf(stderr, "Failed to load \"%s\"\n", argv[1]); + return 1; + } + Py_Finalize(); + return 0; +} diff --git a/Doc/includes/setup.py b/Doc/includes/setup.py new file mode 100644 index 0000000..b853d23 --- /dev/null +++ b/Doc/includes/setup.py @@ -0,0 +1,8 @@ +from distutils.core import setup, Extension +setup(name="noddy", version="1.0", + ext_modules=[ + Extension("noddy", ["noddy.c"]), + Extension("noddy2", ["noddy2.c"]), + Extension("noddy3", ["noddy3.c"]), + Extension("noddy4", ["noddy4.c"]), + ]) diff --git a/Doc/includes/shoddy.c b/Doc/includes/shoddy.c new file mode 100644 index 0000000..07a4177 --- /dev/null +++ b/Doc/includes/shoddy.c @@ -0,0 +1,91 @@ +#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 = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "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 new file mode 100644 index 0000000..5869e22 --- /dev/null +++ b/Doc/includes/sqlite3/adapter_datetime.py @@ -0,0 +1,14 @@ +import sqlite3 +import datetime, time + +def adapt_datetime(ts): + return time.mktime(ts.timetuple()) + +sqlite3.register_adapter(datetime.datetime, adapt_datetime) + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +now = datetime.datetime.now() +cur.execute("select ?", (now,)) +print(cur.fetchone()[0]) diff --git a/Doc/includes/sqlite3/adapter_point_1.py b/Doc/includes/sqlite3/adapter_point_1.py new file mode 100644 index 0000000..1343acd --- /dev/null +++ b/Doc/includes/sqlite3/adapter_point_1.py @@ -0,0 +1,16 @@ +import sqlite3 + +class Point(object): + def __init__(self, x, y): + self.x, self.y = x, y + + def __conform__(self, protocol): + if protocol is sqlite3.PrepareProtocol: + return "%f;%f" % (self.x, self.y) + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +p = Point(4.0, -3.2) +cur.execute("select ?", (p,)) +print(cur.fetchone()[0]) diff --git a/Doc/includes/sqlite3/adapter_point_2.py b/Doc/includes/sqlite3/adapter_point_2.py new file mode 100644 index 0000000..1e1719a --- /dev/null +++ b/Doc/includes/sqlite3/adapter_point_2.py @@ -0,0 +1,17 @@ +import sqlite3 + +class Point(object): + def __init__(self, x, y): + self.x, self.y = x, y + +def adapt_point(point): + return "%f;%f" % (point.x, point.y) + +sqlite3.register_adapter(Point, adapt_point) + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +p = Point(4.0, -3.2) +cur.execute("select ?", (p,)) +print(cur.fetchone()[0]) diff --git a/Doc/includes/sqlite3/collation_reverse.py b/Doc/includes/sqlite3/collation_reverse.py new file mode 100644 index 0000000..bfd7f5b --- /dev/null +++ b/Doc/includes/sqlite3/collation_reverse.py @@ -0,0 +1,15 @@ +import sqlite3 + +def collate_reverse(string1, string2): + return -cmp(string1, string2) + +con = sqlite3.connect(":memory:") +con.create_collation("reverse", collate_reverse) + +cur = con.cursor() +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) +con.close() diff --git a/Doc/includes/sqlite3/complete_statement.py b/Doc/includes/sqlite3/complete_statement.py new file mode 100644 index 0000000..cd38d73 --- /dev/null +++ b/Doc/includes/sqlite3/complete_statement.py @@ -0,0 +1,30 @@ +# A minimal SQLite shell for experiments + +import sqlite3 + +con = sqlite3.connect(":memory:") +con.isolation_level = None +cur = con.cursor() + +buffer = "" + +print("Enter your SQL commands to execute in sqlite3.") +print("Enter a blank line to exit.") + +while True: + line = input() + if line == "": + break + buffer += line + if sqlite3.complete_statement(buffer): + try: + buffer = buffer.strip() + cur.execute(buffer) + + if buffer.lstrip().upper().startswith("SELECT"): + print(cur.fetchall()) + except sqlite3.Error as e: + 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 new file mode 100644 index 0000000..d0707ab --- /dev/null +++ b/Doc/includes/sqlite3/converter_point.py @@ -0,0 +1,47 @@ +import sqlite3 + +class Point(object): + def __init__(self, x, y): + self.x, self.y = x, y + + def __repr__(self): + return "(%f;%f)" % (self.x, self.y) + +def adapt_point(point): + return "%f;%f" % (point.x, point.y) + +def convert_point(s): + x, y = list(map(float, s.split(";"))) + return Point(x, y) + +# Register the adapter +sqlite3.register_adapter(Point, adapt_point) + +# Register the converter +sqlite3.register_converter("point", convert_point) + +p = Point(4.0, -3.2) + +######################### +# 1) Using declared types +con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES) +cur = con.cursor() +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]) +cur.close() +con.close() + +####################### +# 1) Using column names +con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES) +cur = con.cursor() +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]) +cur.close() +con.close() diff --git a/Doc/includes/sqlite3/countcursors.py b/Doc/includes/sqlite3/countcursors.py new file mode 100644 index 0000000..ef3e70a --- /dev/null +++ b/Doc/includes/sqlite3/countcursors.py @@ -0,0 +1,15 @@ +import sqlite3 + +class CountCursorsConnection(sqlite3.Connection): + def __init__(self, *args, **kwargs): + sqlite3.Connection.__init__(self, *args, **kwargs) + self.numcursors = 0 + + def cursor(self, *args, **kwargs): + self.numcursors += 1 + return sqlite3.Connection.cursor(self, *args, **kwargs) + +con = sqlite3.connect(":memory:", factory=CountCursorsConnection) +cur1 = con.cursor() +cur2 = con.cursor() +print(con.numcursors) diff --git a/Doc/includes/sqlite3/createdb.py b/Doc/includes/sqlite3/createdb.py new file mode 100644 index 0000000..ee2950b --- /dev/null +++ b/Doc/includes/sqlite3/createdb.py @@ -0,0 +1,28 @@ +# Not referenced from the documentation, but builds the database file the other +# code snippets expect. + +import sqlite3 +import os + +DB_FILE = "mydb" + +if os.path.exists(DB_FILE): + os.remove(DB_FILE) + +con = sqlite3.connect(DB_FILE) +cur = con.cursor() +cur.execute(""" + create table people + ( + name_last varchar(20), + age integer + ) + """) + +cur.execute("insert into people (name_last, age) values ('Yeltsin', 72)") +cur.execute("insert into people (name_last, age) values ('Putin', 51)") + +con.commit() + +cur.close() +con.close() diff --git a/Doc/includes/sqlite3/execsql_fetchonerow.py b/Doc/includes/sqlite3/execsql_fetchonerow.py new file mode 100644 index 0000000..078873b --- /dev/null +++ b/Doc/includes/sqlite3/execsql_fetchonerow.py @@ -0,0 +1,17 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() +SELECT = "select name_last, age from people order by age, name_last" + +# 1. Iterate over the rows available from the cursor, unpacking the +# 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)) + +# 2. Equivalently: +cur.execute(SELECT) +for row in cur: + 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 new file mode 100644 index 0000000..a4ce5c5 --- /dev/null +++ b/Doc/includes/sqlite3/execsql_printall_1.py @@ -0,0 +1,13 @@ +import sqlite3 + +# Create a connection to the database file "mydb": +con = sqlite3.connect("mydb") + +# Get a Cursor object that operates in the context of Connection con: +cur = con.cursor() + +# Execute the SELECT statement: +cur.execute("select * from people order by age") + +# Retrieve all rows as a sequence and print that sequence: +print(cur.fetchall()) diff --git a/Doc/includes/sqlite3/execute_1.py b/Doc/includes/sqlite3/execute_1.py new file mode 100644 index 0000000..3d08840 --- /dev/null +++ b/Doc/includes/sqlite3/execute_1.py @@ -0,0 +1,11 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() + +who = "Yeltsin" +age = 72 + +cur.execute("select name_last, age from people where name_last=? and age=?", (who, age)) +print(cur.fetchone()) diff --git a/Doc/includes/sqlite3/execute_2.py b/Doc/includes/sqlite3/execute_2.py new file mode 100644 index 0000000..84734f9 --- /dev/null +++ b/Doc/includes/sqlite3/execute_2.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", + {"who": who, "age": age}) +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..0353683 --- /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 new file mode 100644 index 0000000..efae106 --- /dev/null +++ b/Doc/includes/sqlite3/executemany_1.py @@ -0,0 +1,24 @@ +import sqlite3 + +class IterChars: + def __init__(self): + self.count = ord('a') + + def __iter__(self): + return self + + def __next__(self): + if self.count > ord('z'): + raise StopIteration + self.count += 1 + return (chr(self.count - 1),) # this is a 1-tuple + +con = sqlite3.connect(":memory:") +cur = con.cursor() +cur.execute("create table characters(c)") + +theIter = IterChars() +cur.executemany("insert into characters(c) values (?)", theIter) + +cur.execute("select c from characters") +print(cur.fetchall()) diff --git a/Doc/includes/sqlite3/executemany_2.py b/Doc/includes/sqlite3/executemany_2.py new file mode 100644 index 0000000..518cd94 --- /dev/null +++ b/Doc/includes/sqlite3/executemany_2.py @@ -0,0 +1,15 @@ +import sqlite3 + +def char_generator(): + import string + for c in string.letters[:26]: + yield (c,) + +con = sqlite3.connect(":memory:") +cur = con.cursor() +cur.execute("create table characters(c)") + +cur.executemany("insert into characters(c) values (?)", char_generator()) + +cur.execute("select c from characters") +print(cur.fetchall()) diff --git a/Doc/includes/sqlite3/executescript.py b/Doc/includes/sqlite3/executescript.py new file mode 100644 index 0000000..7e53581 --- /dev/null +++ b/Doc/includes/sqlite3/executescript.py @@ -0,0 +1,24 @@ +import sqlite3 + +con = sqlite3.connect(":memory:") +cur = con.cursor() +cur.executescript(""" + create table person( + firstname, + lastname, + age + ); + + create table book( + title, + author, + published + ); + + insert into book(title, author, published) + values ( + 'Dirk Gently''s Holistic Detective Agency', + 'Douglas Adams', + 1987 + ); + """) diff --git a/Doc/includes/sqlite3/insert_more_people.py b/Doc/includes/sqlite3/insert_more_people.py new file mode 100644 index 0000000..edbc79e --- /dev/null +++ b/Doc/includes/sqlite3/insert_more_people.py @@ -0,0 +1,16 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() + +newPeople = ( + ('Lebed' , 53), + ('Zhirinovsky' , 57), + ) + +for person in newPeople: + cur.execute("insert into people (name_last, age) values (?, ?)", person) + +# The changes will not be saved unless the transaction is committed explicitly: +con.commit() diff --git a/Doc/includes/sqlite3/md5func.py b/Doc/includes/sqlite3/md5func.py new file mode 100644 index 0000000..b7bc05b --- /dev/null +++ b/Doc/includes/sqlite3/md5func.py @@ -0,0 +1,11 @@ +import sqlite3 +import hashlib + +def md5sum(t): + return hashlib.md5(t).hexdigest() + +con = sqlite3.connect(":memory:") +con.create_function("md5", 1, md5sum) +cur = con.cursor() +cur.execute("select md5(?)", ("foo",)) +print(cur.fetchone()[0]) diff --git a/Doc/includes/sqlite3/mysumaggr.py b/Doc/includes/sqlite3/mysumaggr.py new file mode 100644 index 0000000..d2dfd2c --- /dev/null +++ b/Doc/includes/sqlite3/mysumaggr.py @@ -0,0 +1,20 @@ +import sqlite3 + +class MySum: + def __init__(self): + self.count = 0 + + def step(self, value): + self.count += value + + def finalize(self): + return self.count + +con = sqlite3.connect(":memory:") +con.create_aggregate("mysum", 1, MySum) +cur = con.cursor() +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]) diff --git a/Doc/includes/sqlite3/parse_colnames.py b/Doc/includes/sqlite3/parse_colnames.py new file mode 100644 index 0000000..cc68c76 --- /dev/null +++ b/Doc/includes/sqlite3/parse_colnames.py @@ -0,0 +1,8 @@ +import sqlite3 +import datetime + +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)) diff --git a/Doc/includes/sqlite3/pysqlite_datetime.py b/Doc/includes/sqlite3/pysqlite_datetime.py new file mode 100644 index 0000000..68d4935 --- /dev/null +++ b/Doc/includes/sqlite3/pysqlite_datetime.py @@ -0,0 +1,20 @@ +import sqlite3 +import datetime + +con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES) +cur = con.cursor() +cur.execute("create table test(d date, ts timestamp)") + +today = datetime.date.today() +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])) + +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])) diff --git a/Doc/includes/sqlite3/row_factory.py b/Doc/includes/sqlite3/row_factory.py new file mode 100644 index 0000000..e436ffc --- /dev/null +++ b/Doc/includes/sqlite3/row_factory.py @@ -0,0 +1,13 @@ +import sqlite3 + +def dict_factory(cursor, row): + d = {} + for idx, col in enumerate(cursor.description): + d[col[0]] = row[idx] + return d + +con = sqlite3.connect(":memory:") +con.row_factory = dict_factory +cur = con.cursor() +cur.execute("select 1 as a") +print(cur.fetchone()["a"]) diff --git a/Doc/includes/sqlite3/rowclass.py b/Doc/includes/sqlite3/rowclass.py new file mode 100644 index 0000000..3fa0b87 --- /dev/null +++ b/Doc/includes/sqlite3/rowclass.py @@ -0,0 +1,12 @@ +import sqlite3 + +con = sqlite3.connect("mydb") +con.row_factory = sqlite3.Row + +cur = con.cursor() +cur.execute("select name_last, age from people") +for row in cur: + assert row[0] == row["name_last"] + assert row["name_last"] == row["nAmE_lAsT"] + assert row[1] == row["age"] + assert row[1] == row["AgE"] diff --git a/Doc/includes/sqlite3/shared_cache.py b/Doc/includes/sqlite3/shared_cache.py new file mode 100644 index 0000000..bf1d7b4 --- /dev/null +++ b/Doc/includes/sqlite3/shared_cache.py @@ -0,0 +1,6 @@ +import sqlite3 + +# The shared cache is only available in SQLite versions 3.3.3 or later +# See the SQLite documentaton for details. + +sqlite3.enable_shared_cache(True) diff --git a/Doc/includes/sqlite3/shortcut_methods.py b/Doc/includes/sqlite3/shortcut_methods.py new file mode 100644 index 0000000..596d87c --- /dev/null +++ b/Doc/includes/sqlite3/shortcut_methods.py @@ -0,0 +1,21 @@ +import sqlite3 + +persons = [ + ("Hugo", "Boss"), + ("Calvin", "Klein") + ] + +con = sqlite3.connect(":memory:") + +# Create the table +con.execute("create table person(firstname, lastname)") + +# Fill the table +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) + +# Using a dummy WHERE clause to not let SQLite take the shortcut table deletes. +print("I just deleted", con.execute("delete from person where 1=1").rowcount, "rows") diff --git a/Doc/includes/sqlite3/simple_tableprinter.py b/Doc/includes/sqlite3/simple_tableprinter.py new file mode 100644 index 0000000..231d872 --- /dev/null +++ b/Doc/includes/sqlite3/simple_tableprinter.py @@ -0,0 +1,26 @@ +import sqlite3 + +FIELD_MAX_WIDTH = 20 +TABLE_NAME = 'people' +SELECT = 'select * from %s order by age, name_last' % TABLE_NAME + +con = sqlite3.connect("mydb") + +cur = con.cursor() +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) + +# For each row, print the value of each field left-justified within +# the maximum possible width of that field. +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() # Finish the row with a newline. diff --git a/Doc/includes/sqlite3/text_factory.py b/Doc/includes/sqlite3/text_factory.py new file mode 100644 index 0000000..2dab8e4 --- /dev/null +++ b/Doc/includes/sqlite3/text_factory.py @@ -0,0 +1,42 @@ +import sqlite3 + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +# Create the table +con.execute("create table person(lastname, firstname)") + +AUSTRIA = "\xd6sterreich" + +# by default, rows are returned as Unicode +cur.execute("select ?", (AUSTRIA,)) +row = cur.fetchone() +assert row[0] == AUSTRIA + +# but we can make pysqlite always return bytestrings ... +con.text_factory = str +cur.execute("select ?", (AUSTRIA,)) +row = cur.fetchone() +assert type(row[0]) == 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 will ignore Unicode characters that cannot be +# decoded from UTF-8 +con.text_factory = lambda x: str(x, "utf-8", "ignore") +cur.execute("select ?", ("this is latin1 and would normally create errors" + "\xe4\xf6\xfc".encode("latin1"),)) +row = cur.fetchone() +assert type(row[0]) == str + +# pysqlite offers a builtin 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]) == str + +cur.execute("select ?", ("Germany",)) +row = cur.fetchone() +assert type(row[0]) == str diff --git a/Doc/includes/test.py b/Doc/includes/test.py new file mode 100644 index 0000000..7ebf46a --- /dev/null +++ b/Doc/includes/test.py @@ -0,0 +1,213 @@ +"""Test module for the noddy examples + +Noddy 1: + +>>> import noddy +>>> n1 = noddy.Noddy() +>>> n2 = noddy.Noddy() +>>> del n1 +>>> del n2 + + +Noddy 2 + +>>> import noddy2 +>>> n1 = noddy2.Noddy('jim', 'fulton', 42) +>>> n1.first +'jim' +>>> n1.last +'fulton' +>>> n1.number +42 +>>> n1.name() +'jim fulton' +>>> n1.first = 'will' +>>> n1.name() +'will fulton' +>>> n1.last = 'tell' +>>> n1.name() +'will tell' +>>> del n1.first +>>> n1.name() +Traceback (most recent call last): +... +AttributeError: first +>>> n1.first +Traceback (most recent call last): +... +AttributeError: first +>>> n1.first = 'drew' +>>> n1.first +'drew' +>>> del n1.number +Traceback (most recent call last): +... +TypeError: can't delete numeric/char attribute +>>> n1.number=2 +>>> n1.number +2 +>>> n1.first = 42 +>>> n1.name() +'42 tell' +>>> n2 = noddy2.Noddy() +>>> n2.name() +' ' +>>> n2.first +'' +>>> n2.last +'' +>>> del n2.first +>>> n2.first +Traceback (most recent call last): +... +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 = noddy2.Noddy('jim', 'fulton', 'waaa') +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: an integer is required +>>> del n1 +>>> del n2 + + +Noddy 3 + +>>> import noddy3 +>>> n1 = noddy3.Noddy('jim', 'fulton', 42) +>>> n1 = noddy3.Noddy('jim', 'fulton', 42) +>>> n1.name() +'jim fulton' +>>> del n1.first +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: Cannot delete the first attribute +>>> n1.first = 42 +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: The first attribute value must be a string +>>> n1.first = 'will' +>>> n1.name() +'will fulton' +>>> 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 +>>> del n1 +>>> del n2 + +Noddy 4 + +>>> import noddy4 +>>> n1 = noddy4.Noddy('jim', 'fulton', 42) +>>> n1.first +'jim' +>>> n1.last +'fulton' +>>> n1.number +42 +>>> n1.name() +'jim fulton' +>>> n1.first = 'will' +>>> n1.name() +'will fulton' +>>> n1.last = 'tell' +>>> n1.name() +'will tell' +>>> del n1.first +>>> n1.name() +Traceback (most recent call last): +... +AttributeError: first +>>> n1.first +Traceback (most recent call last): +... +AttributeError: first +>>> n1.first = 'drew' +>>> n1.first +'drew' +>>> del n1.number +Traceback (most recent call last): +... +TypeError: can't delete numeric/char attribute +>>> n1.number=2 +>>> n1.number +2 +>>> n1.first = 42 +>>> n1.name() +'42 tell' +>>> n2 = noddy4.Noddy() +>>> n2 = noddy4.Noddy() +>>> n2 = noddy4.Noddy() +>>> n2 = noddy4.Noddy() +>>> n2.name() +' ' +>>> n2.first +'' +>>> n2.last +'' +>>> del n2.first +>>> n2.first +Traceback (most recent call last): +... +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(?) + +>>> import gc +>>> gc.disable() + +>>> x = [] +>>> l = [x] +>>> n2.first = l +>>> n2.first +[[]] +>>> l.append(n2) +>>> del l +>>> del n1 +>>> del n2 +>>> sys.getrefcount(x) +3 +>>> ignore = gc.collect() +>>> sys.getrefcount(x) +2 + +>>> gc.enable() +""" + +import os +import sys +from distutils.util import get_platform +PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3]) +src = os.path.join("build", "lib.%s" % PLAT_SPEC) +sys.path.append(src) + +if __name__ == "__main__": + import doctest, __main__ + doctest.testmod(__main__) diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h new file mode 100644 index 0000000..0afe375 --- /dev/null +++ b/Doc/includes/typestruct.h @@ -0,0 +1,76 @@ +typedef struct _typeobject { + PyObject_VAR_HEAD + char *tp_name; /* For printing, in format "<module>.<name>" */ + int tp_basicsize, tp_itemsize; /* For allocation */ + + /* Methods to implement standard operations */ + + destructor tp_dealloc; + printfunc tp_print; + getattrfunc tp_getattr; + setattrfunc tp_setattr; + cmpfunc tp_compare; + reprfunc tp_repr; + + /* Method suites for standard classes */ + + PyNumberMethods *tp_as_number; + PySequenceMethods *tp_as_sequence; + PyMappingMethods *tp_as_mapping; + + /* More standard operations (here for binary compatibility) */ + + hashfunc tp_hash; + ternaryfunc tp_call; + reprfunc tp_str; + getattrofunc tp_getattro; + setattrofunc tp_setattro; + + /* Functions to access object as input/output buffer */ + PyBufferProcs *tp_as_buffer; + + /* Flags to define presence of optional/expanded features */ + long tp_flags; + + 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 */ + long tp_weaklistoffset; + + /* Added in release 2.2 */ + /* Iterators */ + getiterfunc tp_iter; + iternextfunc tp_iternext; + + /* Attribute descriptor and subclassing stuff */ + struct PyMethodDef *tp_methods; + struct PyMemberDef *tp_members; + struct PyGetSetDef *tp_getset; + struct _typeobject *tp_base; + PyObject *tp_dict; + descrgetfunc tp_descr_get; + descrsetfunc tp_descr_set; + long tp_dictoffset; + initproc tp_init; + allocfunc tp_alloc; + newfunc tp_new; + freefunc tp_free; /* Low-level free-memory routine */ + inquiry tp_is_gc; /* For PyObject_IS_GC */ + PyObject *tp_bases; + PyObject *tp_mro; /* method resolution order */ + PyObject *tp_cache; + PyObject *tp_subclasses; + PyObject *tp_weaklist; + +} PyTypeObject; diff --git a/Doc/includes/tzinfo-examples.py b/Doc/includes/tzinfo-examples.py new file mode 100644 index 0000000..5a2b8ad --- /dev/null +++ b/Doc/includes/tzinfo-examples.py @@ -0,0 +1,139 @@ +from datetime import tzinfo, timedelta, datetime + +ZERO = timedelta(0) +HOUR = timedelta(hours=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. + +import time as _time + +STDOFFSET = timedelta(seconds = -_time.timezone) +if _time.daylight: + DSTOFFSET = timedelta(seconds = -_time.altzone) +else: + DSTOFFSET = STDOFFSET + +DSTDIFF = DSTOFFSET - STDOFFSET + +class LocalTimezone(tzinfo): + + def utcoffset(self, dt): + if self._isdst(dt): + return DSTOFFSET + else: + return STDOFFSET + + def dst(self, dt): + if self._isdst(dt): + return DSTDIFF + else: + return ZERO + + def tzname(self, dt): + return _time.tzname[self._isdst(dt)] + + def _isdst(self, dt): + tt = (dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.weekday(), 0, -1) + stamp = _time.mktime(tt) + tt = _time.localtime(stamp) + return tt.tm_isdst > 0 + +Local = LocalTimezone() + + +# A complete implementation of current DST rules for major US time zones. + +def first_sunday_on_or_after(dt): + days_to_go = 6 - dt.weekday() + if days_to_go: + dt += timedelta(days_to_go) + return dt + +# In the US, DST starts at 2am (standard time) on the first Sunday in April. +DSTSTART = datetime(1, 4, 1, 2) +# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. +# which is the first Sunday on or after Oct 25. +DSTEND = datetime(1, 10, 25, 1) + +class USTimeZone(tzinfo): + + def __init__(self, hours, reprname, stdname, dstname): + self.stdoffset = timedelta(hours=hours) + self.reprname = reprname + self.stdname = stdname + self.dstname = dstname + + def __repr__(self): + return self.reprname + + def tzname(self, dt): + if self.dst(dt): + return self.dstname + else: + return self.stdname + + def utcoffset(self, dt): + return self.stdoffset + self.dst(dt) + + def dst(self, dt): + if dt is None or dt.tzinfo is None: + # An exception may be sensible here, in one or both cases. + # It depends on how you want to treat them. The default + # fromutc() implementation (called by the default astimezone() + # implementation) passes a datetime with dt.tzinfo is self. + return ZERO + assert dt.tzinfo is self + + # Find first Sunday in April & the last in October. + 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. + if start <= dt.replace(tzinfo=None) < end: + return HOUR + else: + return ZERO + +Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") +Central = USTimeZone(-6, "Central", "CST", "CDT") +Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") +Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") |