Commit d1c51592 authored by Benjamin Peterson's avatar Benjamin Peterson

merge 3.3

parents 6b37eb5a ffc4d425

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

......@@ -15,11 +15,13 @@ Doc/tools/jinja2/
Doc/tools/pygments/
Doc/tools/sphinx/
Lib/lib2to3/*.pickle
Lib/test/data/*
Lib/_sysconfigdata.py
Lib/plat-mac/errors.rsrc.df.rsrc
Makefile
Makefile.pre
Misc/python.pc
Misc/python-config.sh
Modules/Setup
Modules/Setup.config
Modules/Setup.local
......@@ -57,6 +59,8 @@ platform
pybuilddir.txt
pyconfig.h
python
python-config
python-config.py
python.exe
python-gdb.py
python.exe-gdb.py
......
......@@ -26,6 +26,7 @@
**.psd = BIN
**.tar = BIN
**.wav = BIN
**.whl = BIN
**.xar = BIN
**.zip = BIN
......
......@@ -19,21 +19,20 @@ platform$
pyconfig.h$
python$
python.exe$
python-config$
python-config.py$
reflog.txt$
tags$
Lib/plat-mac/errors.rsrc.df.rsrc
Doc/tools/sphinx/
Doc/tools/docutils/
Doc/tools/jinja/
Doc/tools/jinja2/
Doc/tools/pygments/
Misc/python.pc
Misc/python-config.sh$
Modules/Setup$
Modules/Setup.config
Modules/Setup.local
Modules/config.c
Modules/ld_so_aix$
Parser/pgen$
^lcov-report/
^core
^python-gdb.py
^python.exe-gdb.py
......@@ -81,7 +80,12 @@ PCbuild/*.suo
PCbuild/*.*sdf
PCbuild/Win32-temp-*
PCbuild/x64-temp-*
PCbuild/*-pgi
PCbuild/*-pgo
PCbuild/amd64
PCbuild/ipch
Tools/unicode/build/
Tools/unicode/MAPPINGS/
BuildLog.htm
__pycache__
Modules/_freeze_importlib
......@@ -89,3 +93,7 @@ Modules/_testembed
.coverage
coverage/
htmlcov/
*.gcda
*.gcno
*.gcov
coverage.info
......@@ -4,8 +4,7 @@
Python/importlib.h: Lib/importlib/_bootstrap.py Modules/_freeze_importlib.c
Include/ast.h: Parser/Python.asdl Parser/asdl.py Parser/asdl_c.py
Include/Python-ast.h: Include/ast.h
Include/Python-ast.h: Parser/Python.asdl Parser/asdl.py Parser/asdl_c.py
Python/Python-ast.c: Include/Python-ast.h
Python/opcode_targets.h: Python/makeopcodetargets.py Lib/opcode.py
......
......@@ -5,7 +5,7 @@
# You can set these variables from the command line.
PYTHON = python
SVNROOT = http://svn.python.org/projects
SPHINXBUILD = sphinx-build
SPHINXOPTS =
PAPER =
SOURCES =
......@@ -14,14 +14,13 @@ DISTVERSION = $(shell $(PYTHON) tools/sphinxext/patchlevel.py)
ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees -D latex_paper_size=$(PAPER) \
$(SPHINXOPTS) . build/$(BUILDER) $(SOURCES)
.PHONY: help checkout update build html htmlhelp latex text changes linkcheck \
.PHONY: help build html htmlhelp latex text changes linkcheck \
suspicious coverage doctest pydoc-topics htmlview clean dist check serve \
autobuild-dev autobuild-stable
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " clean to remove build files"
@echo " update to update build tools"
@echo " html to make standalone HTML files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
......@@ -37,30 +36,8 @@ help:
@echo " check to run a check for frequent markup errors"
@echo " serve to serve the documentation on the localhost (8000)"
# Note: if you update versions here, do the same in make.bat and README.txt
checkout:
@if [ ! -d tools/sphinx ]; then \
echo "Checking out Sphinx..."; \
svn checkout $(SVNROOT)/external/Sphinx-1.2/sphinx tools/sphinx; \
fi
@if [ ! -d tools/docutils ]; then \
echo "Checking out Docutils..."; \
svn checkout $(SVNROOT)/external/docutils-0.11/docutils tools/docutils; \
fi
@if [ ! -d tools/jinja2 ]; then \
echo "Checking out Jinja..."; \
svn checkout $(SVNROOT)/external/Jinja-2.3.1/jinja2 tools/jinja2; \
fi
@if [ ! -d tools/pygments ]; then \
echo "Checking out Pygments..."; \
svn checkout $(SVNROOT)/external/Pygments-1.6/pygments tools/pygments; \
fi
update: clean checkout
build: checkout
mkdir -p build/$(BUILDER) build/doctrees
$(PYTHON) tools/sphinx-build.py $(ALLSPHINXOPTS)
build:
$(SPHINXBUILD) $(ALLSPHINXOPTS)
@echo
html: BUILDER = html
......@@ -120,10 +97,6 @@ htmlview: html
clean:
-rm -rf build/*
-rm -rf tools/sphinx
-rm -rf tools/pygments
-rm -rf tools/jinja2
-rm -rf tools/docutils
dist:
rm -rf dist
......@@ -163,16 +136,10 @@ dist:
cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-letter.zip
cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-letter.tar.bz2
# archive the epub build
# copy the epub build
rm -rf build/epub
make epub
mkdir -p dist/python-$(DISTVERSION)-docs-epub
cp -pPR build/epub/*.epub dist/python-$(DISTVERSION)-docs-epub/
tar -C dist -cf dist/python-$(DISTVERSION)-docs-epub.tar python-$(DISTVERSION)-docs-epub
bzip2 -9 -k dist/python-$(DISTVERSION)-docs-epub.tar
(cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-epub.zip python-$(DISTVERSION)-docs-epub)
rm -r dist/python-$(DISTVERSION)-docs-epub
rm dist/python-$(DISTVERSION)-docs-epub.tar
cp -pPR build/epub/Python.epub dist/python-$(DISTVERSION)-docs.epub
check:
$(PYTHON) tools/rstlint.py -i tools
......@@ -184,7 +151,6 @@ serve:
# for development releases: always build
autobuild-dev:
make update
make dist SPHINXOPTS='-A daily=1 -A versionswitcher=1'
-make suspicious
......
......@@ -3,34 +3,31 @@ Python Documentation README
This directory contains the reStructuredText (reST) sources to the Python
documentation. You don't need to build them yourself, prebuilt versions are
available at http://docs.python.org/download/.
available at <http://docs.python.org/download/>.
Documentation on the authoring Python documentation, including information about
both style and markup, is available in the "Documenting Python" chapter of the
documentation.
developers guide <http://docs.python.org/devguide/documenting.html>.
Building the docs
=================
You need to have Python 2 installed; the toolset used to build the
docs is written in Python. It is called *Sphinx*, it is not included in this
tree, but maintained separately. Also needed are the docutils, supplying the
base markup that Sphinx uses, Jinja, a templating engine, and optionally
Pygments, a code highlighter.
You need to have Sphinx <http://sphinx-doc.org/> installed; it is the toolset
used to build the docs. It is not included in this tree, but maintained
separately and available from PyPI <http://pypi.python.org/pypi/Sphinx>.
Using make
----------
Luckily, a Makefile has been prepared so that on Unix, provided you have
installed Python and Subversion, you can just run ::
A Makefile has been prepared so that on Unix, provided you have installed
Sphinx, you can just run ::
make html
to check out the necessary toolset in the `tools/` subdirectory and build the
HTML output files. To view the generated HTML, point your favorite browser at
the top-level index `build/html/index.html` after running "make".
to build the HTML output files. To view the generated HTML, point your favorite
browser at the top-level index `build/html/index.html` after running "make".
On Windows, we try to emulate the Makefile as closely as possible with a
``make.bat`` file.
......@@ -78,8 +75,6 @@ Available make targets are:
* "suspicious", which checks the parsed markup for text that looks like
malformed and thus unconverted reST.
A "make update" updates the Subversion checkouts in `tools/`.
Without make
------------
......
......@@ -295,6 +295,8 @@ Other objects
the object pointer is stored. If the Python object does not have the required
type, :exc:`TypeError` is raised.
.. _o_ampersand:
``O&`` (object) [*converter*, *anything*]
Convert a Python object to a C variable through a *converter* function. This
takes two arguments: the first is a function, the second is the address of a C
......
......@@ -74,26 +74,35 @@ intrinsic to the Python language.
.. _mapobjects:
Mapping Objects
===============
Container Objects
=================
.. index:: object: mapping
.. toctree::
dict.rst
set.rst
.. _otherobjects:
Other Objects
=============
Function Objects
================
.. toctree::
set.rst
function.rst
method.rst
cell.rst
code.rst
Other Objects
=============
.. toctree::
file.rst
module.rst
iterator.rst
......@@ -102,7 +111,6 @@ Other Objects
memoryview.rst
weakref.rst
capsule.rst
cell.rst
gen.rst
datetime.rst
code.rst
......@@ -84,7 +84,7 @@ Dictionary Objects
on failure.
.. c:function:: int PyDict_DelItemString(PyObject *p, char *key)
.. c:function:: int PyDict_DelItemString(PyObject *p, const char *key)
Remove the entry in dictionary *p* which has a key specified by the string
*key*. Return ``0`` on success or ``-1`` on failure.
......@@ -110,6 +110,15 @@ Dictionary Objects
:c:type:`char\*`, rather than a :c:type:`PyObject\*`.
.. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *default)
This is the same as the Python-level :meth:`dict.setdefault`. If present, it
returns the value corresponding to *key* from the dictionary *p*. If the key
is not in the dict, it is inserted with value *defaultobj* and *defaultobj*
is returned. This function evaluates the hash function of *key* only once,
instead of evaluating it independently for the lookup and the insertion.
.. c:function:: PyObject* PyDict_Items(PyObject *p)
Return a :c:type:`PyListObject` containing all the items from the dictionary.
......@@ -192,8 +201,11 @@ Dictionary Objects
.. c:function:: int PyDict_Update(PyObject *a, PyObject *b)
This is the same as ``PyDict_Merge(a, b, 1)`` in C, or ``a.update(b)`` in
Python. Return ``0`` on success or ``-1`` if an exception was raised.
This is the same as ``PyDict_Merge(a, b, 1)`` in C, and is similar to
``a.update(b)`` in Python except that :c:func:`PyDict_Update` doesn't fall
back to the iterating over a sequence of key value pairs if the second
argument has no "keys" attribute. Return ``0`` on success or ``-1`` if an
exception was raised.
.. c:function:: int PyDict_MergeFromSeq2(PyObject *a, PyObject *seq2, int override)
......
......@@ -90,6 +90,16 @@ in various ways. There is a separate error indicator for each thread.
the class in that case. If the values are already normalized, nothing happens.
The delayed normalization is implemented to improve performance.
.. note::
This function *does not* implicitly set the ``__traceback__``
attribute on the exception value. If setting the traceback
appropriately is desired, the following additional snippet is needed::
if (tb != NULL) {
PyException_SetTraceback(val, tb);
}
.. c:function:: void PyErr_Clear()
......@@ -231,11 +241,20 @@ in various ways. There is a separate error indicator for each thread.
exception instance.
.. c:function:: PyObject* PyErr_SetFromErrnoWithFilenameObjects(PyObject *type, PyObject *filenameObject, PyObject *filenameObject2)
Similar to :c:func:`PyErr_SetFromErrnoWithFilenameObject`, but takes a second
filename object, for raising errors when a function that takes two filenames
fails.
.. versionadded:: 3.4
.. c:function:: PyObject* PyErr_SetFromErrnoWithFilename(PyObject *type, const char *filename)
Similar to :c:func:`PyErr_SetFromErrnoWithFilenameObject`, but the filename
is given as a C string. *filename* is decoded from the filesystem encoding
(:func:`sys.getfilesystemencoding`).
(:func:`os.fsdecode`).
.. c:function:: PyObject* PyErr_SetFromWindowsErr(int ierr)
......@@ -256,18 +275,11 @@ in various ways. There is a separate error indicator for each thread.
specifying the exception type to be raised. Availability: Windows.
.. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilenameObject(int ierr, PyObject *filenameObject)
Similar to :c:func:`PyErr_SetFromWindowsErr`, with the additional behavior
that if *filenameObject* is not *NULL*, it is passed to the constructor of
:exc:`WindowsError` as a third parameter. Availability: Windows.
.. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilename(int ierr, const char *filename)
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, but the
filename is given as a C string. *filename* is decoded from the filesystem
encoding (:func:`sys.getfilesystemencoding`). Availability: Windows.
encoding (:func:`os.fsdecode`). Availability: Windows.
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObject(PyObject *type, int ierr, PyObject *filename)
......@@ -277,6 +289,15 @@ in various ways. There is a separate error indicator for each thread.
Availability: Windows.
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObjects(PyObject *type, int ierr, PyObject *filename, PyObject *filename2)
Similar to :c:func:`PyErr_SetExcFromWindowsErrWithFilenameObject`,
but accepts a second filename object.
Availability: Windows.
.. versionadded:: 3.4
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilename(PyObject *type, int ierr, const char *filename)
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilename`, with an additional
......@@ -293,13 +314,20 @@ in various ways. There is a separate error indicator for each thread.
.. versionadded:: 3.3
.. c:function:: void PyErr_SyntaxLocationEx(char *filename, int lineno, int col_offset)
.. c:function:: void PyErr_SyntaxLocationObject(PyObject *filename, int lineno, int col_offset)
Set file, line, and offset information for the current exception. If the
current exception is not a :exc:`SyntaxError`, then it sets additional
attributes, which make the exception printing subsystem think the exception
is a :exc:`SyntaxError`. *filename* is decoded from the filesystem encoding
(:func:`sys.getfilesystemencoding`).
is a :exc:`SyntaxError`.
.. versionadded:: 3.4
.. c:function:: void PyErr_SyntaxLocationEx(char *filename, int lineno, int col_offset)
Like :c:func:`PyErr_SyntaxLocationObject`, but *filename* is a byte string
decoded from the filesystem encoding (:func:`os.fsdecode`).
.. versionadded:: 3.2
......@@ -355,15 +383,22 @@ in various ways. There is a separate error indicator for each thread.
documentation. There is no C API for warning control.
.. c:function:: int PyErr_WarnExplicit(PyObject *category, const char *message, const char *filename, int lineno, const char *module, PyObject *registry)
.. c:function:: int PyErr_WarnExplicitObject(PyObject *category, PyObject *message, PyObject *filename, int lineno, PyObject *module, PyObject *registry)
Issue a warning message with explicit control over all warning attributes. This
is a straightforward wrapper around the Python function
:func:`warnings.warn_explicit`, see there for more information. The *module*
and *registry* arguments may be set to *NULL* to get the default effect
described there. *message* and *module* are UTF-8 encoded strings,
*filename* is decoded from the filesystem encoding
(:func:`sys.getfilesystemencoding`).
described there.
.. versionadded:: 3.4
.. c:function:: int PyErr_WarnExplicit(PyObject *category, const char *message, const char *filename, int lineno, const char *module, PyObject *registry)
Similar to :c:func:`PyErr_WarnExplicitObject` except that *message* and
*module* are UTF-8 encoded strings, and *filename* is decoded from the
filesystem encoding (:func:`os.fsdecode`).
.. c:function:: int PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, const char *format, ...)
......
......@@ -17,7 +17,7 @@ error reporting in the interpreter; third-party code is advised to access
the :mod:`io` APIs instead.
.. c:function:: PyFile_FromFd(int fd, char *name, char *mode, int buffering, char *encoding, char *errors, char *newline, int closefd)
.. c:function:: PyFile_FromFd(int fd, const char *name, const char *mode, int buffering, const char *encoding, const char *errors, const char *newline, int closefd)
Create a Python file object from the file descriptor of an already
opened file *fd*. The arguments *name*, *encoding*, *errors* and *newline*
......
......@@ -118,7 +118,7 @@ Importing Modules
encoded string instead of a Unicode object.
.. c:function:: PyObject* PyImport_ExecCodeModule(char *name, PyObject *co)
.. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co)
.. index:: builtin: compile
......@@ -145,7 +145,7 @@ Importing Modules
:c:func:`PyImport_ExecCodeModuleWithPathnames`.
.. c:function:: PyObject* PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname)
.. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname)
Like :c:func:`PyImport_ExecCodeModule`, but the :attr:`__file__` attribute of
the module object is set to *pathname* if it is non-``NULL``.
......@@ -162,7 +162,7 @@ Importing Modules
.. versionadded:: 3.3
.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(char *name, PyObject *co, char *pathname, char *cpathname)
.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname)
Like :c:func:`PyImport_ExecCodeModuleObject`, but *name*, *pathname* and
*cpathname* are UTF-8 encoded strings. Attempts are also made to figure out
......@@ -246,7 +246,7 @@ Importing Modules
.. versionadded:: 3.3
.. c:function:: int PyImport_ImportFrozenModule(char *name)
.. c:function:: int PyImport_ImportFrozenModule(const char *name)
Similar to :c:func:`PyImport_ImportFrozenModuleObject`, but the name is a
UTF-8 encoded string instead of a Unicode object.
......
......@@ -86,6 +86,36 @@ Process-wide parameters
=======================
.. c:function:: int Py_SetStandardStreamEncoding(char *encoding, char *errors)
.. index::
single: Py_Initialize()
single: main()
triple: stdin; stdout; sdterr
This function should be called before :c:func:`Py_Initialize`, if it is
called at all. It specifies which encoding and error handling to use
with standard IO, with the same meanings as in :func:`str.encode`.
It overrides :envvar:`PYTHONIOENCODING` values, and allows embedding code
to control IO encoding when the environment variable does not work.
``encoding`` and/or ``errors`` may be NULL to use
:envvar:`PYTHONIOENCODING` and/or default values (depending on other
settings).
Note that :data:`sys.stderr` always uses the "backslashreplace" error
handler, regardless of this (or any other) setting.
If :c:func:`Py_Finalize` is called, this function will need to be called
again in order to affect subsequent calls to :c:func:`Py_Initialize`.
Returns 0 if successful, a nonzero value on error (e.g. calling after the
interpreter has already been initialized).
.. versionadded:: 3.4
.. c:function:: void Py_SetProgramName(wchar_t *name)
.. index::
......@@ -329,7 +359,11 @@ Process-wide parameters
.. c:function:: void PySys_SetArgv(int argc, wchar_t **argv)
This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set to 1.
This function works like :c:func:`PySys_SetArgvEx` with *updatepath* set
to 1 unless the :program:`python` interpreter was started with the
:option:`-I`.
.. versionchanged:: 3.4 The *updatepath* value depends on :option:`-I`.
.. c:function:: void Py_SetPythonHome(wchar_t *home)
......@@ -658,6 +692,20 @@ with sub-interpreters:
made on the main thread. This is mainly a helper/diagnostic function.
.. c:function:: int PyGILState_Check()
Return 1 if the current thread is holding the GIL and 0 otherwise.
This function can be called from any thread at any time.
Only if it has had its Python thread state initialized and currently is
holding the GIL will it return 1.
This is mainly a helper/diagnostic function. It can be useful
for example in callback contexts or memory allocation functions when
knowing that the GIL is locked can allow the caller to perform sensitive
actions or otherwise behave differently.
.. versionadded:: 3.4
The following macros are normally used without a trailing semicolon; look for
example usage in the Python source distribution.
......
......@@ -80,7 +80,7 @@ All integers are implemented as "long" integer objects of arbitrary size.
*NULL* on failure.
.. c:function:: PyObject* PyLong_FromString(char *str, char **pend, int base)
.. c:function:: PyObject* PyLong_FromString(const char *str, char **pend, int base)
Return a new :c:type:`PyLongObject` based on the string value in *str*, which
is interpreted according to the radix in *base*. If *pend* is non-*NULL*,
......
......@@ -22,7 +22,7 @@ Mapping Protocol
expression ``len(o)``.
.. c:function:: int PyMapping_DelItemString(PyObject *o, char *key)
.. c:function:: int PyMapping_DelItemString(PyObject *o, const char *key)
Remove the mapping for object *key* from the object *o*. Return ``-1`` on
failure. This is equivalent to the Python statement ``del o[key]``.
......@@ -67,13 +67,13 @@ Mapping Protocol
the Python expression ``list(o.items())``.
.. c:function:: PyObject* PyMapping_GetItemString(PyObject *o, char *key)
.. c:function:: PyObject* PyMapping_GetItemString(PyObject *o, const char *key)
Return element of *o* corresponding to the object *key* or *NULL* on failure.
This is the equivalent of the Python expression ``o[key]``.
.. c:function:: int PyMapping_SetItemString(PyObject *o, char *key, PyObject *v)
.. c:function:: int PyMapping_SetItemString(PyObject *o, const char *key, PyObject *v)
Map the object *key* to the value *v* in object *o*. Returns ``-1`` on failure.
This is the equivalent of the Python statement ``o[key] = v``.
......@@ -84,6 +84,48 @@ the C library allocator as shown in the previous example, the allocated memory
for the I/O buffer escapes completely the Python memory manager.
Raw Memory Interface
====================
The following function sets are wrappers to the system allocator. These
functions are thread-safe, the :term:`GIL <global interpreter lock>` does not
need to be held.
The default raw memory block allocator uses the following functions:
:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when
requesting zero bytes.
.. versionadded:: 3.4
.. c:function:: void* PyMem_RawMalloc(size_t n)
Allocates *n* bytes and returns a pointer of type :c:type:`void\*` to the
allocated memory, or *NULL* if the request fails. Requesting zero bytes
returns a distinct non-*NULL* pointer if possible, as if
``PyMem_RawMalloc(1)`` had been called instead. The memory will not have
been initialized in any way.
.. c:function:: void* PyMem_RawRealloc(void *p, size_t n)
Resizes the memory block pointed to by *p* to *n* bytes. The contents will
be unchanged to the minimum of the old and the new sizes. If *p* is *NULL*,
the call is equivalent to ``PyMem_RawMalloc(n)``; else if *n* is equal to
zero, the memory block is resized but is not freed, and the returned pointer
is non-*NULL*. Unless *p* is *NULL*, it must have been returned by a
previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`. If
the request fails, :c:func:`PyMem_RawRealloc` returns *NULL* and *p* remains
a valid pointer to the previous memory area.
.. c:function:: void PyMem_RawFree(void *p)
Frees the memory block pointed to by *p*, which must have been returned by a
previous call to :c:func:`PyMem_RawMalloc` or :c:func:`PyMem_RawRealloc`.
Otherwise, or if ``PyMem_Free(p)`` has been called before, undefined
behavior occurs. If *p* is *NULL*, no operation is performed.
.. _memoryinterface:
Memory Interface
......@@ -91,8 +133,16 @@ Memory Interface
The following function sets, modeled after the ANSI C standard, but specifying
behavior when requesting zero bytes, are available for allocating and releasing
memory from the Python heap:
memory from the Python heap.
The default memory block allocator uses the following functions:
:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when
requesting zero bytes.
.. warning::
The :term:`GIL <global interpreter lock>` must be held when using these
functions.
.. c:function:: void* PyMem_Malloc(size_t n)
......@@ -155,6 +205,125 @@ versions and is therefore deprecated in extension modules.
:c:func:`PyMem_NEW`, :c:func:`PyMem_RESIZE`, :c:func:`PyMem_DEL`.
Customize Memory Allocators
===========================
.. versionadded:: 3.4
.. c:type:: PyMemAllocator
Structure used to describe a memory block allocator. The structure has
four fields:
+----------------------------------------------------------+---------------------------------------+
| Field | Meaning |
+==========================================================+=======================================+
| ``void *ctx`` | user context passed as first argument |
+----------------------------------------------------------+---------------------------------------+
| ``void* malloc(void *ctx, size_t size)`` | allocate a memory block |
+----------------------------------------------------------+---------------------------------------+
| ``void* realloc(void *ctx, void *ptr, size_t new_size)`` | allocate or resize a memory block |
+----------------------------------------------------------+---------------------------------------+
| ``void free(void *ctx, void *ptr)`` | free a memory block |
+----------------------------------------------------------+---------------------------------------+
.. c:type:: PyMemAllocatorDomain
Enum used to identify an allocator domain. Domains:
* :c:data:`PYMEM_DOMAIN_RAW`: functions :c:func:`PyMem_RawMalloc`,
:c:func:`PyMem_RawRealloc` and :c:func:`PyMem_RawFree`
* :c:data:`PYMEM_DOMAIN_MEM`: functions :c:func:`PyMem_Malloc`,
:c:func:`PyMem_Realloc` and :c:func:`PyMem_Free`
* :c:data:`PYMEM_DOMAIN_OBJ`: functions :c:func:`PyObject_Malloc`,
:c:func:`PyObject_Realloc` and :c:func:`PyObject_Free`
.. c:function:: void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)
Get the memory block allocator of the specified domain.
.. c:function:: void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)
Set the memory block allocator of the specified domain.
The new allocator must return a distinct non-NULL pointer when requesting
zero bytes.
For the :c:data:`PYMEM_DOMAIN_RAW` domain, the allocator must be
thread-safe: the :term:`GIL <global interpreter lock>` is not held when the
allocator is called.
If the new allocator is not a hook (does not call the previous allocator),
the :c:func:`PyMem_SetupDebugHooks` function must be called to reinstall the
debug hooks on top on the new allocator.
.. c:function:: void PyMem_SetupDebugHooks(void)
Setup hooks to detect bugs in the following Python memory allocator
functions:
- :c:func:`PyMem_RawMalloc`, :c:func:`PyMem_RawRealloc`,
:c:func:`PyMem_RawFree`
- :c:func:`PyMem_Malloc`, :c:func:`PyMem_Realloc`, :c:func:`PyMem_Free`
- :c:func:`PyObject_Malloc`, :c:func:`PyObject_Realloc`,
:c:func:`PyObject_Free`
Newly allocated memory is filled with the byte ``0xCB``, freed memory is
filled with the byte ``0xDB``. Additionnal checks:
- detect API violations, ex: :c:func:`PyObject_Free` called on a buffer
allocated by :c:func:`PyMem_Malloc`
- detect write before the start of the buffer (buffer underflow)
- detect write after the end of the buffer (buffer overflow)
The function does nothing if Python is not compiled is debug mode.
Customize PyObject Arena Allocator
==================================
Python has a *pymalloc* allocator for allocations smaller than 512 bytes. This
allocator is optimized for small objects with a short lifetime. It uses memory
mappings called "arenas" with a fixed size of 256 KB. It falls back to
:c:func:`PyMem_RawMalloc` and :c:func:`PyMem_RawRealloc` for allocations larger
than 512 bytes. *pymalloc* is the default allocator used by
:c:func:`PyObject_Malloc`.
The default arena allocator uses the following functions:
* :c:func:`VirtualAlloc` and :c:func:`VirtualFree` on Windows,
* :c:func:`mmap` and :c:func:`munmap` if available,
* :c:func:`malloc` and :c:func:`free` otherwise.
.. versionadded:: 3.4
.. c:type:: PyObjectArenaAllocator
Structure used to describe an arena allocator. The structure has
three fields:
+--------------------------------------------------+---------------------------------------+
| Field | Meaning |
+==================================================+=======================================+
| ``void *ctx`` | user context passed as first argument |
+--------------------------------------------------+---------------------------------------+
| ``void* alloc(void *ctx, size_t size)`` | allocate an arena of size bytes |
+--------------------------------------------------+---------------------------------------+
| ``void free(void *ctx, size_t size, void *ptr)`` | free an arena |
+--------------------------------------------------+---------------------------------------+
.. c:function:: PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)
Get the arena allocator.
.. c:function:: PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)
Set the arena allocator.
.. _memoryexamples:
Examples
......
......@@ -35,13 +35,20 @@ There are only a few functions special to module objects.
single: __name__ (module attribute)
single: __doc__ (module attribute)
single: __file__ (module attribute)
single: __package__ (module attribute)
single: __loader__ (module attribute)
Return a new module object with the :attr:`__name__` attribute set to *name*.
Only the module's :attr:`__doc__` and :attr:`__name__` attributes are filled in;
the caller is responsible for providing a :attr:`__file__` attribute.
The module's :attr:`__name__`, :attr:`__doc__`, :attr:`__package__`, and
:attr:`__loader__` attributes are filled in (all but :attr:`__name__` are set
to ``None``); the caller is responsible for providing a :attr:`__file__`
attribute.
.. versionadded:: 3.3
.. versionchanged:: 3.4
:attr:`__package__` and :attr:`__loader__` are set to ``None``.
.. c:function:: PyObject* PyModule_New(const char *name)
......
......@@ -149,6 +149,9 @@ Object Protocol
representation on success, *NULL* on failure. This is the equivalent of the
Python expression ``repr(o)``. Called by the :func:`repr` built-in function.
.. versionchanged:: 3.4
This function now includes a debug assertion to help ensure that it
does not silently discard an active exception.
.. c:function:: PyObject* PyObject_ASCII(PyObject *o)
......@@ -170,6 +173,10 @@ Object Protocol
Python expression ``str(o)``. Called by the :func:`str` built-in function
and, therefore, by the :func:`print` function.
.. versionchanged:: 3.4
This function now includes a debug assertion to help ensure that it
does not silently discard an active exception.
.. c:function:: PyObject* PyObject_Bytes(PyObject *o)
.. index:: builtin: bytes
......@@ -240,7 +247,7 @@ attribute is considered sufficient for this determination.
of the Python expression ``callable_object(*args)``.
.. c:function:: PyObject* PyObject_CallFunction(PyObject *callable, char *format, ...)
.. c:function:: PyObject* PyObject_CallFunction(PyObject *callable, const char *format, ...)
Call a callable Python object *callable*, with a variable number of C arguments.
The C arguments are described using a :c:func:`Py_BuildValue` style format
......@@ -250,8 +257,11 @@ attribute is considered sufficient for this determination.
pass :c:type:`PyObject \*` args, :c:func:`PyObject_CallFunctionObjArgs` is a
faster alternative.
.. versionchanged:: 3.4
The type of *format* was changed from ``char *``.
.. c:function:: PyObject* PyObject_CallMethod(PyObject *o, char *method, char *format, ...)
.. c:function:: PyObject* PyObject_CallMethod(PyObject *o, const char *method, const char *format, ...)
Call the method named *method* of object *o* with a variable number of C
arguments. The C arguments are described by a :c:func:`Py_BuildValue` format
......@@ -261,6 +271,9 @@ attribute is considered sufficient for this determination.
Note that if you only pass :c:type:`PyObject \*` args,
:c:func:`PyObject_CallMethodObjArgs` is a faster alternative.
.. versionchanged:: 3.4
The types of *method* and *format* were changed from ``char *``.
.. c:function:: PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)
......@@ -342,6 +355,16 @@ attribute is considered sufficient for this determination.
returned. This is the equivalent to the Python expression ``len(o)``.
.. c:function:: Py_ssize_t PyObject_LengthHint(PyObject *o, Py_ssize_t default)
Return an estimated length for the object *o*. First try to return its
actual length, then an estimate using :meth:`~object.__length_hint__`, and
finally return the default value. On error return ``-1``. This is the
equivalent to the Python expression ``operator.length_hint(o, default)``.
.. versionadded:: 3.4
.. c:function:: PyObject* PyObject_GetItem(PyObject *o, PyObject *key)
Return element of *o* corresponding to the object *key* or *NULL* on failure.
......
......@@ -129,6 +129,14 @@ type.
Initializes a struct sequence type *type* from *desc* in place.
.. c:function:: int PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
The same as ``PyStructSequence_InitType``, but returns ``0`` on success and ``-1`` on
failure.
.. versionadded:: 3.4
.. c:type:: PyStructSequence_Desc
Contains the meta information of a struct sequence type to create.
......
......@@ -97,3 +97,13 @@ Type Objects
types. This allows the caller to reference other heap types as base types.
.. versionadded:: 3.3
.. c:function:: void* PyType_GetSlot(PyTypeObject *type, int slot)
Return the function pointer stored in the given slot. If the
result is *NULL*, this indicates that either the slot is *NULL*,
or that the function was called with invalid parameters.
Callers will typically cast the result pointer into the appropriate
function type.
.. versionadded:: 3.4
......@@ -464,6 +464,14 @@ type objects) *must* have the :attr:`ob_size` field.
:const:`Py_TPFLAGS_HAVE_VERSION_TAG`.
.. data:: Py_TPFLAGS_HAVE_FINALIZE
This bit is set when the :c:member:`~PyTypeObject.tp_finalize` slot is present in the
type structure.
.. versionadded:: 3.4
.. c:member:: char* PyTypeObject.tp_doc
An optional pointer to a NUL-terminated C string giving the docstring for this
......@@ -967,6 +975,47 @@ type objects) *must* have the :attr:`ob_size` field.
This field is not inherited; it is calculated fresh by :c:func:`PyType_Ready`.
.. c:member:: destructor PyTypeObject.tp_finalize
An optional pointer to an instance finalization function. Its signature is
:c:type:`destructor`::
void tp_finalize(PyObject *)
If :c:member:`~PyTypeObject.tp_finalize` is set, the interpreter calls it once when
finalizing an instance. It is called either from the garbage
collector (if the instance is part of an isolated reference cycle) or
just before the object is deallocated. Either way, it is guaranteed
to be called before attempting to break reference cycles, ensuring
that it finds the object in a sane state.
:c:member:`~PyTypeObject.tp_finalize` should not mutate the current exception status;
therefore, a recommended way to write a non-trivial finalizer is::
static void
local_finalize(PyObject *self)
{
PyObject *error_type, *error_value, *error_traceback;
/* Save the current exception, if any. */
PyErr_Fetch(&error_type, &error_value, &error_traceback);
/* ... */
/* Restore the saved exception. */
PyErr_Restore(error_type, error_value, error_traceback);
}
For this field to be taken into account (even through inheritance),
you must also set the :const:`Py_TPFLAGS_HAVE_FINALIZE` flags bit.
This field is inherited by subtypes.
.. versionadded:: 3.4
.. seealso:: "Safe object finalization" (:pep:`442`)
.. c:member:: PyObject* PyTypeObject.tp_cache
Unused. Not inherited. Internal use only.
......
......@@ -526,12 +526,23 @@ APIs:
The `"%lld"` and `"%llu"` format specifiers are only available
when :const:`HAVE_LONG_LONG` is defined.
.. note::
The width formatter unit is number of characters rather than bytes.
The precision formatter unit is number of bytes for ``"%s"`` and
``"%V"`` (if the ``PyObject*`` argument is NULL), and a number of
characters for ``"%A"``, ``"%U"``, ``"%S"``, ``"%R"`` and ``"%V"``
(if the ``PyObject*`` argument is not NULL).
.. versionchanged:: 3.2
Support for ``"%lld"`` and ``"%llu"`` added.
.. versionchanged:: 3.3
Support for ``"%li"``, ``"%lli"`` and ``"%zi"`` added.
.. versionchanged:: 3.4
Support width and precision formatter for ``"%s"``, ``"%A"``, ``"%U"``,
``"%V"``, ``"%S"``, ``"%R"`` added.
.. c:function:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs)
......
......@@ -144,6 +144,37 @@ the same library that the Python runtime is using.
(:func:`sys.getfilesystemencoding`). Returns ``0`` at EOF.
.. c:var:: int (*PyOS_InputHook)(void)
Can be set to point to a function with the prototype
``int func(void)``. The function will be called when Python's
interpreter prompt is about to become idle and wait for user input
from the terminal. The return value is ignored. Overriding this
hook can be used to integrate the interpreter's prompt with other
event loops, as done in the :file:`Modules/_tkinter.c` in the
Python source code.
.. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *)
Can be set to point to a function with the prototype
``char *func(FILE *stdin, FILE *stdout, char *prompt)``,
overriding the default function used to read a single line of input
at the interpreter's prompt. The function is expected to output
the string *prompt* if it's not *NULL*, and then read a line of
input from the provided standard input file, returning the
resulting string. For example, The :mod:`readline` module sets
this hook to provide line-editing and tab-completion features.
The result must be a string allocated by :c:func:`PyMem_RawMalloc` or
:c:func:`PyMem_RawRealloc`, or *NULL* if an error occurred.
.. versionchanged:: 3.4
The result must be allocated by :c:func:`PyMem_RawMalloc` or
:c:func:`PyMem_RawRealloc`, instead of being allocated by
:c:func:`PyMem_Malloc` or :c:func:`PyMem_Realloc`.
.. c:function:: struct _node* PyParser_SimpleParseString(const char *str, int start)
This is a simplified interface to
......@@ -235,16 +266,15 @@ the same library that the Python runtime is using.
*optimize* set to ``-1``.
.. c:function:: PyObject* Py_CompileStringExFlags(const char *str, const char *filename, int start, PyCompilerFlags *flags, int optimize)
.. c:function:: PyObject* Py_CompileStringObject(const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize)
Parse and compile the Python source code in *str*, returning the resulting code
object. The start token is given by *start*; this can be used to constrain the
code which can be compiled and should be :const:`Py_eval_input`,
:const:`Py_file_input`, or :const:`Py_single_input`. The filename specified by
*filename* is used to construct the code object and may appear in tracebacks or
:exc:`SyntaxError` exception messages, it is decoded from the filesystem
encoding (:func:`sys.getfilesystemencoding`). This returns *NULL* if the
code cannot be parsed or compiled.
:exc:`SyntaxError` exception messages. This returns *NULL* if the code
cannot be parsed or compiled.
The integer *optimize* specifies the optimization level of the compiler; a
value of ``-1`` selects the optimization level of the interpreter as given by
......@@ -252,8 +282,15 @@ the same library that the Python runtime is using.
``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false)
or ``2`` (docstrings are removed too).
.. versionadded:: 3.2
.. versionadded:: 3.4
.. c:function:: PyObject* Py_CompileStringExFlags(const char *str, const char *filename, int start, PyCompilerFlags *flags, int optimize)
Like :c:func:`Py_CompileStringExFlags`, but *filename* is a byte string
decoded from the filesystem encoding (:func:`os.fsdecode`).
.. versionadded:: 3.2
.. c:function:: PyObject* PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
......@@ -285,6 +322,10 @@ the same library that the Python runtime is using.
it causes an exception to immediately be thrown; this is used for the
:meth:`~generator.throw` methods of generator objects.
.. versionchanged:: 3.4
This function now includes a debug assertion to help ensure that it
does not silently discard an active exception.
.. c:function:: int PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
......@@ -338,4 +379,3 @@ the same library that the Python runtime is using.
This bit can be set in *flags* to cause division operator ``/`` to be
interpreted as "true division" according to :pep:`238`.
......@@ -61,6 +61,8 @@ add_module_names = True
# By default, highlight as Python 3.
highlight_language = 'python3'
needs_sphinx = '1.1'
# Options for HTML output
# -----------------------
......@@ -118,11 +120,11 @@ _stdauthor = r'Guido van Rossum\\Fred L. Drake, Jr., editor'
latex_documents = [
('c-api/index', 'c-api.tex',
'The Python/C API', _stdauthor, 'manual'),
('distutils/index', 'distutils.tex',
('distributing/index', 'distributing.tex',
'Distributing Python Modules', _stdauthor, 'manual'),
('extending/index', 'extending.tex',
'Extending and Embedding Python', _stdauthor, 'manual'),
('install/index', 'install.tex',
('installing/index', 'installing.tex',
'Installing Python Modules', _stdauthor, 'manual'),
('library/index', 'library.tex',
'The Python Library Reference', _stdauthor, 'manual'),
......
......@@ -11,8 +11,8 @@
library/index.rst
extending/index.rst
c-api/index.rst
distutils/index.rst
install/index.rst
distributing/index.rst
installing/index.rst
howto/index.rst
faq/index.rst
glossary.rst
......@@ -21,3 +21,11 @@
bugs.rst
copyright.rst
license.rst
.. include legacy packaging docs in build
.. toctree::
:hidden:
distutils/index.rst
install/index.rst
......@@ -29,7 +29,7 @@
# reference to the item argument!
# The parameter names are as they appear in the API manual, not the source
# code.
# code.
PyBool_FromLong:PyObject*::+1:
PyBool_FromLong:long:v:0:
......@@ -220,6 +220,11 @@ PyDict_GetItemString:PyObject*::0:
PyDict_GetItemString:PyObject*:p:0:
PyDict_GetItemString:const char*:key::
PyDict_SetDefault:PyObject*::0:
PyDict_SetDefault:PyObject*:p:0:
PyDict_SetDefault:PyObject*:key:0:conditionally +1 if inserted into the dict
PyDict_SetDefault:PyObject*:default:0:conditionally +1 if inserted into the dict
PyDict_Items:PyObject*::+1:
PyDict_Items:PyObject*:p:0:
......@@ -503,13 +508,13 @@ PyImport_AddModule:const char*:name::
PyImport_Cleanup:void:::
PyImport_ExecCodeModule:PyObject*::+1:
PyImport_ExecCodeModule:char*:name::
PyImport_ExecCodeModule:const char*:name::
PyImport_ExecCodeModule:PyObject*:co:0:
PyImport_ExecCodeModuleEx:PyObject*::+1:
PyImport_ExecCodeModuleEx:char*:name::
PyImport_ExecCodeModuleEx:const char*:name::
PyImport_ExecCodeModuleEx:PyObject*:co:0:
PyImport_ExecCodeModuleEx:char*:pathname::
PyImport_ExecCodeModuleEx:const char*:pathname::
PyImport_GetMagicNumber:long:::
......@@ -519,7 +524,7 @@ PyImport_Import:PyObject*::+1:
PyImport_Import:PyObject*:name:0:
PyImport_ImportFrozenModule:int:::
PyImport_ImportFrozenModule:char*:::
PyImport_ImportFrozenModule:const char*:::
PyImport_ImportModule:PyObject*::+1:
PyImport_ImportModule:const char*:name::
......@@ -668,7 +673,7 @@ PyLong_FromUnsignedLongLong:PyObject*::+1:
PyLong_FromUnsignedLongLong:unsigned long long:v::
PyLong_FromString:PyObject*::+1:
PyLong_FromString:char*:str::
PyLong_FromString:const char*:str::
PyLong_FromString:char**:pend::
PyLong_FromString:int:base::
......@@ -696,7 +701,7 @@ PyMapping_DelItemString:const char*:key::
PyMapping_GetItemString:PyObject*::+1:
PyMapping_GetItemString:PyObject*:o:0:
PyMapping_GetItemString:char*:key::
PyMapping_GetItemString:const char*:key::
PyMapping_HasKey:int:::
PyMapping_HasKey:PyObject*:o:0:
......@@ -704,7 +709,7 @@ PyMapping_HasKey:PyObject*:key::
PyMapping_HasKeyString:int:::
PyMapping_HasKeyString:PyObject*:o:0:
PyMapping_HasKeyString:char*:key::
PyMapping_HasKeyString:const char*:key::
PyMapping_Items:PyObject*::+1:
PyMapping_Items:PyObject*:o:0:
......@@ -717,7 +722,7 @@ PyMapping_Length:PyObject*:o:0:
PyMapping_SetItemString:int:::
PyMapping_SetItemString:PyObject*:o:0:
PyMapping_SetItemString:char*:key::
PyMapping_SetItemString:const char*:key::
PyMapping_SetItemString:PyObject*:v:+1:
PyMapping_Values:PyObject*::+1:
......@@ -730,7 +735,7 @@ PyMarshal_ReadObjectFromFile:PyObject*::+1:
PyMarshal_ReadObjectFromFile:FILE*:file::
PyMarshal_ReadObjectFromString:PyObject*::+1:
PyMarshal_ReadObjectFromString:char*:string::
PyMarshal_ReadObjectFromString:const char*:string::
PyMarshal_ReadObjectFromString:int:len::
PyMarshal_WriteObjectToString:PyObject*::+1:
......@@ -902,7 +907,7 @@ PyNumber_Xor:PyObject*::+1:
PyNumber_Xor:PyObject*:o1:0:
PyNumber_Xor:PyObject*:o2:0:
PyObject_AsFileDescriptor:int:::
PyObject_AsFileDescriptor:int:::
PyObject_AsFileDescriptor:PyObject*:o:0:
PyObject_Call:PyObject*::+1:
......@@ -912,7 +917,7 @@ PyObject_Call:PyObject*:kw:0:
PyObject_CallFunction:PyObject*::+1:
PyObject_CallFunction:PyObject*:callable_object:0:
PyObject_CallFunction:char*:format::
PyObject_CallFunction:const char*:format::
PyObject_CallFunction::...::
PyObject_CallFunctionObjArgs:PyObject*::+1:
......@@ -921,8 +926,8 @@ PyObject_CallFunctionObjArgs::...::
PyObject_CallMethod:PyObject*::+1:
PyObject_CallMethod:PyObject*:o:0:
PyObject_CallMethod:char*:m::
PyObject_CallMethod:char*:format::
PyObject_CallMethod:const char*:m::
PyObject_CallMethod:const char*:format::
PyObject_CallMethod::...::
PyObject_CallMethodObjArgs:PyObject*::+1:
......
.. _distributing-index:
###############################
Distributing Python Modules
###############################
:Email: distutils-sig@python.org
As a popular open source development project, Python has an active
supporting community of contributors and users that also make their software
available for other Python developers to use under open source license terms.
This allows Python users to share and collaborate effectively, benefiting
from the solutions others have already created to common (and sometimes
even rare!) problems, as well as potentially contributing their own
solutions to the common pool.
This guide covers the distribution part of the process. For a guide to
installing other Python projects, refer to the
:ref:`installation guide <installing-index>`.
.. note::
For corporate and other institutional users, be aware that many
organisations have their own policies around using and contributing to
open source software. Please take such policies into account when making
use of the distribution and installation tools provided with Python.
Key terms
=========
* the `Python Package Index <https://pypi.python.org/pypi>`__ is a public
repository of open source licensed packages made available for use by
other Python users
* the `Python Packaging Authority
<http://packaging.python.org/en/latest/future.html>`__ are the group of
developers and documentation authors responsible for the maintenance and
evolution of the standard packaging tools and the associated metadata and
file format standards. They maintain a variety of tools, documentation
and issue trackers on both `GitHub <https://github.com/pypa>`__ and
`BitBucket <https://bitbucket.org/pypa/>`__.
* ``distutils`` is the original build and distribution system first added to
the Python standard library in 1998. While direct use of ``distutils`` is
being phased out, it still laid the foundation for the current packaging
and distribution infrastructure, and it not only remains part of the
standard library, but its name lives on in other ways (such as the name
of the mailing list used to coordinate Python packaging standards
development).
Open source licensing and collaboration
=======================================
In most parts of the world, software is automatically covered by copyright.
This means that other developers require explicit permission to copy, use,
modify and redistribute the software.
Open source licensing is a way of explicitly granting such permission in a
relatively consistent way, allowing developers to share and collaborate
efficiently by making common solutions to various problems freely available.
This leaves many developers free to spend more time focusing on the problems
that are relatively unique to their specific situation.
The distribution tools provided with Python are designed to make it
reasonably straightforward for developers to make their own contributions
back to that common pool of software if they choose to do so.
The same distribution tools can also be used to distribute software within
an organisation, regardless of whether that software is published as open
source software or not.
Installing the tools
====================
The standard library does not include build tools that support modern
Python packaging standards, as the core development team has found that it
is important to have standard tools that work consistently, even on older
versions of Python.
The currently recommended build and distribution tools can be installed
using ``pip``::
pip install setuptools wheel twine
Reading the guide
=================
The Python Packaging User Guide covers the various key steps and elements
involved in creating a project
* `Project structure`_
* `Building and packaging the project`_
* `Uploading the project to the Python Package Index`_
.. _Project structure: \
http://packaging.python.org/en/latest/tutorial.html#creating-your-own-project
.. _Building and packaging the project: \
http://packaging.python.org/en/latest/tutorial.html#building-packaging-your-project
.. _Uploading the project to the Python Package Index: \
http://packaging.python.org/en/latest/tutorial.html#uploading-your-project-to-pypi
How do I...?
============
These are quick answers or links for some common tasks.
... choose a name for my project?
---------------------------------
This isn't an easy topic, but here are a few tips:
* check the Python Package Index to see if the name is already in use
* check popular hosting sites like GitHub, BitBucket, etc to see if there
is already a project with that name
* check what comes up in a web search for the name you're considering
* avoid particularly common words, especially ones with multiple meanings,
as they can make it difficult for users to find your software when
searching for it
... create and distribute binary extensions?
--------------------------------------------
This is actually quite a complex topic, with a variety of alternatives
available depending on exactly what you're aiming to achieve. See the
Python Packaging User Guide for more information and recommendations.
.. seealso::
`Python Packaging User Guide: Binary Extensions
<http://packaging.python.org/en/latest/extensions.html>`__
.. other topics:
Once the Development & Deployment part of PPUG is fleshed out, some of
those sections should be linked from new questions here (most notably,
we should have a question about avoiding depending on PyPI that links to
http://packaging.python.org/en/latest/deployment.html#pypi-mirrors-and-caches)
......@@ -853,17 +853,6 @@ Windows. It also contains the Mingw32CCompiler class which handles the mingw32
port of GCC (same as cygwin in no-cygwin mode).
:mod:`distutils.emxccompiler` --- OS/2 EMX Compiler
===================================================
.. module:: distutils.emxccompiler
:synopsis: OS/2 EMX Compiler support
This module provides the EMXCCompiler class, a subclass of
:class:`UnixCCompiler` that handles the EMX port of the GNU C compiler to OS/2.
:mod:`distutils.archive_util` --- Archiving utilities
======================================================
......@@ -1004,7 +993,7 @@ directories.
Files in *src* that begin with :file:`.nfs` are skipped (more information on
these files is available in answer D2 of the `NFS FAQ page
<http://nfs.sourceforge.net/#section_d>`_.
<http://nfs.sourceforge.net/#section_d>`_).
.. versionchanged:: 3.3.1
NFS files are ignored.
......
......@@ -239,7 +239,8 @@ tedious and error-prone, so it's usually best to put them in the setup
configuration file, :file:`setup.cfg`\ ---see section :ref:`setup-config`. If
you distribute or package many Python module distributions, you might want to
put options that apply to all of them in your personal Distutils configuration
file (:file:`~/.pydistutils.cfg`).
file (:file:`~/.pydistutils.cfg`). If you want to temporarily disable
this file, you can pass the :option:`--no-user-cfg` option to :file:`setup.py`.
There are three steps to building a binary RPM package, all of which are
handled automatically by the Distutils:
......
.. _distutils-index:
###############################
Distributing Python Modules
###############################
##############################################
Distributing Python Modules (Legacy version)
##############################################
:Authors: Greg Ward, Anthony Baxter
:Email: distutils-sig@python.org
......
......@@ -26,16 +26,16 @@ to create a gzipped tarball and a zip file. The available formats are:
+===========+=========================+=========+
| ``zip`` | zip file (:file:`.zip`) | (1),(3) |
+-----------+-------------------------+---------+
| ``gztar`` | gzip'ed tar file | (2),(4) |
| ``gztar`` | gzip'ed tar file | \(2) |
| | (:file:`.tar.gz`) | |
+-----------+-------------------------+---------+
| ``bztar`` | bzip2'ed tar file | \(4) |
| ``bztar`` | bzip2'ed tar file | |
| | (:file:`.tar.bz2`) | |
+-----------+-------------------------+---------+
| ``ztar`` | compressed tar file | \(4) |
| | (:file:`.tar.Z`) | |
+-----------+-------------------------+---------+
| ``tar`` | tar file (:file:`.tar`) | \(4) |
| ``tar`` | tar file (:file:`.tar`) | |
+-----------+-------------------------+---------+
Notes:
......@@ -51,8 +51,16 @@ Notes:
of the standard Python library since Python 1.6)
(4)
requires external utilities: :program:`tar` and possibly one of :program:`gzip`,
:program:`bzip2`, or :program:`compress`
requires the :program:`compress` program. Notice that this format is now
pending for deprecation and will be removed in the future versions of Python.
When using any ``tar`` format (``gztar``, ``bztar``, ``ztar`` or
``tar``), under Unix you can specify the ``owner`` and ``group`` names
that will be set for each member of the archive.
For example, if you want all files of the archive to be owned by root::
python setup.py sdist --owner=root --group=root
.. _manifest:
......@@ -68,7 +76,7 @@ source distribution:
:option:`packages` options
* all C source files mentioned in the :option:`ext_modules` or
:option:`libraries` options (
:option:`libraries` options
.. XXX getting C library sources currently broken---no
:meth:`get_source_files` method in :file:`build_clib.py`!
......
......@@ -285,14 +285,14 @@ be directly useful to you:
* ``pythonX.Y-config --cflags`` will give you the recommended flags when
compiling::
$ /opt/bin/python3.3-config --cflags
-I/opt/include/python3.3m -I/opt/include/python3.3m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
$ /opt/bin/python3.4-config --cflags
-I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
* ``pythonX.Y-config --ldflags`` will give you the recommended flags when
linking::
$ /opt/bin/python3.3-config --ldflags
-L/opt/lib/python3.3/config-3.3m -lpthread -ldl -lutil -lm -lpython3.3m -Xlinker -export-dynamic
$ /opt/bin/python3.4-config --ldflags
-L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic
.. note::
To avoid confusion between several Python installations (and especially
......
......@@ -21,14 +21,31 @@ Python) that give the language its wide application range.
For a detailed description of the whole Python/C API, see the separate
:ref:`c-api-index`.
.. note::
This guide only covers the basic tools for creating extensions provided
as part of this version of CPython. Third party tools may offer simpler
alternatives. Refer to the `binary extensions section
<https://python-packaging-user-guide.readthedocs.org/en/latest/extensions.html>`__
in the Python Packaging User Guide for more information.
Recommended third party tools
=============================
This guide only covers the basic tools for creating extensions provided
as part of this version of CPython. Third party tools like Cython,
``cffi``, SWIG and Numba offer both simpler and more sophisticated
approaches to creating C and C++ extensions for Python.
.. seealso::
`Python Packaging User Guide: Binary Extensions <https://packaging.python.org/en/latest/extensions.html>`_
The Python Packaging User Guide not only covers several available
tools that simplify the creation of binary extensions, but also
discusses the various reasons why creating an extension module may be
desirable in the first place.
Creating extensions without third party tools
=============================================
This section of the guide covers creating C and C++ extensions without
assistance from third party tools. It is intended primarily for creators
of those tools, rather than being a recommended way to create your own
C extensions.
.. toctree::
:maxdepth: 2
......@@ -38,4 +55,17 @@ For a detailed description of the whole Python/C API, see the separate
newtypes.rst
building.rst
windows.rst
Embedding the CPython runtime in a larger application
=====================================================
Sometimes, rather than creating an extension that runs inside the Python
interpreter as the main application, it is desirable to instead embed
the CPython runtime inside a larger application. This section covers
some of the details involved in doing that successfully.
.. toctree::
:maxdepth: 2
:numbered:
embedding.rst
......@@ -157,7 +157,8 @@ to :const:`Py_TPFLAGS_DEFAULT`. ::
Py_TPFLAGS_DEFAULT, /* tp_flags */
All types should include this constant in their flags. It enables all of the
members defined by the current version of Python.
members defined until at least Python 3.3. If you need further members,
you will need to OR the corresponding flags.
We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. ::
......@@ -928,8 +929,9 @@ Finalization and De-allocation
This function is called when the reference count of the instance of your type is
reduced to zero and the Python interpreter wants to reclaim it. If your type
has memory to free or other clean-up to perform, put it here. The object itself
needs to be freed here as well. Here is an example of this function::
has memory to free or other clean-up to perform, you can put it here. The
object itself needs to be freed here as well. Here is an example of this
function::
static void
newdatatype_dealloc(newdatatypeobject * obj)
......@@ -980,6 +982,22 @@ done. This can be done using the :c:func:`PyErr_Fetch` and
Py_TYPE(obj)->tp_free((PyObject*)self);
}
.. note::
There are limitations to what you can safely do in a deallocator function.
First, if your type supports garbage collection (using :c:member:`~PyTypeObject.tp_traverse`
and/or :c:member:`~PyTypeObject.tp_clear`), some of the object's members can have been
cleared or finalized by the time :c:member:`~PyTypeObject.tp_dealloc` is called. Second, in
:c:member:`~PyTypeObject.tp_dealloc`, your object is in an unstable state: its reference
count is equal to zero. Any call to a non-trivial object or API (as in the
example above) might end up calling :c:member:`~PyTypeObject.tp_dealloc` again, causing a
double free and a crash.
Starting with Python 3.4, it is recommended not to put any complex
finalization code in :c:member:`~PyTypeObject.tp_dealloc`, and instead use the new
:c:member:`~PyTypeObject.tp_finalize` type method.
.. seealso::
:pep:`442` explains the new finalization scheme.
.. index::
single: string; object representation
......
......@@ -95,8 +95,8 @@ To test the type of an object, first make sure it isn't *NULL*, and then use
There is also a high-level API to Python objects which is provided by the
so-called 'abstract' interface -- read ``Include/abstract.h`` for further
details. It allows interfacing with any kind of Python sequence using calls
like :c:func:`PySequence_Length`, :c:func:`PySequence_GetItem`, etc.) as well
as many other useful protocols such as numbers (:c:func:`PyNumber_Index` et.
like :c:func:`PySequence_Length`, :c:func:`PySequence_GetItem`, etc. as well
as many other useful protocols such as numbers (:c:func:`PyNumber_Index` et
al.) and mappings in the PyMapping APIs.
......
......@@ -211,7 +211,7 @@ using curses, but curses is a fairly large module to learn.
try:
c = sys.stdin.read(1)
print("Got character", repr(c))
except IOError:
except OSError:
pass
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
......@@ -224,7 +224,11 @@ using curses, but curses is a fairly large module to learn.
:func:`termios.tcsetattr` turns off stdin's echoing and disables canonical
mode. :func:`fcntl.fnctl` is used to obtain stdin's file descriptor flags
and modify them for non-blocking mode. Since reading stdin when it is empty
results in an :exc:`IOError`, this error is caught and ignored.
results in an :exc:`OSError`, this error is caught and ignored.
.. versionchanged:: 3.3
*sys.stdin.read* used to raise :exc:`IOError`. Starting from Python 3.3
:exc:`IOError` is alias for :exc:`OSError`.
Threads
......
......@@ -1751,12 +1751,12 @@ When I edit an imported module and reimport it, the changes don't show up. Why
For reasons of efficiency as well as consistency, Python only reads the module
file on the first time a module is imported. If it didn't, in a program
consisting of many modules where each one imports the same basic module, the
basic module would be parsed and re-parsed many times. To force rereading of a
basic module would be parsed and re-parsed many times. To force re-reading of a
changed module, do this::
import imp
import importlib
import modname
imp.reload(modname)
importlib.reload(modname)
Warning: this technique is not 100% fool-proof. In particular, modules
containing statements like ::
......@@ -1768,10 +1768,10 @@ module contains class definitions, existing class instances will *not* be
updated to use the new class definition. This can result in the following
paradoxical behaviour:
>>> import imp
>>> import importlib
>>> import cls
>>> c = cls.C() # Create an instance of C
>>> imp.reload(cls)
>>> importlib.reload(cls)
<module 'cls' from 'cls.py'>
>>> isinstance(c, cls.C) # isinstance is false?!?
False
......
......@@ -310,6 +310,15 @@ Glossary
>>> sum(i*i for i in range(10)) # sum of squares 0, 1, 4, ... 81
285
generic function
A function composed of multiple functions implementing the same operation
for different types. Which implementation should be used during a call is
determined by the dispatch algorithm.
See also the :term:`single dispatch` glossary entry, the
:func:`functools.singledispatch` decorator, and :pep:`443`.
GIL
See :term:`global interpreter lock`.
......@@ -530,6 +539,10 @@ Glossary
See also :term:`package`.
module spec
A namespace containing the import-related information used to load a
module.
MRO
See :term:`method resolution order`.
......@@ -671,20 +684,27 @@ Glossary
positional argument
See :term:`argument`.
provisional package
A provisional package is one which has been deliberately excluded from
provisional API
A provisional API is one which has been deliberately excluded from
the standard library's backwards compatibility guarantees. While major
changes to such packages are not expected, as long as they are marked
changes to such interfaces are not expected, as long as they are marked
provisional, backwards incompatible changes (up to and including removal
of the package) may occur if deemed necessary by core developers. Such
of the interface) may occur if deemed necessary by core developers. Such
changes will not be made gratuitously -- they will occur only if serious
flaws are uncovered that were missed prior to the inclusion of the
package.
fundamental flaws are uncovered that were missed prior to the inclusion
of the API.
Even for provisional APIs, backwards incompatible changes are seen as
a "solution of last resort" - every attempt will still be made to find
a backwards compatible resolution to any identified problems.
This process allows the standard library to continue to evolve over
time, without locking in problematic design errors for extended periods
of time. See :pep:`411` for more details.
provisional package
See :term:`provisional API`.
Python 3000
Nickname for the Python 3.x release line (coined long ago when the
release of version 3 was something in the distant future.) This is also
......@@ -771,6 +791,10 @@ Glossary
interface can be registered explicitly using
:func:`~abc.register`.
single dispatch
A form of :term:`generic function` dispatch where the implementation is
chosen based on the type of a single argument.
slice
An object usually containing a portion of a :term:`sequence`. A slice is
created using the subscript notation, ``[]`` with colons between numbers
......
This diff is collapsed.
......@@ -3,7 +3,7 @@
********************************
:Author: A. M. Kuchling
:Release: 0.31
:Release: 0.32
In this document, we'll take a tour of Python's features suitable for
implementing programs in a functional style. After an introduction to the
......@@ -15,9 +15,9 @@ concepts of functional programming, we'll look at language features such as
Introduction
============
This section explains the basic concept of functional programming; if you're
just interested in learning about Python language features, skip to the next
section.
This section explains the basic concept of functional programming; if
you're just interested in learning about Python language features,
skip to the next section on :ref:`functional-howto-iterators`.
Programming languages support decomposing problems in several different ways:
......@@ -173,6 +173,8 @@ new programs by arranging existing functions in a new configuration and writing
a few functions specialized for the current task.
.. _functional-howto-iterators:
Iterators
=========
......@@ -670,7 +672,7 @@ indexes at which certain conditions are met::
:func:`sorted(iterable, key=None, reverse=False) <sorted>` collects all the
elements of the iterable into a list, sorts the list, and returns the sorted
result. The *key*, and *reverse* arguments are passed through to the
result. The *key* and *reverse* arguments are passed through to the
constructed list's :meth:`~list.sort` method. ::
>>> import random
......@@ -836,7 +838,8 @@ Another group of functions chooses a subset of an iterator's elements based on a
predicate.
:func:`itertools.filterfalse(predicate, iter) <itertools.filterfalse>` is the
opposite, returning all elements for which the predicate returns false::
opposite of :func:`filter`, returning all elements for which the predicate
returns false::
itertools.filterfalse(is_even, itertools.count()) =>
1, 3, 5, 7, 9, 11, 13, 15, ...
......@@ -864,6 +867,77 @@ iterable's results. ::
itertools.dropwhile(is_even, itertools.count()) =>
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...
:func:`itertools.compress(data, selectors) <itertools.compress>` takes two
iterators and returns only those elements of *data* for which the corresponding
element of *selectors* is true, stopping whenever either one is exhausted::
itertools.compress([1,2,3,4,5], [True, True, False, False, True]) =>
1, 2, 5
Combinatoric functions
----------------------
The :func:`itertools.combinations(iterable, r) <itertools.combinations>`
returns an iterator giving all possible *r*-tuple combinations of the
elements contained in *iterable*. ::
itertools.combinations([1, 2, 3, 4, 5], 2) =>
(1, 2), (1, 3), (1, 4), (1, 5),
(2, 3), (2, 4), (2, 5),
(3, 4), (3, 5),
(4, 5)
itertools.combinations([1, 2, 3, 4, 5], 3) =>
(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5),
(2, 3, 4), (2, 3, 5), (2, 4, 5),
(3, 4, 5)
The elements within each tuple remain in the same order as
*iterable* returned them. For example, the number 1 is always before
2, 3, 4, or 5 in the examples above. A similar function,
:func:`itertools.permutations(iterable, r=None) <itertools.permutations>`,
removes this constraint on the order, returning all possible
arrangements of length *r*::
itertools.permutations([1, 2, 3, 4, 5], 2) =>
(1, 2), (1, 3), (1, 4), (1, 5),
(2, 1), (2, 3), (2, 4), (2, 5),
(3, 1), (3, 2), (3, 4), (3, 5),
(4, 1), (4, 2), (4, 3), (4, 5),
(5, 1), (5, 2), (5, 3), (5, 4)
itertools.permutations([1, 2, 3, 4, 5]) =>
(1, 2, 3, 4, 5), (1, 2, 3, 5, 4), (1, 2, 4, 3, 5),
...
(5, 4, 3, 2, 1)
If you don't supply a value for *r* the length of the iterable is used,
meaning that all the elements are permuted.
Note that these functions produce all of the possible combinations by
position and don't require that the contents of *iterable* are unique::
itertools.permutations('aba', 3) =>
('a', 'b', 'a'), ('a', 'a', 'b'), ('b', 'a', 'a'),
('b', 'a', 'a'), ('a', 'a', 'b'), ('a', 'b', 'a')
The identical tuple ``('a', 'a', 'b')`` occurs twice, but the two 'a'
strings came from different positions.
The :func:`itertools.combinations_with_replacement(iterable, r) <itertools.combinations_with_replacement>`
function relaxes a different constraint: elements can be repeated
within a single tuple. Conceptually an element is selected for the
first position of each tuple and then is replaced before the second
element is selected. ::
itertools.combinations_with_replacement([1, 2, 3, 4, 5], 2) =>
(1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
(2, 2), (2, 3), (2, 4), (2, 5),
(3, 3), (3, 4), (3, 5),
(4, 4), (4, 5),
(5, 5)
Grouping elements
-----------------
......@@ -986,6 +1060,17 @@ write the obvious :keyword:`for` loop::
for i in [1,2,3]:
product *= i
A related function is `itertools.accumulate(iterable, func=operator.add) <itertools.accumulate`.
It performs the same calculation, but instead of returning only the
final result, :func:`accumulate` returns an iterator that also yields
each partial result::
itertools.accumulate([1,2,3,4,5]) =>
1, 3, 6, 10, 15
itertools.accumulate([1,2,3,4,5], operator.mul) =>
1, 2, 6, 24, 120
The operator module
-------------------
......@@ -1157,51 +1242,6 @@ Documentation for the :mod:`operator` module.
:pep:`342`: "Coroutines via Enhanced Generators" describes the new generator
features in Python 2.5.
.. comment
Topics to place
-----------------------------
XXX os.walk()
XXX Need a large example.
But will an example add much? I'll post a first draft and see
what the comments say.
.. comment
Original outline:
Introduction
Idea of FP
Programs built out of functions
Functions are strictly input-output, no internal state
Opposed to OO programming, where objects have state
Why FP?
Formal provability
Assignment is difficult to reason about
Not very relevant to Python
Modularity
Small functions that do one thing
Debuggability:
Easy to test due to lack of state
Easy to verify output from intermediate steps
Composability
You assemble a toolbox of functions that can be mixed
Tackling a problem
Need a significant example
Iterators
Generators
The itertools module
List comprehensions
Small functions and the lambda statement
Built-in functions
map
filter
.. comment
Handy little function for printing part of an iterator -- used
......@@ -1214,5 +1254,3 @@ features in Python 2.5.
sys.stdout.write(str(elem))
sys.stdout.write(', ')
print(elem[-1])
......@@ -28,4 +28,5 @@ Currently, the HOWTOs are:
webservers.rst
argparse.rst
ipaddress.rst
clinic.rst
......@@ -416,7 +416,7 @@ module. Here is a basic working example::
Simple TCP socket-based logging receiver suitable for testing.
"""
allow_reuse_address = 1
allow_reuse_address = True
def __init__(self, host='localhost',
port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
......@@ -704,9 +704,7 @@ the basis for code meeting your own specific requirements::
break
logger = logging.getLogger(record.name)
logger.handle(record) # No level or filter logic applied - just do it!
except (KeyboardInterrupt, SystemExit):
raise
except:
except Exception:
import sys, traceback
print('Whoops! Problem:', file=sys.stderr)
traceback.print_exc(file=sys.stderr)
......@@ -1310,7 +1308,7 @@ This dictionary is passed to :func:`~config.dictConfig` to put the configuration
}
For more information about this configuration, you can see the `relevant
section <https://docs.djangoproject.com/en/1.3/topics/logging/#configuring-logging>`_
section <https://docs.djangoproject.com/en/1.6/topics/logging/#configuring-logging>`_
of the Django documentation.
.. _cookbook-rotator-namer:
......
......@@ -901,10 +901,10 @@ provided:
disk files, rotating the log file at certain timed intervals.
#. :class:`~handlers.SocketHandler` instances send messages to TCP/IP
sockets.
sockets. Since 3.4, Unix domain sockets are also supported.
#. :class:`~handlers.DatagramHandler` instances send messages to UDP
sockets.
sockets. Since 3.4, Unix domain sockets are also supported.
#. :class:`~handlers.SMTPHandler` instances send messages to a designated
email address.
......
......@@ -271,8 +271,8 @@ performing string substitutions. ::
>>> import re
>>> p = re.compile('ab*')
>>> p #doctest: +ELLIPSIS
<_sre.SRE_Pattern object at 0x...>
>>> p
re.compile('ab*')
:func:`re.compile` also accepts an optional *flags* argument, used to enable
various special features and syntax variations. We'll go over the available
......@@ -383,8 +383,8 @@ Python interpreter, import the :mod:`re` module, and compile a RE::
>>> import re
>>> p = re.compile('[a-z]+')
>>> p #doctest: +ELLIPSIS
<_sre.SRE_Pattern object at 0x...>
>>> p
re.compile('[a-z]+')
Now, you can try matching various strings against the RE ``[a-z]+``. An empty
string shouldn't match at all, since ``+`` means 'one or more repetitions'.
......@@ -402,7 +402,7 @@ should store the result in a variable for later use. ::
>>> m = p.match('tempo')
>>> m #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(0, 5), match='tempo'>
Now you can query the :ref:`match object <match-objects>` for information
about the matching string. :ref:`match object <match-objects>` instances
......@@ -441,7 +441,7 @@ case. ::
>>> print(p.match('::: message'))
None
>>> m = p.search('::: message'); print(m) #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(4, 11), match='message'>
>>> m.group()
'message'
>>> m.span()
......@@ -493,7 +493,7 @@ the RE string added as the first argument, and still return either ``None`` or a
>>> print(re.match(r'From\s+', 'Fromage amk'))
None
>>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998') #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(0, 5), match='From '>
Under the hood, these functions simply create a pattern object for you
and call the appropriate method on it. They also store the compiled
......@@ -685,7 +685,7 @@ given location, they can obviously be matched an infinite number of times.
line, the RE to use is ``^From``. ::
>>> print(re.search('^From', 'From Here to Eternity')) #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(0, 4), match='From'>
>>> print(re.search('^From', 'Reciting From Memory'))
None
......@@ -697,11 +697,11 @@ given location, they can obviously be matched an infinite number of times.
or any location followed by a newline character. ::
>>> print(re.search('}$', '{block}')) #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(6, 7), match='}'>
>>> print(re.search('}$', '{block} '))
None
>>> print(re.search('}$', '{block}\n')) #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(6, 7), match='}'>
To match a literal ``'$'``, use ``\$`` or enclose it inside a character class,
as in ``[$]``.
......@@ -726,7 +726,7 @@ given location, they can obviously be matched an infinite number of times.
>>> p = re.compile(r'\bclass\b')
>>> print(p.search('no class at all')) #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(3, 8), match='class'>
>>> print(p.search('the declassified algorithm'))
None
>>> print(p.search('one subclass is'))
......@@ -744,7 +744,7 @@ given location, they can obviously be matched an infinite number of times.
>>> print(p.search('no class at all'))
None
>>> print(p.search('\b' + 'class' + '\b')) #doctest: +ELLIPSIS
<_sre.SRE_Match object at 0x...>
<_sre.SRE_Match object; span=(0, 7), match='\x08class\x08'>
Second, inside a character class, where there's no use for this assertion,
``\b`` represents the backspace character, for compatibility with Python's
......
......@@ -507,7 +507,7 @@ than the URL you pass to .add_password() will also match. ::
-- ``ProxyHandler`` (if a proxy setting such as an :envvar:`http_proxy`
environment variable is set), ``UnknownHandler``, ``HTTPHandler``,
``HTTPDefaultErrorHandler``, ``HTTPRedirectHandler``, ``FTPHandler``,
``FileHandler``, ``HTTPErrorProcessor``.
``FileHandler``, ``DataHandler``, ``HTTPErrorProcessor``.
``top_level_url`` is in fact *either* a full URL (including the 'http:' scheme
component and the hostname and optionally the port number)
......
#!/usr/bin/env python3
import smtplib
from email.message import EmailMessage
from email.headerregistry import Address
from email.utils import make_msgid
# Create the base text message.
msg = EmailMessage()
msg['Subject'] = "Ayons asperges pour le déjeuner"
msg['From'] = Address("Pepé Le Pew", "pepe@example.com")
msg['To'] = (Address("Penelope Pussycat", "penelope@example.com"),
Address("Fabrette Pussycat", "fabrette@example.com"))
msg.set_content("""\
Salut!
Cela ressemble à un excellent recipie[1] déjeuner.
[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718
--Pepé
""")
# Add the html version. This converts the message into a multipart/alternative
# container, with the original text message as the first part and the new html
# message as the second part.
asparagus_cid = make_msgid()
msg.add_alternative("""\
<html>
<head></head>
<body>
<p>Salut!<\p>
<p>Cela ressemble à un excellent
<a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718>
recipie
</a> déjeuner.
</p>
<img src="cid:{asparagus_cid}" \>
</body>
</html>
""".format(asparagus_cid=asparagus_cid[1:-1]), subtype='html')
# note that we needed to peel the <> off the msgid for use in the html.
# Now add the related image to the html part.
with open("roasted-asparagus.jpg", 'rb') as img:
msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg',
cid=asparagus_cid)
# Make a local copy of what we are going to send.
with open('outgoing.msg', 'wb') as f:
f.write(bytes(msg))
# Send the message via local SMTP server.
with smtplib.SMTP('localhost') as s:
s.send_message(msg)
......@@ -8,7 +8,7 @@ import smtplib
# For guessing MIME type based on file name extension
import mimetypes
from optparse import OptionParser
from argparse import ArgumentParser
from email import encoders
from email.message import Message
......@@ -22,44 +22,36 @@ COMMASPACE = ', '
def main():
parser = OptionParser(usage="""\
parser = ArgumentParser(description="""\
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
parser.add_argument('-d', '--directory',
help="""Mail the contents of the specified directory,
otherwise use the current directory. Only the regular
files in the directory are sent, and we don't recurse to
subdirectories.""")
parser.add_argument('-o', '--output',
metavar='FILE',
help="""Print the composed message to FILE instead of
sending the message to the SMTP server.""")
parser.add_argument('-s', '--sender', required=True,
help='The value of the From: header (required)')
parser.add_argument('-r', '--recipient', required=True,
action='append', metavar='RECIPIENT',
default=[], dest='recipients',
help='A To: header value (at least one required)')
args = parser.parse_args()
directory = args.directory
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['To'] = COMMASPACE.join(args.recipients)
outer['From'] = args.sender
outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'
for filename in os.listdir(directory):
......@@ -76,23 +68,19 @@ must be running an SMTP server.
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()
with open(path) as fp:
# Note: we should handle calculating the charset
msg = MIMEText(fp.read(), _subtype=subtype)
elif maintype == 'image':
fp = open(path, 'rb')
msg = MIMEImage(fp.read(), _subtype=subtype)
fp.close()
with open(path, 'rb') as fp:
msg = MIMEImage(fp.read(), _subtype=subtype)
elif maintype == 'audio':
fp = open(path, 'rb')
msg = MIMEAudio(fp.read(), _subtype=subtype)
fp.close()
with open(path, 'rb') as fp:
msg = MIMEAudio(fp.read(), _subtype=subtype)
else:
fp = open(path, 'rb')
msg = MIMEBase(maintype, subtype)
msg.set_payload(fp.read())
fp.close()
with open(path, 'rb') as fp:
msg = MIMEBase(maintype, subtype)
msg.set_payload(fp.read())
# Encode the payload using Base64
encoders.encode_base64(msg)
# Set the filename parameter
......@@ -100,14 +88,12 @@ must be running an SMTP server.
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()
if args.output:
with open(args.output, 'w') as fp:
fp.write(composed)
else:
s = smtplib.SMTP('localhost')
s.sendmail(opts.sender, opts.recipients, composed)
s.quit()
with smtplib.SMTP('localhost') as s:
s.sendmail(args.sender, args.recipients, composed)
if __name__ == '__main__':
......
import os
import sys
import tempfile
import mimetypes
import webbrowser
# Import the email modules we'll need
from email import policy
from email.parser import BytesParser
# An imaginary module that would make this work and be safe.
from imaginary import magic_html_parser
# In a real program you'd get the filename from the arguments.
msg = BytesParser(policy=policy.default).parse(open('outgoing.msg', 'rb'))
# Now the header items can be accessed as a dictionary, and any non-ASCII will
# be converted to unicode:
print('To:', msg['to'])
print('From:', msg['from'])
print('Subject:', msg['subject'])
# If we want to print a priview of the message content, we can extract whatever
# the least formatted payload is and print the first three lines. Of course,
# if the message has no plain text part printing the first three lines of html
# is probably useless, but this is just a conceptual example.
simplest = msg.get_body(preferencelist=('plain', 'html'))
print()
print(''.join(simplest.get_content().splitlines(keepends=True)[:3]))
ans = input("View full message?")
if ans.lower()[0] == 'n':
sys.exit()
# We can extract the richest alternative in order to display it:
richest = msg.get_body()
partfiles = {}
if richest['content-type'].maintype == 'text':
if richest['content-type'].subtype == 'plain':
for line in richest.get_content().splitlines():
print(line)
sys.exit()
elif richest['content-type'].subtype == 'html':
body = richest
else:
print("Don't know how to display {}".format(richest.get_content_type()))
sys.exit()
elif richest['content-type'].content_type == 'multipart/related':
body = richest.get_body(preferencelist=('html'))
for part in richest.iter_attachments():
fn = part.get_filename()
if fn:
extension = os.path.splitext(part.get_filename())[1]
else:
extension = mimetypes.guess_extension(part.get_content_type())
with tempfile.NamedTemporaryFile(suffix=extension, delete=False) as f:
f.write(part.get_content())
# again strip the <> to go from email form of cid to html form.
partfiles[part['content-id'][1:-1]] = f.name
else:
print("Don't know how to display {}".format(richest.get_content_type()))
sys.exit()
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
# The magic_html_parser has to rewrite the href="cid:...." attributes to
# point to the filenames in partfiles. It also has to do a safety-sanitize
# of the html. It could be written using html.parser.
f.write(magic_html_parser(body.get_content(), partfiles))
webbrowser.open(f.name)
os.remove(f.name)
for fn in partfiles.values():
os.remove(fn)
# Of course, there are lots of email messages that could break this simple
# minded program, but it will handle the most common ones.
......@@ -8,41 +8,27 @@ import email
import errno
import mimetypes
from optparse import OptionParser
from argparse import ArgumentParser
def main():
parser = OptionParser(usage="""\
parser = ArgumentParser(description="""\
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)
parser.add_argument('-d', '--directory', required=True,
help="""Unpack the MIME message into the named
directory, which will be created if it doesn't already
exist.""")
parser.add_argument('msgfile')
args = parser.parse_args()
try:
msgfile = args[0]
except IndexError:
parser.print_help()
sys.exit(1)
with open(args.msgfile) as fp:
msg = email.message_from_file(fp)
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()
os.mkdir(args.directory)
except FileExistsError:
pass
counter = 1
for part in msg.walk():
......@@ -59,9 +45,8 @@ Usage: %prog [options] msgfile
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()
with open(os.path.join(args.directory, filename), 'wb') as fp:
fp.write(part.get_payload(decode=True))
if __name__ == '__main__':
......
#
# Simple benchmarks for the multiprocessing package
#
# Copyright (c) 2006-2008, R Oudkerk
# All rights reserved.
#
import time
import multiprocessing
import threading
import queue
import gc
_timer = time.perf_counter
delta = 1
#### TEST_QUEUESPEED
def queuespeed_func(q, c, iterations):
a = '0' * 256
c.acquire()
c.notify()
c.release()
for i in range(iterations):
q.put(a)
q.put('STOP')
def test_queuespeed(Process, q, c):
elapsed = 0
iterations = 1
while elapsed < delta:
iterations *= 2
p = Process(target=queuespeed_func, args=(q, c, iterations))
c.acquire()
p.start()
c.wait()
c.release()
result = None
t = _timer()
while result != 'STOP':
result = q.get()
elapsed = _timer() - t
p.join()
print(iterations, 'objects passed through the queue in', elapsed, 'seconds')
print('average number/sec:', iterations/elapsed)
#### TEST_PIPESPEED
def pipe_func(c, cond, iterations):
a = '0' * 256
cond.acquire()
cond.notify()
cond.release()
for i in range(iterations):
c.send(a)
c.send('STOP')
def test_pipespeed():
c, d = multiprocessing.Pipe()
cond = multiprocessing.Condition()
elapsed = 0
iterations = 1
while elapsed < delta:
iterations *= 2
p = multiprocessing.Process(target=pipe_func,
args=(d, cond, iterations))
cond.acquire()
p.start()
cond.wait()
cond.release()
result = None
t = _timer()
while result != 'STOP':
result = c.recv()
elapsed = _timer() - t
p.join()
print(iterations, 'objects passed through connection in',elapsed,'seconds')
print('average number/sec:', iterations/elapsed)
#### TEST_SEQSPEED
def test_seqspeed(seq):
elapsed = 0
iterations = 1
while elapsed < delta:
iterations *= 2
t = _timer()
for i in range(iterations):
a = seq[5]
elapsed = _timer() - t
print(iterations, 'iterations in', elapsed, 'seconds')
print('average number/sec:', iterations/elapsed)
#### TEST_LOCK
def test_lockspeed(l):
elapsed = 0
iterations = 1
while elapsed < delta:
iterations *= 2
t = _timer()
for i in range(iterations):
l.acquire()
l.release()
elapsed = _timer() - t
print(iterations, 'iterations in', elapsed, 'seconds')
print('average number/sec:', iterations/elapsed)
#### TEST_CONDITION
def conditionspeed_func(c, N):
c.acquire()
c.notify()
for i in range(N):
c.wait()
c.notify()
c.release()
def test_conditionspeed(Process, c):
elapsed = 0
iterations = 1
while elapsed < delta:
iterations *= 2
c.acquire()
p = Process(target=conditionspeed_func, args=(c, iterations))
p.start()
c.wait()
t = _timer()
for i in range(iterations):
c.notify()
c.wait()
elapsed = _timer() - t
c.release()
p.join()
print(iterations * 2, 'waits in', elapsed, 'seconds')
print('average number/sec:', iterations * 2 / elapsed)
####
def test():
manager = multiprocessing.Manager()
gc.disable()
print('\n\t######## testing Queue.Queue\n')
test_queuespeed(threading.Thread, queue.Queue(),
threading.Condition())
print('\n\t######## testing multiprocessing.Queue\n')
test_queuespeed(multiprocessing.Process, multiprocessing.Queue(),
multiprocessing.Condition())
print('\n\t######## testing Queue managed by server process\n')
test_queuespeed(multiprocessing.Process, manager.Queue(),
manager.Condition())
print('\n\t######## testing multiprocessing.Pipe\n')
test_pipespeed()
print()
print('\n\t######## testing list\n')
test_seqspeed(list(range(10)))
print('\n\t######## testing list managed by server process\n')
test_seqspeed(manager.list(list(range(10))))
print('\n\t######## testing Array("i", ..., lock=False)\n')
test_seqspeed(multiprocessing.Array('i', list(range(10)), lock=False))
print('\n\t######## testing Array("i", ..., lock=True)\n')
test_seqspeed(multiprocessing.Array('i', list(range(10)), lock=True))
print()
print('\n\t######## testing threading.Lock\n')
test_lockspeed(threading.Lock())
print('\n\t######## testing threading.RLock\n')
test_lockspeed(threading.RLock())
print('\n\t######## testing multiprocessing.Lock\n')
test_lockspeed(multiprocessing.Lock())
print('\n\t######## testing multiprocessing.RLock\n')
test_lockspeed(multiprocessing.RLock())
print('\n\t######## testing lock managed by server process\n')
test_lockspeed(manager.Lock())
print('\n\t######## testing rlock managed by server process\n')
test_lockspeed(manager.RLock())
print()
print('\n\t######## testing threading.Condition\n')
test_conditionspeed(threading.Thread, threading.Condition())
print('\n\t######## testing multiprocessing.Condition\n')
test_conditionspeed(multiprocessing.Process, multiprocessing.Condition())
print('\n\t######## testing condition managed by a server process\n')
test_conditionspeed(multiprocessing.Process, manager.Condition())
gc.enable()
if __name__ == '__main__':
multiprocessing.freeze_support()
test()
#
# This module shows how to use arbitrary callables with a subclass of
# `BaseManager`.
#
# Copyright (c) 2006-2008, R Oudkerk
# All rights reserved.
#
from multiprocessing import freeze_support
from multiprocessing.managers import BaseManager, BaseProxy
import operator
......@@ -27,11 +19,9 @@ def baz():
# Proxy type for generator objects
class GeneratorProxy(BaseProxy):
_exposed_ = ('next', '__next__')
_exposed_ = ['__next__']
def __iter__(self):
return self
def __next__(self):
return self._callmethod('next')
def __next__(self):
return self._callmethod('__next__')
......@@ -90,8 +80,6 @@ def test():
op = manager.operator()
print('op.add(23, 45) =', op.add(23, 45))
print('op.pow(2, 94) =', op.pow(2, 94))
print('op.getslice(range(10), 2, 6) =', op.getslice(list(range(10)), 2, 6))
print('op.repeat(range(5), 3) =', op.repeat(list(range(5)), 3))
print('op._exposed_ =', op._exposed_)
##
......
#
# A test of `multiprocessing.Pool` class
#
# Copyright (c) 2006-2008, R Oudkerk
# All rights reserved.
#
import multiprocessing
import time
import random
......@@ -46,269 +39,115 @@ def noop(x):
#
def test():
print('cpu_count() = %d\n' % multiprocessing.cpu_count())
#
# Create pool
#
PROCESSES = 4
print('Creating pool with %d processes\n' % PROCESSES)
pool = multiprocessing.Pool(PROCESSES)
print('pool = %s' % pool)
print()
#
# Tests
#
TASKS = [(mul, (i, 7)) for i in range(10)] + \
[(plus, (i, 8)) for i in range(10)]
results = [pool.apply_async(calculate, t) for t in TASKS]
imap_it = pool.imap(calculatestar, TASKS)
imap_unordered_it = pool.imap_unordered(calculatestar, TASKS)
print('Ordered results using pool.apply_async():')
for r in results:
print('\t', r.get())
print()
print('Ordered results using pool.imap():')
for x in imap_it:
print('\t', x)
print()
print('Unordered results using pool.imap_unordered():')
for x in imap_unordered_it:
print('\t', x)
print()
print('Ordered results using pool.map() --- will block till complete:')
for x in pool.map(calculatestar, TASKS):
print('\t', x)
print()
#
# Simple benchmarks
#
N = 100000
print('def pow3(x): return x**3')
t = time.time()
A = list(map(pow3, range(N)))
print('\tmap(pow3, range(%d)):\n\t\t%s seconds' % \
(N, time.time() - t))
with multiprocessing.Pool(PROCESSES) as pool:
#
# Tests
#
t = time.time()
B = pool.map(pow3, range(N))
print('\tpool.map(pow3, range(%d)):\n\t\t%s seconds' % \
(N, time.time() - t))
TASKS = [(mul, (i, 7)) for i in range(10)] + \
[(plus, (i, 8)) for i in range(10)]
t = time.time()
C = list(pool.imap(pow3, range(N), chunksize=N//8))
print('\tlist(pool.imap(pow3, range(%d), chunksize=%d)):\n\t\t%s' \
' seconds' % (N, N//8, time.time() - t))
results = [pool.apply_async(calculate, t) for t in TASKS]
imap_it = pool.imap(calculatestar, TASKS)
imap_unordered_it = pool.imap_unordered(calculatestar, TASKS)
assert A == B == C, (len(A), len(B), len(C))
print()
print('Ordered results using pool.apply_async():')
for r in results:
print('\t', r.get())
print()
L = [None] * 1000000
print('def noop(x): pass')
print('L = [None] * 1000000')
print('Ordered results using pool.imap():')
for x in imap_it:
print('\t', x)
print()
t = time.time()
A = list(map(noop, L))
print('\tmap(noop, L):\n\t\t%s seconds' % \
(time.time() - t))
print('Unordered results using pool.imap_unordered():')
for x in imap_unordered_it:
print('\t', x)
print()
t = time.time()
B = pool.map(noop, L)
print('\tpool.map(noop, L):\n\t\t%s seconds' % \
(time.time() - t))
print('Ordered results using pool.map() --- will block till complete:')
for x in pool.map(calculatestar, TASKS):
print('\t', x)
print()
t = time.time()
C = list(pool.imap(noop, L, chunksize=len(L)//8))
print('\tlist(pool.imap(noop, L, chunksize=%d)):\n\t\t%s seconds' % \
(len(L)//8, time.time() - t))
#
# Test error handling
#
assert A == B == C, (len(A), len(B), len(C))
print()
print('Testing error handling:')
del A, B, C, L
#
# Test error handling
#
print('Testing error handling:')
try:
print(pool.apply(f, (5,)))
except ZeroDivisionError:
print('\tGot ZeroDivisionError as expected from pool.apply()')
else:
raise AssertionError('expected ZeroDivisionError')
try:
print(pool.map(f, list(range(10))))
except ZeroDivisionError:
print('\tGot ZeroDivisionError as expected from pool.map()')
else:
raise AssertionError('expected ZeroDivisionError')
try:
print(list(pool.imap(f, list(range(10)))))
except ZeroDivisionError:
print('\tGot ZeroDivisionError as expected from list(pool.imap())')
else:
raise AssertionError('expected ZeroDivisionError')
it = pool.imap(f, list(range(10)))
for i in range(10):
try:
x = next(it)
print(pool.apply(f, (5,)))
except ZeroDivisionError:
if i == 5:
pass
except StopIteration:
break
print('\tGot ZeroDivisionError as expected from pool.apply()')
else:
if i == 5:
raise AssertionError('expected ZeroDivisionError')
assert i == 9
print('\tGot ZeroDivisionError as expected from IMapIterator.next()')
print()
raise AssertionError('expected ZeroDivisionError')
#
# Testing timeouts
#
print('Testing ApplyResult.get() with timeout:', end=' ')
res = pool.apply_async(calculate, TASKS[0])
while 1:
sys.stdout.flush()
try:
sys.stdout.write('\n\t%s' % res.get(0.02))
break
except multiprocessing.TimeoutError:
sys.stdout.write('.')
print()
print()
print(pool.map(f, list(range(10))))
except ZeroDivisionError:
print('\tGot ZeroDivisionError as expected from pool.map()')
else:
raise AssertionError('expected ZeroDivisionError')
print('Testing IMapIterator.next() with timeout:', end=' ')
it = pool.imap(calculatestar, TASKS)
while 1:
sys.stdout.flush()
try:
sys.stdout.write('\n\t%s' % it.next(0.02))
except StopIteration:
break
except multiprocessing.TimeoutError:
sys.stdout.write('.')
print()
print()
#
# Testing callback
#
print('Testing callback:')
A = []
B = [56, 0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
r = pool.apply_async(mul, (7, 8), callback=A.append)
r.wait()
r = pool.map_async(pow3, list(range(10)), callback=A.extend)
r.wait()
if A == B:
print('\tcallbacks succeeded\n')
else:
print('\t*** callbacks failed\n\t\t%s != %s\n' % (A, B))
#
# Check there are no outstanding tasks
#
assert not pool._cache, 'cache = %r' % pool._cache
#
# Check close() methods
#
print('Testing close():')
for worker in pool._pool:
assert worker.is_alive()
result = pool.apply_async(time.sleep, [0.5])
pool.close()
pool.join()
assert result.get() is None
for worker in pool._pool:
assert not worker.is_alive()
print('\tclose() succeeded\n')
#
# Check terminate() method
#
print('Testing terminate():')
pool = multiprocessing.Pool(2)
DELTA = 0.1
ignore = pool.apply(pow3, [2])
results = [pool.apply_async(time.sleep, [DELTA]) for i in range(100)]
pool.terminate()
pool.join()
for worker in pool._pool:
assert not worker.is_alive()
print('\tterminate() succeeded\n')
#
# Check garbage collection
#
print('Testing garbage collection:')
pool = multiprocessing.Pool(2)
DELTA = 0.1
processes = pool._pool
ignore = pool.apply(pow3, [2])
results = [pool.apply_async(time.sleep, [DELTA]) for i in range(100)]
results = pool = None
time.sleep(DELTA * 2)
for worker in processes:
assert not worker.is_alive()
print('\tgarbage collection succeeded\n')
print(list(pool.imap(f, list(range(10)))))
except ZeroDivisionError:
print('\tGot ZeroDivisionError as expected from list(pool.imap())')
else:
raise AssertionError('expected ZeroDivisionError')
it = pool.imap(f, list(range(10)))
for i in range(10):
try:
x = next(it)
except ZeroDivisionError:
if i == 5:
pass
except StopIteration:
break
else:
if i == 5:
raise AssertionError('expected ZeroDivisionError')
assert i == 9
print('\tGot ZeroDivisionError as expected from IMapIterator.next()')
print()
#
# Testing timeouts
#
print('Testing ApplyResult.get() with timeout:', end=' ')
res = pool.apply_async(calculate, TASKS[0])
while 1:
sys.stdout.flush()
try:
sys.stdout.write('\n\t%s' % res.get(0.02))
break
except multiprocessing.TimeoutError:
sys.stdout.write('.')
print()
print()
print('Testing IMapIterator.next() with timeout:', end=' ')
it = pool.imap(calculatestar, TASKS)
while 1:
sys.stdout.flush()
try:
sys.stdout.write('\n\t%s' % it.next(0.02))
except StopIteration:
break
except multiprocessing.TimeoutError:
sys.stdout.write('.')
print()
print()
if __name__ == '__main__':
multiprocessing.freeze_support()
assert len(sys.argv) in (1, 2)
if len(sys.argv) == 1 or sys.argv[1] == 'processes':
print(' Using processes '.center(79, '-'))
elif sys.argv[1] == 'threads':
print(' Using threads '.center(79, '-'))
import multiprocessing.dummy as multiprocessing
else:
print('Usage:\n\t%s [processes | threads]' % sys.argv[0])
raise SystemExit(2)
test()
#
# A test file for the `multiprocessing` package
#
# Copyright (c) 2006-2008, R Oudkerk
# All rights reserved.
#
import time
import sys
import random
from queue import Empty
import multiprocessing # may get overwritten
#### TEST_VALUE
def value_func(running, mutex):
random.seed()
time.sleep(random.random()*4)
mutex.acquire()
print('\n\t\t\t' + str(multiprocessing.current_process()) + ' has finished')
running.value -= 1
mutex.release()
def test_value():
TASKS = 10
running = multiprocessing.Value('i', TASKS)
mutex = multiprocessing.Lock()
for i in range(TASKS):
p = multiprocessing.Process(target=value_func, args=(running, mutex))
p.start()
while running.value > 0:
time.sleep(0.08)
mutex.acquire()
print(running.value, end=' ')
sys.stdout.flush()
mutex.release()
print()
print('No more running processes')
#### TEST_QUEUE
def queue_func(queue):
for i in range(30):
time.sleep(0.5 * random.random())
queue.put(i*i)
queue.put('STOP')
def test_queue():
q = multiprocessing.Queue()
p = multiprocessing.Process(target=queue_func, args=(q,))
p.start()
o = None
while o != 'STOP':
try:
o = q.get(timeout=0.3)
print(o, end=' ')
sys.stdout.flush()
except Empty:
print('TIMEOUT')
print()
#### TEST_CONDITION
def condition_func(cond):
cond.acquire()
print('\t' + str(cond))
time.sleep(2)
print('\tchild is notifying')
print('\t' + str(cond))
cond.notify()
cond.release()
def test_condition():
cond = multiprocessing.Condition()
p = multiprocessing.Process(target=condition_func, args=(cond,))
print(cond)
cond.acquire()
print(cond)
cond.acquire()
print(cond)
p.start()
print('main is waiting')
cond.wait()
print('main has woken up')
print(cond)
cond.release()
print(cond)
cond.release()
p.join()
print(cond)
#### TEST_SEMAPHORE
def semaphore_func(sema, mutex, running):
sema.acquire()
mutex.acquire()
running.value += 1
print(running.value, 'tasks are running')
mutex.release()
random.seed()
time.sleep(random.random()*2)
mutex.acquire()
running.value -= 1
print('%s has finished' % multiprocessing.current_process())
mutex.release()
sema.release()
def test_semaphore():
sema = multiprocessing.Semaphore(3)
mutex = multiprocessing.RLock()
running = multiprocessing.Value('i', 0)
processes = [
multiprocessing.Process(target=semaphore_func,
args=(sema, mutex, running))
for i in range(10)
]
for p in processes:
p.start()
for p in processes:
p.join()
#### TEST_JOIN_TIMEOUT
def join_timeout_func():
print('\tchild sleeping')
time.sleep(5.5)
print('\n\tchild terminating')
def test_join_timeout():
p = multiprocessing.Process(target=join_timeout_func)
p.start()
print('waiting for process to finish')
while 1:
p.join(timeout=1)
if not p.is_alive():
break
print('.', end=' ')
sys.stdout.flush()
#### TEST_EVENT
def event_func(event):
print('\t%r is waiting' % multiprocessing.current_process())
event.wait()
print('\t%r has woken up' % multiprocessing.current_process())
def test_event():
event = multiprocessing.Event()
processes = [multiprocessing.Process(target=event_func, args=(event,))
for i in range(5)]
for p in processes:
p.start()
print('main is sleeping')
time.sleep(2)
print('main is setting event')
event.set()
for p in processes:
p.join()
#### TEST_SHAREDVALUES
def sharedvalues_func(values, arrays, shared_values, shared_arrays):
for i in range(len(values)):
v = values[i][1]
sv = shared_values[i].value
assert v == sv
for i in range(len(values)):
a = arrays[i][1]
sa = list(shared_arrays[i][:])
assert a == sa
print('Tests passed')
def test_sharedvalues():
values = [
('i', 10),
('h', -2),
('d', 1.25)
]
arrays = [
('i', list(range(100))),
('d', [0.25 * i for i in range(100)]),
('H', list(range(1000)))
]
shared_values = [multiprocessing.Value(id, v) for id, v in values]
shared_arrays = [multiprocessing.Array(id, a) for id, a in arrays]
p = multiprocessing.Process(
target=sharedvalues_func,
args=(values, arrays, shared_values, shared_arrays)
)
p.start()
p.join()
assert p.exitcode == 0
####
def test(namespace=multiprocessing):
global multiprocessing
multiprocessing = namespace
for func in [test_value, test_queue, test_condition,
test_semaphore, test_join_timeout, test_event,
test_sharedvalues]:
print('\n\t######## %s\n' % func.__name__)
func()
ignore = multiprocessing.active_children() # cleanup any old processes
if hasattr(multiprocessing, '_debug_info'):
info = multiprocessing._debug_info()
if info:
print(info)
raise ValueError('there should be no positive refcounts left')
if __name__ == '__main__':
multiprocessing.freeze_support()
assert len(sys.argv) in (1, 2)
if len(sys.argv) == 1 or sys.argv[1] == 'processes':
print(' Using processes '.center(79, '-'))
namespace = multiprocessing
elif sys.argv[1] == 'manager':
print(' Using processes and a manager '.center(79, '-'))
namespace = multiprocessing.Manager()
namespace.Process = multiprocessing.Process
namespace.current_process = multiprocessing.current_process
namespace.active_children = multiprocessing.active_children
elif sys.argv[1] == 'threads':
print(' Using threads '.center(79, '-'))
import multiprocessing.dummy as namespace
else:
print('Usage:\n\t%s [processes | manager | threads]' % sys.argv[0])
raise SystemExit(2)
test(namespace)
#
# Example where a pool of http servers share a single listening socket
#
# On Windows this module depends on the ability to pickle a socket
# object so that the worker processes can inherit a copy of the server
# object. (We import `multiprocessing.reduction` to enable this pickling.)
#
# Not sure if we should synchronize access to `socket.accept()` method by
# using a process-shared lock -- does not seem to be necessary.
#
# Copyright (c) 2006-2008, R Oudkerk
# All rights reserved.
#
import os
import sys
from multiprocessing import Process, current_process, freeze_support
from http.server import HTTPServer
from http.server import SimpleHTTPRequestHandler
if sys.platform == 'win32':
import multiprocessing.reduction # make sockets pickable/inheritable
def note(format, *args):
sys.stderr.write('[%s]\t%s\n' % (current_process().name, format % args))
class RequestHandler(SimpleHTTPRequestHandler):
# we override log_message() to show which process is handling the request
def log_message(self, format, *args):
note(format, *args)
def serve_forever(server):
note('starting server')
try:
server.serve_forever()
except KeyboardInterrupt:
pass
def runpool(address, number_of_processes):
# create a single server object -- children will each inherit a copy
server = HTTPServer(address, RequestHandler)
# create child processes to act as workers
for i in range(number_of_processes - 1):
Process(target=serve_forever, args=(server,)).start()
# main process also acts as a worker
serve_forever(server)
def test():
DIR = os.path.join(os.path.dirname(__file__), '..')
ADDRESS = ('localhost', 8000)
NUMBER_OF_PROCESSES = 4
print('Serving at http://%s:%d using %d worker processes' % \
(ADDRESS[0], ADDRESS[1], NUMBER_OF_PROCESSES))
print('To exit press Ctrl-' + ['C', 'Break'][sys.platform=='win32'])
os.chdir(DIR)
runpool(ADDRESS, NUMBER_OF_PROCESSES)
if __name__ == '__main__':
freeze_support()
test()
This diff is collapsed.
......@@ -70,4 +70,11 @@ typedef struct _typeobject {
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
destructor tp_finalize;
} PyTypeObject;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment