summaryrefslogtreecommitdiffstats
path: root/Doc/includes
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2007-08-15 14:28:22 (GMT)
committerGeorg Brandl <georg@python.org>2007-08-15 14:28:22 (GMT)
commit116aa62bf54a39697e25f21d6cf6799f7faa1349 (patch)
tree8db5729518ed4ca88e26f1e26cc8695151ca3eb3 /Doc/includes
parent739c01d47b9118d04e5722333f0e6b4d0c8bdd9e (diff)
downloadcpython-116aa62bf54a39697e25f21d6cf6799f7faa1349.zip
cpython-116aa62bf54a39697e25f21d6cf6799f7faa1349.tar.gz
cpython-116aa62bf54a39697e25f21d6cf6799f7faa1349.tar.bz2
Move the 3k reST doc tree in place.
Diffstat (limited to 'Doc/includes')
-rw-r--r--Doc/includes/email-dir.py115
-rw-r--r--Doc/includes/email-mime.py32
-rw-r--r--Doc/includes/email-simple.py25
-rw-r--r--Doc/includes/email-unpack.py68
-rw-r--r--Doc/includes/minidom-example.py64
-rw-r--r--Doc/includes/noddy.c54
-rw-r--r--Doc/includes/noddy2.c190
-rw-r--r--Doc/includes/noddy3.c243
-rw-r--r--Doc/includes/noddy4.c224
-rw-r--r--Doc/includes/run-func.c68
-rw-r--r--Doc/includes/setup.py8
-rw-r--r--Doc/includes/shoddy.c91
-rw-r--r--Doc/includes/sqlite3/adapter_datetime.py14
-rw-r--r--Doc/includes/sqlite3/adapter_point_1.py16
-rw-r--r--Doc/includes/sqlite3/adapter_point_2.py17
-rw-r--r--Doc/includes/sqlite3/collation_reverse.py15
-rw-r--r--Doc/includes/sqlite3/complete_statement.py30
-rw-r--r--Doc/includes/sqlite3/connect_db_1.py3
-rw-r--r--Doc/includes/sqlite3/connect_db_2.py3
-rw-r--r--Doc/includes/sqlite3/converter_point.py47
-rw-r--r--Doc/includes/sqlite3/countcursors.py15
-rw-r--r--Doc/includes/sqlite3/createdb.py28
-rw-r--r--Doc/includes/sqlite3/execsql_fetchonerow.py17
-rw-r--r--Doc/includes/sqlite3/execsql_printall_1.py13
-rw-r--r--Doc/includes/sqlite3/execute_1.py11
-rw-r--r--Doc/includes/sqlite3/execute_2.py12
-rw-r--r--Doc/includes/sqlite3/execute_3.py12
-rw-r--r--Doc/includes/sqlite3/executemany_1.py24
-rw-r--r--Doc/includes/sqlite3/executemany_2.py15
-rw-r--r--Doc/includes/sqlite3/executescript.py24
-rw-r--r--Doc/includes/sqlite3/insert_more_people.py16
-rw-r--r--Doc/includes/sqlite3/md5func.py11
-rw-r--r--Doc/includes/sqlite3/mysumaggr.py20
-rw-r--r--Doc/includes/sqlite3/parse_colnames.py8
-rw-r--r--Doc/includes/sqlite3/pysqlite_datetime.py20
-rw-r--r--Doc/includes/sqlite3/row_factory.py13
-rw-r--r--Doc/includes/sqlite3/rowclass.py12
-rw-r--r--Doc/includes/sqlite3/shared_cache.py6
-rw-r--r--Doc/includes/sqlite3/shortcut_methods.py21
-rw-r--r--Doc/includes/sqlite3/simple_tableprinter.py26
-rw-r--r--Doc/includes/sqlite3/text_factory.py42
-rw-r--r--Doc/includes/test.py213
-rw-r--r--Doc/includes/typestruct.h76
-rw-r--r--Doc/includes/tzinfo-examples.py139
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")