From python-checkins at python.org Sun Feb 1 04:06:09 2015 From: python-checkins at python.org (nick.coghlan) Date: Sun, 01 Feb 2015 03:06:09 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_462_now_proposes_Kallithe?= =?utf-8?q?a_as_the_review_component?= Message-ID: <20150201030551.39290.76025@psf.io> https://hg.python.org/peps/rev/33f7f6d4fcb9 changeset: 5683:33f7f6d4fcb9 user: Nick Coghlan date: Sun Feb 01 12:59:34 2015 +1000 summary: PEP 462 now proposes Kallithea as the review component files: pep-0462.txt | 188 ++++++++++++++++++++------------------ pep-0474.txt | 57 +++++++++++- 2 files changed, 157 insertions(+), 88 deletions(-) diff --git a/pep-0462.txt b/pep-0462.txt --- a/pep-0462.txt +++ b/pep-0462.txt @@ -8,7 +8,7 @@ Content-Type: text/x-rst Requires: 474 Created: 23-Jan-2014 -Post-History: 25-Jan-2014, 27-Jan-2014 +Post-History: 25-Jan-2014, 27-Jan-2014, 01-Feb-2015 Abstract @@ -26,8 +26,8 @@ PEP Deferral ============ -This PEP is currently deferred pending updates to redesign it around -the proposal in PEP 474 to create a Kallithea-based forge.python.org service. +This PEP is currently deferred pending acceptance or rejection of the +Kallithea-based forge.python.org proposal in PEP 474. Rationale for changes to the core development workflow @@ -139,9 +139,11 @@ * For core developers, the branch wrangling for bug fixes is delicate and easy to get wrong. Conflicts on the NEWS file and push races when attempting to upload changes add to the irritation of something most of - us aren't being paid to spend time on. The time we spend actually getting - a change merged is time we're not spending coding additional changes, - writing or updating documentation or reviewing contributions from others. + us aren't being paid to spend time on (and for those that are, contributing + to CPython is likely to be only one of our responsibilities). The time we + spend actually getting a change merged is time we're not spending coding + additional changes, writing or updating documentation or reviewing + contributions from others. * Red buildbots make life difficult for other developers (since a local test failure may *not* be due to anything that developer did), release managers (since they may need to enlist assistance cleaning up test @@ -172,13 +174,17 @@ * Rietveld (also hosted on bugs.python.org) for code review * Buildbot (buildbot.python.org) for automated testing -This proposal does *not* currently suggest replacing any of these tools, -although implementing it effectively may require modifications to some or -all of them. +This proposal suggests replacing the use of Rietveld for code review with +the more full-featured Kallithea-based forge.python.org service proposed in +PEP 474. Guido has indicated that the original Rietveld implementation was +primarily intended as a public demonstration application for Google App +Engine, and switching to Kallithea will address some of the issues with +identifying intended target branches that arise when working with patch files +on Roundup and the associated reviews in the integrated Rietveld instance. -It does however suggest the addition of new tools in order to automate -additional parts of the workflow, as well as a critical review of these -tools to see which, if any, may be candidates for replacement. +It also suggests the addition of new tools in order to automate +additional parts of the workflow, as well as a critical review of the +remaining tools to see which, if any, may be candidates for replacement. Proposal @@ -224,12 +230,12 @@ the queue, and rebuilds the queue without the failing patch. If a developer looks at a test which failed on merge and determines that it -was due to an intermittent failure, then they can resubmit the patch for +was due to an intermittent failure, they can then resubmit the patch for another attempt at merging. To adapt this process to CPython, it should be feasible to have Zuul monitor -Rietveld for approved patches (which would require a feature addition in -Rietveld), submit them to Buildbot for testing on the stable buildbots, and +Kallithea for approved pull requests (which may require a feature addition in +Kallithea), submit them to Buildbot for testing on the stable buildbots, and then merge the changes appropriately in Mercurial. This idea poses a few technical challenges, which have their own section below. @@ -280,7 +286,7 @@ still allowing the rest of the automation flows to be worked out (such as how to push a patch into the merge queue). -The one downside to this approach is that Zuul wouldn't have complete +The key downside to this approach is that Zuul wouldn't have complete control of the merge process as it usually expects, so there would potentially be additional coordination needed around that. @@ -288,14 +294,15 @@ deployment proves to have more trouble with test reliability than is anticipated. -It would also be possible to tweak the merge gating criteria such that it doesn't -run the test suite if it detects that the patch hasn't modified any files -outside the "Docs" tree, and instead only checks that the documentation +It would also be possible to tweak the merge gating criteria such that it +doesn't run the test suite if it detects that the patch hasn't modified any +files outside the "Docs" tree, and instead only checks that the documentation builds without errors. As yet another alternative, it may be reasonable to move some parts of the -documentation (such as the tutorial) out of the main source repository and -manage them using the simpler pull request based model. +documentation (such as the tutorial and the HOWTO guides) out of the main +source repository and manage them using the simpler pull request based model +described in PEP 474. Perceived Benefits @@ -346,10 +353,11 @@ Finally, a more stable default branch in CPython makes it easier for other Python projects to conduct continuous integration directly against the main repo, rather than having to wait until we get into the release -candidate phase. At the moment, setting up such a system isn't particularly -attractive, as it would need to include an additional mechanism to wait -until CPython's own Buildbot fleet had indicate that the build was in a -usable state. +candidate phase of a new release. At the moment, setting up such a system +isn't particularly attractive, as it would need to include an additional +mechanism to wait until CPython's own Buildbot fleet indicated that the +build was in a usable state. With the proposed merge gating system, the +trunk always remains usable. Technical Challenges @@ -361,20 +369,17 @@ in some of our existing tools. -Rietveld/Roundup vs Gerrit --------------------------- +Kallithea vs Gerrit +------------------- -Rietveld does not currently include a voting/approval feature that is +Kallithea does not currently include a voting/approval feature that is equivalent to Gerrit's. For CPython, we wouldn't need anything as sophisticated as Gerrit's voting system - a simple core-developer-only "Approved" marker to trigger action from Zuul should suffice. The core-developer-or-not flag is available in Roundup, as is the flag indicating whether or not the uploader of a patch has signed a PSF -Contributor Licensing Agreement, which may require further additions to -the existing integration between the two tools. - -Rietveld may also require some changes to allow the uploader of a patch -to indicate which branch it is intended for. +Contributor Licensing Agreement, which may require further development to +link contributor accounts between the Kallithea instance and Roundup. We would likely also want to improve the existing patch handling, in particular looking at how the Roundup/Reitveld integration handles cases @@ -386,29 +391,33 @@ Some of the existing Zuul triggers work by monitoring for particular comments (in particular, recheck/reverify comments to ask Zuul to try merging a change again if it was previously rejected due to an unrelated intermittent -failure). We will likely also want similar explicit triggers for Rietveld. +failure). We will likely also want similar explicit triggers for Kallithea. The current Zuul plugins for Gerrit work by monitoring the Gerrit activity -stream for particular events. If Rietveld has no equivalent, we will need +stream for particular events. If Kallithea has no equivalent, we will need to add something suitable for the events we would like to trigger on. There would also be development effort needed to create a Zuul plugin -that monitors Rietveld activity rather than Gerrit. +that monitors Kallithea activity rather than Gerrit. Mercurial vs Gerrit/git ----------------------- Gerrit uses git as the actual storage mechanism for patches, and -automatically handles merging of approved patches. By contrast, Rietveld -works directly on patches, and is completely decoupled from any specific -version control system. +automatically handles merging of approved patches. By contrast, Kallithea +use the RhodeCode created `vcs ` library as +an abstraction layer over specific DVCS implementations (with Mercurial and +git backends currently available). Zuul is also directly integrated with git for patch manipulation - as far -as I am aware, this part of the design isn't pluggable. However, at PyCon -US 2014, the Mercurial core developers at the sprints expressed some -interest in collaborating with the core development team and the Zuul +as I am aware, this part of the design currently isn't pluggable. However, +at PyCon US 2014, the Mercurial core developers at the sprints expressed +some interest in collaborating with the core development team and the Zuul developers on enabling the use of Zuul with Mercurial in addition to git. +As Zuul is itself a Python application, migrating it to use the same DVCS +abstraction library as RhodeCode and Kallithea may be a viable path towards +achieving that. Buildbot vs Jenkins @@ -463,27 +472,28 @@ maintenance branches. Python 2.7 can be handled easily enough by treating it as a separate patch -queue. This would just require a change in Rietveld to indicate which -branch was the intended target of the patch. +queue. This would be handled natively in Kallithea by submitting separate +pull requests in order to update the Python 2.7 maintenance branch. The Python 3.x maintenance branches are potentially more complicated. My current recommendation is to simply stop using Mercurial merges to manage them, and instead treat them as independent heads, similar to the Python -2.7 branch. Patches that apply cleanly to both the active maintenance branch -and to default would then just be submitted to both queues, while other -changes might involve submitting separate patches for the active maintenance -branch and for default. This approach also has the benefit of adjusting -cleanly to the intermittent periods where we have two active Python 3 -maintenance branches. +2.7 branch. Separate pull requests would need to be submitted for the active +Python 3 maintenance branch and the default development branch. The +downside of this approach is that it increases the risk that a fix is merged +only to the maintenance branch without also being submitted to the default +branch, so we may want to design some additional tooling that ensures that +every maintenance branch pull request either has a corresponding default +branch pull request prior to being merged, or else has an explicit disclaimer +indicating that it is only applicable to that branch and doesn't need to be +ported forward to later branches. -This does suggest some user interface ideas for the branch nomination -interface for a patch: +Such an approach has the benefit of adjusting relatively cleanly to the +intermittent periods where we have two active Python 3 maintenance branches. -* default to "default" on issues that are marked as "enhancement" -* default to "3.x+" (where 3.x is the oldest branch in regular maintenance) - on any other issues -* also offer the ability to select specific branches in addition to or - instead of the default selection +This issue does suggest some potential user interface ideas for Kallithea, +where it may be desirable to be able to clone a pull request in order to be +able to apply it to a second branch. Handling of security branches @@ -491,7 +501,10 @@ For simplicity's sake, I would suggest leaving the handling of security-fix only branches alone: the release managers for those branches -would continue to backport specific changes manually. +would continue to backport specific changes manually. The only change is +that they would be able to use the Kallithea pull request workflow to do the +backports if they would like others to review the updates prior to merging +them. Handling of NEWS file updates @@ -510,9 +523,9 @@ ------------------------------------- Instability of the nominally stable buildbots has a substantially larger -impact under this proposal. We would need to ensure we're happy with each -of those systems gating merges to the development branches, or else move -then to "unstable" status. +impact under this proposal. We would need to ensure we're genuinely happy +with each of those systems gating merges to the development branches, or +else move then to "unstable" status. Intermittent test failures @@ -535,29 +548,20 @@ hence likely even more amenable to automated analysis. -Enhancing Mercurial/Rietveld/Roundup integration ------------------------------------------------- +Custom Mercurial client workflow support +---------------------------------------- One useful part of the OpenStack workflow is the "git review" plugin, which makes it relatively easy to push a branch from a local git clone up to Gerrit for review. -It seems that it should be possible to create a plugin that similarly -integrates Mercurial queues with Rietveld and Roundup, allowing a draft -patch to be uploaded as easily as running a command like "hg qpost" with a -suitable .hgqpost configuration file checked in to the source repo. +PEP 474 mentions a draft `custom Mercurial +extension `__ +that automates some aspects of the existing CPython core development workflow. -(There's an existing `hg review `__, -plugin hence the suggestion of ``hg qpost`` as an alternate command) - -It would also be good to work directly with the Mercurial folks to come up -with a tailored CPython-specific tutorial for using Mercurial queues and -other extensions to work effectively with the CPython repository structure. -We have some of that already in the developer guide, but I've come to believe -that we may want to start getting more opinionated as to which extensions -we recommend using, especially for users that have previously learned -``git`` and need to know which extensions to enable to gain a similar level -of flexibility in their local workflow from Mercurial. +As part of this proposal, that custom extension would be extended to work +with the new Kallithea based review workflow in addition to the legacy +Roundup/Rietveld based review workflow. Social Challenges @@ -604,9 +608,9 @@ `__ rather than in a PEP). Accordingly, proposals that involve setting ourselves up for "SourceForge -usability and reliability issues, round two" aren't likely to gain any -traction with either the CPython core development team or with the PSF -Infrastructure committee. This proposal respects that history by +usability and reliability issues, round two" will face significant +opposition from at least some members of the CPython core development team +(including the author of this PEP). This proposal respects that history by recommending only tools that are available for self-hosting as sponsored or PSF funded infrastructure, and are also open source Python projects that can be customised to meet the needs of the CPython core development team. @@ -665,8 +669,9 @@ ============== Pretty much everything in the PEP. Do we want to adopt merge gating and -Zuul? Is Rietveld the right place to hook Zuul into our current workflows? -How do we want to address the various technical challenges? +Zuul? How do we want to address the various technical challenges? +Are the Kallithea and Zuul development communities open to the kind +of collaboration that would be needed to make this effort a success? Assuming we do want to do it (or something like it), how is the work going to get done? Do we try to get it done solely as a volunteer effort? Do we @@ -678,14 +683,18 @@ OpenStack infrastructure team, and the available development resources for OpenStack currently dwarf those for CPython? +Do those of us working for Python redistributors and major users (including +me), attempt to make the business case to our superiors for investing +developer time in supporting this effort? + Next Steps ========== -Unfortunately, we ran out of time at the PyCon 2014 language summit to really -discuss these issues. However, the `core-workflow mailing list -`__ has now been set -up to discuss workflow issues in general. +If pursued, this will be a follow-on project to the Kallithea-based +forge.python.org proposal in PEP 474. Refer to that PEP for more details +on the discussion, review and proof-of-concept pilot process currently +under way. Acknowledgements @@ -696,6 +705,11 @@ Taylor for additional technical feedback following publication of the initial draft. +Thanks to Bradley Kuhn, Mads Kiellerich and other Kallithea developers for +the discussions around PEP 474 that led to a significant revision of this +proposal to be based on using Kallithea for the review component rather than +the existing Rietveld installation. + Copyright ========= diff --git a/pep-0474.txt b/pep-0474.txt --- a/pep-0474.txt +++ b/pep-0474.txt @@ -7,7 +7,7 @@ Type: Process Content-Type: text/x-rst Created: 19-Jul-2014 -Post-History: 19-Jul-2014, 08-Jan-2015 +Post-History: 19-Jul-2014, 08-Jan-2015, 01-Feb-2015 Abstract @@ -287,6 +287,61 @@ forge.python.org hosted Mercurial repositories. +Pilot Objectives and Timeline +============================= + +This proposal is part of Brett Cannon's `current evaluation +`__ +of improvement proposals for various aspects of the CPython development +workflow. Key dates in that timeline are: + +* Feb 1: Draft proposal published (for Kallithea, this PEP) +* Apr 8: Discussion of final proposals at Python Language Summit +* May 1: Brett's decision on which proposal to accept +* Sep 13: Python 3.5 released, adopting new workflows for Python 3.6 + +Prior to the April 8 discussion, it is proposed to have the following aspects +of this PEP completed: + +* a reference implementation operational at kallithea-pilot.python.org, + containing at least the developer guide and PEP repositories. This will + be a "throwaway" instance, allowing core developers and other contributors + to experiement freely without worrying about the long term consequences for + the repository history. +* read-only live mirrors of the Kallithea hosted repositories on GitHub and + BitBucket. As with the pilot service itself, these would be temporary repos, + to be discarded after the pilot period ends. +* clear documentation on using those mirrors to create pull requests against + Kallithea hosted Mercurial repositories (for the pilot, this will likely + *not* include using the native pull request workflows of those hosted + services) +* automatic linking of issue references in code review comments and commit + messages to the corresponding issues on bugs.python.org +* draft updates to PEP 1 explaining the Kallithea based PEP editing and + submission workflow + +The following items would be needed for a production migration, but there +doesn't appear to be an obvious way to trial an updated implementation as +part of the pilot: + +* adjusting the PEP publication process and the developer guide publication + process to be based on the relocated Mercurial repos + +The following items would be objectives of the overall workflow improvement +process, but may not be completed before the Python Language summit, and are +also considered "desirable, but not essential" for the initial adoption of +the new service in September (if this proposal is the one selected): + +* allowing the use of python-social-auth to authenticate against the PSF + hosted Kallithea instance +* allowing the use of the GitHub and BitBucket pull request workflows to + submit pull requests to the main Kallithea repo +* allowing easy triggering of forced BuildBot runs based on Kallithea hosted + repos and pull requests (prior to the implementation of PEP 462, this + would be intended for use with sandbox repos rather than the main CPython + repo) + + Future Implications for CPython Core Development ================================================ -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Feb 1 06:57:26 2015 From: python-checkins at python.org (nick.coghlan) Date: Sun, 01 Feb 2015 05:57:26 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_477_was_implemented_for_2?= =?utf-8?q?=2E7=2E9?= Message-ID: <20150201055721.25863.27054@psf.io> https://hg.python.org/peps/rev/ca51fb69dbb7 changeset: 5684:ca51fb69dbb7 user: Nick Coghlan date: Sun Feb 01 15:57:13 2015 +1000 summary: PEP 477 was implemented for 2.7.9 files: pep-0477.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0477.txt b/pep-0477.txt --- a/pep-0477.txt +++ b/pep-0477.txt @@ -5,7 +5,7 @@ Author: Donald Stufft Nick Coghlan BDFL-Delegate: Benjamin Peterson -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 26-Aug-2014 -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Feb 1 06:59:50 2015 From: python-checkins at python.org (nick.coghlan) Date: Sun, 01 Feb 2015 05:59:50 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_461_has_been_implemented_?= =?utf-8?q?for_3=2E5?= Message-ID: <20150201055949.96068.65696@psf.io> https://hg.python.org/peps/rev/7fdec54e0566 changeset: 5685:7fdec54e0566 user: Nick Coghlan date: Sun Feb 01 15:59:42 2015 +1000 summary: PEP 461 has been implemented for 3.5 files: pep-0461.txt | 2 +- pep-0478.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt --- a/pep-0461.txt +++ b/pep-0461.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Ethan Furman -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 2014-01-13 diff --git a/pep-0478.txt b/pep-0478.txt --- a/pep-0478.txt +++ b/pep-0478.txt @@ -58,10 +58,10 @@ Implemented / Final PEPs: * PEP 465, a new matrix multiplication operator +* PEP 461, %-formatting for binary strings Accepted PEPs: -* PEP 461, %-formatting for binary strings * PEP 471, os.scandir() Proposed changes for 3.5: -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Sun Feb 1 09:19:34 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 01 Feb 2015 09:19:34 +0100 Subject: [Python-checkins] Daily reference leaks (469ff344f8fd): sum=3 Message-ID: results for 469ff344f8fd on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogTyMukx', '-x'] From python-checkins at python.org Sun Feb 1 14:55:34 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 13:55:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322445=3A_PyBuffer?= =?utf-8?q?=5FIsContiguous=28=29_now_implements_precise_contiguity?= Message-ID: <20150201135424.25869.75411@psf.io> https://hg.python.org/cpython/rev/369300948f3f changeset: 94423:369300948f3f user: Stefan Krah date: Sun Feb 01 14:53:54 2015 +0100 summary: Issue #22445: PyBuffer_IsContiguous() now implements precise contiguity tests, compatible with NumPy's NPY_RELAXED_STRIDES_CHECKING compilation flag. Previously the function reported false negatives for corner cases. files: Lib/test/test_buffer.py | 13 ++++++ Misc/NEWS | 4 ++ Modules/_testbuffer.c | 55 +++++++++++++++++++--------- Objects/abstract.c | 49 +++++++++++++++++++------ 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -1007,6 +1007,7 @@ # shape, strides, offset structure = ( ([], [], 0), + ([1,3,1], [], 0), ([12], [], 0), ([12], [-1], 11), ([6], [2], 0), @@ -1078,6 +1079,18 @@ self.assertRaises(BufferError, ndarray, ex, getbuf=PyBUF_ANY_CONTIGUOUS) nd = ndarray(ex, getbuf=PyBUF_SIMPLE) + # Issue #22445: New precise contiguity definition. + for shape in [1,12,1], [7,0,7]: + for order in 0, ND_FORTRAN: + ex = ndarray(items, shape=shape, flags=order|ND_WRITABLE) + self.assertTrue(is_contiguous(ex, 'F')) + self.assertTrue(is_contiguous(ex, 'C')) + + for flags in requests: + nd = ndarray(ex, getbuf=flags) + self.assertTrue(is_contiguous(nd, 'F')) + self.assertTrue(is_contiguous(nd, 'C')) + def test_ndarray_exceptions(self): nd = ndarray([9], [1]) ndm = ndarray([9], [1], flags=ND_VAREXPORT) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1531,6 +1531,10 @@ C API ----- +- Issue #22445: PyBuffer_IsContiguous() now implements precise contiguity + tests, compatible with NumPy's NPY_RELAXED_STRIDES_CHECKING compilation + flag. Previously the function reported false negatives for corner cases. + - Issue #22079: PyType_Ready() now checks that statically allocated type has no dynamically allocated bases. diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -1510,6 +1510,19 @@ view->shape = NULL; } + /* Ascertain that the new buffer has the same contiguity as the exporter */ + if (ND_C_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'C') || + /* skip cast to 1-d */ + (view->format != NULL && view->shape != NULL && + ND_FORTRAN_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'F')) || + /* cast to 1-d */ + (view->format == NULL && view->shape == NULL && + !PyBuffer_IsContiguous(view, 'F'))) { + PyErr_SetString(PyExc_BufferError, + "ndarray: contiguity mismatch in getbuf()"); + return -1; + } + view->obj = (PyObject *)self; Py_INCREF(view->obj); self->head->exports++; @@ -2206,6 +2219,8 @@ for (i = 0; i < base->ndim; i++) base->suboffsets[i] = -1; + nd->head->flags &= ~(ND_C|ND_FORTRAN); + Py_RETURN_NONE; } @@ -2469,13 +2484,12 @@ { Py_ssize_t i; - if (ndim == 1 && shape && shape[0] == 1) { - /* This is for comparing strides: For example, the array - [175], shape=[1], strides=[-5] is considered contiguous. */ - return 1; - } for (i = 0; i < ndim; i++) { + if (shape && shape[i] <= 1) { + /* strides can differ if the dimension is less than 2 */ + continue; + } if (a1[i] != a2[i]) { return 0; } @@ -2555,30 +2569,35 @@ PyObject *obj; PyObject *order; PyObject *ret = NULL; - Py_buffer view; + Py_buffer view, *base; char ord; if (!PyArg_ParseTuple(args, "OO", &obj, &order)) { return NULL; } - if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) { - PyErr_SetString(PyExc_TypeError, - "is_contiguous: object does not implement the buffer " - "protocol"); + ord = get_ascii_order(order); + if (ord == CHAR_MAX) { return NULL; } - ord = get_ascii_order(order); - if (ord == CHAR_MAX) { - goto release; + if (NDArray_Check(obj)) { + /* Skip the buffer protocol to check simple etc. buffers directly. */ + base = &((NDArrayObject *)obj)->head->base; + ret = PyBuffer_IsContiguous(base, ord) ? Py_True : Py_False; } - - ret = PyBuffer_IsContiguous(&view, ord) ? Py_True : Py_False; + else { + if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) { + PyErr_SetString(PyExc_TypeError, + "is_contiguous: object does not implement the buffer " + "protocol"); + return NULL; + } + ret = PyBuffer_IsContiguous(&view, ord) ? Py_True : Py_False; + PyBuffer_Release(&view); + } + Py_INCREF(ret); - -release: - PyBuffer_Release(&view); return ret; } diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -367,16 +367,35 @@ Py_ssize_t sd, dim; int i; - if (view->ndim == 0) return 1; - if (view->strides == NULL) return (view->ndim == 1); + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) { /* C-contiguous by definition */ + /* Trivially F-contiguous */ + if (view->ndim <= 1) return 1; + + /* ndim > 1 implies shape != NULL */ + assert(view->shape != NULL); + + /* Effectively 1-d */ + sd = 0; + for (i=0; indim; i++) { + if (view->shape[i] > 1) sd += 1; + } + return sd <= 1; + } + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); sd = view->itemsize; - if (view->ndim == 1) return (view->shape[0] == 1 || - sd == view->strides[0]); for (i=0; indim; i++) { dim = view->shape[i]; - if (dim == 0) return 1; - if (view->strides[i] != sd) return 0; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } sd *= dim; } return 1; @@ -388,16 +407,22 @@ Py_ssize_t sd, dim; int i; - if (view->ndim == 0) return 1; - if (view->strides == NULL) return 1; + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) return 1; /* C-contiguous by definition */ + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); sd = view->itemsize; - if (view->ndim == 1) return (view->shape[0] == 1 || - sd == view->strides[0]); for (i=view->ndim-1; i>=0; i--) { dim = view->shape[i]; - if (dim == 0) return 1; - if (view->strides[i] != sd) return 0; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } sd *= dim; } return 1; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 16:18:49 2015 From: python-checkins at python.org (vinay.sajip) Date: Sun, 01 Feb 2015 15:18:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merged_documentation_update_from_3=2E4=2E?= Message-ID: <20150201151825.25847.56941@psf.io> https://hg.python.org/cpython/rev/6405709f4f82 changeset: 94426:6405709f4f82 parent: 94423:369300948f3f parent: 94425:35fa000406c4 user: Vinay Sajip date: Sun Feb 01 15:18:14 2015 +0000 summary: Merged documentation update from 3.4. files: Doc/howto/logging-cookbook.rst | 54 ++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -2088,3 +2088,57 @@ While the above treatment is simplistic, it points the way to how exception information can be formatted to your liking. The :mod:`traceback` module may be helpful for more specialized needs. + +.. _spoken-messages: + +Speaking logging messages +------------------------- + +There might be situations when it is desirable to have logging messages rendered +in an audible rather than a visible format. This is easy to do if you have text- +to-speech (TTS) functionality available in your system, even if it doesn't have +a Python binding. Most TTS systems have a command line program you can run, and +this can be invoked from a handler using :mod:`subprocess`. It's assumed here +that TTS command line programs won't expect to interact with users or take a +long time to complete, and that the frequency of logged messages will be not so +high as to swamp the user with messages, and that it's acceptable to have the +messages spoken one at a time rather than concurrently, The example implementation +below waits for one message to be spoken before the next is processed, and this +might cause other handlers to be kept waiting. Here is a short example showing +the approach, which assumes that the ``espeak`` TTS package is available:: + + import logging + import subprocess + import sys + + class TTSHandler(logging.Handler): + def emit(self, record): + msg = self.format(record) + # Speak slowly in a female English voice + cmd = ['espeak', '-s150', '-ven+f3', msg] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + # wait for the program to finish + p.communicate() + + def configure_logging(): + h = TTSHandler() + root = logging.getLogger() + root.addHandler(h) + # the default formatter just returns the message + root.setLevel(logging.DEBUG) + + def main(): + logging.info('Hello') + logging.debug('Goodbye') + + if __name__ == '__main__': + configure_logging() + sys.exit(main()) + +When run, this script should say "Hello" and then "Goodbye" in a female voice. + +The above approach can, of course, be adapted to other TTS systems and even +other systems altogether which can process messages via external programs run +from a command line. + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 16:18:49 2015 From: python-checkins at python.org (vinay.sajip) Date: Sun, 01 Feb 2015 15:18:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Added_a_cookbo?= =?utf-8?q?ok_entry_on_logging_audible_messages=2E?= Message-ID: <20150201151824.39290.39018@psf.io> https://hg.python.org/cpython/rev/35fa000406c4 changeset: 94425:35fa000406c4 branch: 3.4 parent: 94420:8049954bc0e4 user: Vinay Sajip date: Sun Feb 01 15:17:34 2015 +0000 summary: Added a cookbook entry on logging audible messages. files: Doc/howto/logging-cookbook.rst | 54 ++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -2088,3 +2088,57 @@ While the above treatment is simplistic, it points the way to how exception information can be formatted to your liking. The :mod:`traceback` module may be helpful for more specialized needs. + +.. _spoken-messages: + +Speaking logging messages +------------------------- + +There might be situations when it is desirable to have logging messages rendered +in an audible rather than a visible format. This is easy to do if you have text- +to-speech (TTS) functionality available in your system, even if it doesn't have +a Python binding. Most TTS systems have a command line program you can run, and +this can be invoked from a handler using :mod:`subprocess`. It's assumed here +that TTS command line programs won't expect to interact with users or take a +long time to complete, and that the frequency of logged messages will be not so +high as to swamp the user with messages, and that it's acceptable to have the +messages spoken one at a time rather than concurrently, The example implementation +below waits for one message to be spoken before the next is processed, and this +might cause other handlers to be kept waiting. Here is a short example showing +the approach, which assumes that the ``espeak`` TTS package is available:: + + import logging + import subprocess + import sys + + class TTSHandler(logging.Handler): + def emit(self, record): + msg = self.format(record) + # Speak slowly in a female English voice + cmd = ['espeak', '-s150', '-ven+f3', msg] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + # wait for the program to finish + p.communicate() + + def configure_logging(): + h = TTSHandler() + root = logging.getLogger() + root.addHandler(h) + # the default formatter just returns the message + root.setLevel(logging.DEBUG) + + def main(): + logging.info('Hello') + logging.debug('Goodbye') + + if __name__ == '__main__': + configure_logging() + sys.exit(main()) + +When run, this script should say "Hello" and then "Goodbye" in a female voice. + +The above approach can, of course, be adapted to other TTS systems and even +other systems altogether which can process messages via external programs run +from a command line. + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 16:18:49 2015 From: python-checkins at python.org (vinay.sajip) Date: Sun, 01 Feb 2015 15:18:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Added_a_cookbo?= =?utf-8?q?ok_entry_on_logging_audible_messages=2E?= Message-ID: <20150201151824.106327.84528@psf.io> https://hg.python.org/cpython/rev/7ee7d9fac852 changeset: 94424:7ee7d9fac852 branch: 2.7 parent: 94419:c8d7df3cb854 user: Vinay Sajip date: Sun Feb 01 15:14:03 2015 +0000 summary: Added a cookbook entry on logging audible messages. files: Doc/howto/logging-cookbook.rst | 54 ++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1114,3 +1114,57 @@ While the above treatment is simplistic, it points the way to how exception information can be formatted to your liking. The :mod:`traceback` module may be helpful for more specialized needs. + +.. _spoken-messages: + +Speaking logging messages +------------------------- + +There might be situations when it is desirable to have logging messages rendered +in an audible rather than a visible format. This is easy to do if you have text- +to-speech (TTS) functionality available in your system, even if it doesn't have +a Python binding. Most TTS systems have a command line program you can run, and +this can be invoked from a handler using :mod:`subprocess`. It's assumed here +that TTS command line programs won't expect to interact with users or take a +long time to complete, and that the frequency of logged messages will be not so +high as to swamp the user with messages, and that it's acceptable to have the +messages spoken one at a time rather than concurrently, The example implementation +below waits for one message to be spoken before the next is processed, and this +might cause other handlers to be kept waiting. Here is a short example showing +the approach, which assumes that the ``espeak`` TTS package is available:: + + import logging + import subprocess + import sys + + class TTSHandler(logging.Handler): + def emit(self, record): + msg = self.format(record) + # Speak slowly in a female English voice + cmd = ['espeak', '-s150', '-ven+f3', msg] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + # wait for the program to finish + p.communicate() + + def configure_logging(): + h = TTSHandler() + root = logging.getLogger() + root.addHandler(h) + # the default formatter just returns the message + root.setLevel(logging.DEBUG) + + def main(): + logging.info('Hello') + logging.debug('Goodbye') + + if __name__ == '__main__': + configure_logging() + sys.exit(main()) + +When run, this script should say "Hello" and then "Goodbye" in a female voice. + +The above approach can, of course, be adapted to other TTS systems and even +other systems altogether which can process messages via external programs run +from a command line. + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 16:26:41 2015 From: python-checkins at python.org (donald.stufft) Date: Sun, 01 Feb 2015 15:26:41 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Switch_to_proposing_a_full_mi?= =?utf-8?q?gration_to_Git=2C_Github=2C_and_Phabricator?= Message-ID: <20150201152622.96082.96221@psf.io> https://hg.python.org/peps/rev/0a92b2d4967b changeset: 5686:0a92b2d4967b user: Donald Stufft date: Sun Feb 01 10:26:15 2015 -0500 summary: Switch to proposing a full migration to Git, Github, and Phabricator files: pep-0481.txt | 448 +++++++++++++++++++++++--------------- 1 files changed, 271 insertions(+), 177 deletions(-) diff --git a/pep-0481.txt b/pep-0481.txt --- a/pep-0481.txt +++ b/pep-0481.txt @@ -1,5 +1,5 @@ PEP: 481 -Title: Migrate Some Supporting Repositories to Git and Github +Title: Migrate CPython to Git, Github, and Phabricator Version: $Revision$ Last-Modified: $Date$ Author: Donald Stufft @@ -13,156 +13,305 @@ Abstract ======== -This PEP proposes migrating to Git and Github for certain supporting -repositories (such as the repository for Python Enhancement Proposals) in a way -that is more accessible to new contributors, and easier to manage for core -developers. This is offered as an alternative to PEP 474 which aims to achieve -the same overall benefits but while continuing to use the Mercurial DVCS and -without relying on a commerical entity. - -In particular this PEP proposes changes to the following repositories: - -* https://hg.python.org/devguide/ -* https://hg.python.org/devinabox/ -* https://hg.python.org/peps/ - - -This PEP does not propose any changes to the core development workflow for -CPython itself. +This PEP proposes migrating the repository hosting of CPython and the +supporting repositories to Git and Github. It also proposes adding Phabricator +as an alternative to Github Pull Requests to handle reviewing changes. This +particular PEP is offered as an alternative to PEP 474 and PEP 462 which aims +to achieve the same overall benefits but restricts itself to tools that support +Mercurial and are completely Open Source. Rationale ========= -As PEP 474 mentions, there are currently a number of repositories hosted on -hg.python.org which are not directly used for the development of CPython but -instead are supporting or ancillary repositories. These supporting repositories -do not typically have complex workflows or often branches at all other than the -primary integration branch. This simplicity makes them very good targets for -the "Pull Request" workflow that is commonly found on sites like Github. +CPython is an open source project which relies on a number of volunteers +donating their time. As an open source project it relies on attracting new +volunteers as well as retaining existing ones in order to continue to have +a healthy amount of manpower available. In addition to increasing the amount of +manpower that is available to the project, it also needs to allow for effective +use of what manpower *is* available. -However whereas PEP 474 proposes to continue to use Mercurial and restricts -itself to only solutions which are OSS and self-hosted, this PEP expands the -scope of that to include migrating to Git and using Github. +The current toolchain of the CPython project is a custom and unique combination +of tools which mandates a workflow that is similar to one found in a lot of +older projects, but which is becoming less and less popular as time goes on. -The existing method of contributing to these repositories generally includes -generating a patch and either uploading them to bugs.python.org or emailing -them to peps at python.org. This process is unfriendly towards non-comitter -contributors as well as cumbersome for comitters seeking to accept the patches -sent by users. In contrast, the Pull Request workflow style enables non -technical contributors, especially those who do not know their way around the -DVCS of choice, to contribute using the web based editor. On the committer -side, the Pull Requests enable them to tell, before merging, whether or not -a particular Pull Request will break anything. It also enables them to do a -simple "push button" merge which does not require them to check out the -changes locally. Another such feature that is useful in particular for docs, -is the ability to view a "prose" diff. This Github-specific feature enables -a committer to view a diff of the rendered output which will hide things like -reformatting a paragraph and show you what the actual "meat" of the change -actually is. +The one-off nature of the CPython toolchain and workflow means that any new +contributor is going to need spend time learning the tools and workflow before +they can start contributing to CPython. Once a new contributor goes through +the process of learning the CPython workflow they also are unlikely to be able +to take that knowledge and apply it to future projects they wish to contribute +to. This acts as a barrier to contribution which will scare off potential new +contributors. +In addition the tooling that CPython uses is under-maintained, antiquated, +and it lacks important features that enable committers to more effectively use +their time when reviewing and approving changes. The fact that it is +under-maintained means that bugs are likely to last for longer, if they ever +get fixed, as well as it's more likely to go down for extended periods of time. +The fact that it is antiquated means that it doesn't effectively harness the +capabilities of the modern web platform. Finally the fact that it lacks several +important features such as a lack of pre-testing commits and the lack of an +automatic merge tool means that committers have to do needless busy work to +commit even the simplest of changes. -Why Git? --------- -Looking at the variety of DVCS which are available today, it becomes fairly -clear that git has the largest mindshare. The Open Hub (previously Ohloh) -statistics [#openhub-stats]_ show that currently 37% of the repositories -indexed by Open Hub are using git which is second only to SVN (which has 48%), -while Mercurial has just 2% of the indexed repositories (beating only bazaar -which has 1%). In additon to the Open Hub statistics, a look at the top 100 -projects on PyPI (ordered by total download counts) shows that within the -Python space itself, the majority of projects use git. +Version Control System +---------------------- -=== ========= ========== ====== === ==== -Git Mercurial Subversion Bazaar CVS None -=== ========= ========== ====== === ==== -62 22 7 4 1 1 -=== ========= ========== ====== === ==== +The first decision that needs to be made is the VCS of the primary server side +repository. Currently the CPython repository, as well as a number of supporting +repositories, uses Mercurial. When evaluating the VCS we must consider the +capabilities of the VCS itself as well as the network effect and mindshare of +the community around that VCS. +There are really only two real options for this, Mercurial and Git. Between the +two of them the technical capabilities are largely equivilant. For this reason +this PEP will largely ignore the technical arguments about the VCS system and +will instead focus on the social aspects. -Chosing a DVCS which has the larger mindshare will make it more likely that any -particular person who has experience with DVCS at all will be able to -meaningfully contribute without having to learn a new tool. +It is not possible to get exact numbers for the number of projects or people +which are using a particular VCS, however we can infer this by looking at +several sources of information for what VCS projects are using. -In addition to simply making it more likely that any individual will already -know how to use git, the number of projects and people using it means that the -resources for learning the tool are likely to be more fully fleshed out. -When you run into problems, the likelihood that someone else had that problem -and posted a question and recieved an answer is also far higher. +The Open Hub (previously Ohloh) statistics [#openhub-stats]_ show that 37% of +the repositories indexed by The Open Hub are using Git (second only to SVN +which has 48%) while Mercurial has just 2% (beating only bazaar which has 1%). +This has Git being just over 18 times as popular as Mercurial on The Open Hub. -Thirdly, by using a more popular tool you also increase your options for -tooling *around* the DVCS itself. Looking at the various options for hosting -repositories, it's extremely rare to find a hosting solution (whether OSS or -commerical) that supports Mercurial but does not support Git. On the flip side, -there are a number of tools which support Git but do not support Mercurial. -Therefore the popularity of git increases the flexibility of our options going -into the future for what toolchain these projects use. +Another source of information on the popular of the difference VCSs is PyPI +itself. This source is more targeted at the Python community itself since it +represents projects developed for Python. Unfortunately PyPI does not have a +standard location for representing this information, so this requires manual +processing. If we limit our search to the top 100 projects on PyPI (ordered +by download counts) we can see that 62% of them use Git while 22% of them use +Mercurial while 13% use something else. This has Git being just under 3 times +as popular as Mercurial for the top 100 projects on PyPI. -Also, by moving to the more popular DVCS, we increase the likelihood that the -knowledge that the person has learned in contributing to these support -repositories will transfer to projects outside of the immediate CPython project -such as to the larger Python community which is primarily using Git hosted on -Github. +Obviously from these numbers Git is by far the more popular DVCS for open +source projects and choosing the more popular VCS has a number of positive +benefits. -In previous years there was concern about how well supported git was on Windows -in comparison to Mercurial. However, git has grown to support Windows as a -first class citizen. In addition to that, for Windows users who are not well -acquainted with the Windows command line, there are GUI options as well. +For new contributors it increases the likelihood that they will have already +learned the basics of Git as part of working with another project or if they +are just now learning Git, that they'll be able to take that knowledge and +apply it to other projects. Additionally a larger community means more people +writing how to guides, answering questions, and writing articles about Git +which makes it easier for a new user to find answers and information about +the tool they are trying to learn. +Another benefit is that by nature of having a larger community, there will be +more tooling written *around* it. This increases options for everything from +GUI clients, helper scripts, repository hosting, etc. -Why Github? + +Repository Hosting +------------------ + +This PEP proposes allowing GitHub Pull Requests to be submitted, however GitHub +does not have a way to submit Pull Requests against a repository that is not +hosted on GitHub. This PEP also proposes that in addition to GitHub Pull +Requests Phabricator's Differential app can also be used to submit proposed +changes and Phabricator *does* allow submitting changes against a repository +that is not hosted on Phabricator. + +For this reason this PEP proposes using GitHub as the canonical location of +the repository with a read-only mirror located in Phabricator. If at some point +in the future GitHub is no longer desired, then repository hosting can easily +be moved to solely in Phabricator and the ability to accept GitHub Pull +Requests dropped. + +In addition to hosting the repositories on Github, a read only copy of all +repositories will also be mirrored onto the PSF Infrastructure. + + +Code Review ----------- -There are a number of software projects or web services which offer -functionality similar to that of Github. These range from commerical web -services such as Bitbucket to self-hosted OSS solutions such as Kallithea or -Gitlab. This PEP proposes that we move these repositories to Github. +Currently CPython uses a custom fork of Rietveld which has been modified to +not run on Google App Engine which is really only able to be maintained +currently by one person. In addition it is missing out on features that are +present in many modern code review tools. -There are two primary reasons for selecting Github: Popularity and -Quality/Polish. +This PEP proposes allowing both Github Pull Requests and Phabricator changes +to propose changes and review code. It suggests both so that contributors can +select which tool best enables them to submit changes, and reviewers can focus +on reviewing changes in the tooling they like best. -Github is currently the most popular hosted repository hosting according to -Alexa, where it currently has a global rank of 121. Much like for Git itself, -by choosing the most popular tool we gain benefits in increasing the likelihood -that a new contributor will have already experienced the toolchain, the quality -and availablity of the help, more and better tooling being built around it, and -the knowledge transfer to other projects. A look again at the top 100 projects -by download counts on PyPI shows the following hosting locations: -====== ========= =========== ========= =========== ========== -GitHub BitBucket Google Code Launchpad SourceForge Other/Self -====== ========= =========== ========= =========== ========== -62 18 6 4 3 7 -====== ========= =========== ========= =========== ========== +GitHub Pull Requests +~~~~~~~~~~~~~~~~~~~~ -In addition to all of those reasons, Github also has the benefit that while -many of the options have similar features when you look at them in a feature -matrix the Github version of each of those features tend to work better and be -far more polished. This is hard to quantify objectively however it is a fairly -common sentiment if you go around and ask people who are using these services -often. +GitHub is a very popular code hosting site and is increasingly becoming the +primary place people look to contribute to a project. Enabling users to +contribute through GitHub is enabling contributors to contribute using tooling +that they are likely already familiar with and if they are not they are likely +to be able to apply to another project. -Finally, a reason to choose a web service at all over something that is -self-hosted is to be able to more efficiently use volunteer time and donated -resources. Every additional service hosted on the PSF infrastructure by the -PSF infrastructure team further spreads out the amount of time that the -volunteers on that team have to spend and uses some chunk of resources that -could potentially be used for something where there is no free or affordable -hosted solution available. +GitHub Pull Requests have a fairly major advantage over the older "submit a +patch to a bug tracker" model. It allows developers to work completely within +their VCS using standard VCS tooling so it does not require creating a patch +file and figuring out what the right location is to upload it to. This lowers +the barrier for sending a change to be reviewed. -One concern that people do have with using a hosted service is that there is a -lack of control and that at some point in the future the service may no longer -be suitable. It is the opinion of this PEP that Github does not currently and -has not in the past engaged in any attempts to lock people into their platform -and that if at some point in the future Github is no longer suitable for one -reason or another, then at that point we can look at migrating away from Github -onto a different solution. In other words, we'll cross that bridge if and when -we come to it. +On the reviewing side, GitHub Pull Requests are far easier to review, they have +nice syntax highlighted diffs which can operate in either unified or side by +side views. They allow expanding the context on a diff up to and including the +entire file. Finally they allow commenting inline and on the pull request as +a whole and they present that in a nice unified way which will also hide +comments which no longer apply. Github also provides a "rendered diff" view +which enables easily viewing a diff of rendered markup (such as rst) instead +of needing to review the diff of the raw markup. + +The Pull Request work flow also makes it trivial to enable the ability to +pre-test a change before actually merging it. Any particular pull request can +have any number of different types of "commit statuses" applied to it, marking +the commit (and thus the pull request) as either in a pending, successful, +errored, or failure state. This makes it easy to see inline if the pull request +is passing all of the tests, if the contributor has signed a CLA, etc. + +Actually merging a Github Pull Request is quite simple, a core reviewer simply +needs to press the "Merge" button once the status of all the checks on the +Pull Request are green for successful. + +GitHub also has a good workflow for submitting pull requests to a project +completely through their web interface. This would enable the Python +documentation to have "Edit on GitHub" buttons on every page and people who +discover things like typos, inaccuracies, or just want to make improvements to +the docs they are currently writing can simply hit that button and get an in +browser editor that will let them make changes and submit a pull request all +from the comfort of their browser. + + +Phabricator +~~~~~~~~~~~ + +In addition to GitHub Pull Requests this PEP also proposes setting up a +Phabricator instance and pointing it at the GitHub hosted repositories. This +will allow utilizing the Phabricator review applications of Differential and +Audit. + +Differential functions similarly to GitHub pull requests except that they +require installing the ``arc`` command line tool to upload patches to +Phabricator. + +Whether to enable Phabricator for any particular repository can be chosen on +a case by case basis, this PEP only proposes that it must be enabled for the +CPython repository, however for smaller repositories such as the PEP repository +it may not be worth the effort. + + +Criticism +========= + +X is not written in Python +-------------------------- + +One feature that the current tooling (Mercurial, Rietveld) has is that the +primary language for all of the pieces are written in Python. It is this PEPs +belief that we should focus on the *best* tools for the job and not the *best* +tools that happen to be written in Python. Volunteer time is a precious +resource to any open source project and we can best respect and utilize that +time by focusing on the benefits and downsides of the tools themselves rather +than what language their authors happened to write them in. + +One concern is the ability to modify tools to work for us, however one of +the Goals here is to *not* modify software to work for us and instead adapt +ourselves to a more standard workflow. This standardization pays off in the +ability to re-use tools out of the box freeing up developer time to actually +work on Python itself as well as enabling knowledge sharing between projects. + +However if we do need to modify the tooling, Git itself is largely written in +C the same as CPython itself is. It can also have commands written for it using +any language, including Python. Phabricator is written in PHP which is a fairly +common language in the web world and fairly easy to pick up. GitHub itself is +largely written in Ruby but given that it's not Open Source there is no ability +to modify it so it's implementation language is completely meaningless. + + +GitHub is not Free/Open Source +------------------------------ + +GitHub is a big part of this proposal and someone who tends more to ideology +rather than practicality may be opposed to this PEP on that grounds alone. It +is this PEPs belief that while using entirely Free/Open Source software is an +attractive idea and a noble goal, that valuing the time of the contributors by +giving them good tooling that is well maintained and that they either already +know or if they learn it they can apply to other projects is a more important +concern than treating whether something is Free/Open Source is a hard +requirement. + +However, history has shown us that sometimes benevolent proprietary companies +can stop being benevolent. This is hedged against in a few ways: + +* We are not utilizing the GitHub Issue Tracker, both because it is not + powerful enough for CPython but also because for the primary CPython + repository the ability to take our issues and put them somewhere else if we + ever need to leave GitHub relies on GitHub continuing to allow API access. + +* We are utilizing the GitHub Pull Request workflow, however all of those + changes live inside of Git. So a mirror of the GitHub repositories can easily + contain all of those Pull Requests. We would potentially lose any comments if + GitHub suddenly turned "evil", but the changes themselves would still exist. + +* We are utilizing the GitHub repository hosting feature, however since this is + just git moving away from GitHub is as simple as pushing the repository to + a different location. Data portability for the repository itself is extremely + high. + +* We are also utilizing Phabricator to provide an alternative for people who + do not wish to use GitHub. This also acts as a fallback option which will + already be in place if we ever need to stop using GitHub. + +Relying on GitHub comes with a number of benefits beyond just the benefits of +the platform itself. Since it is a commercially backed venture it has a full +time staff responsible for maintaining its services. This includes making sure +they stay up, making sure they stay patched for various security +vulnerabilities, and further improving the software and infrastructure as time +goes on. + + +Mercurial is better than Git +---------------------------- + +Whether Mercurial or Git is better on a technical level is a highly subjective +opinion. This PEP does not state whether the mechanics of Git or Mercurial is +better and instead focuses on the network effect that is available for either +option. Since this PEP proposes switching to Git this leaves the people who +prefer Mercurial out, however those users can easily continue to work with +Mercurial by using the hg-git [#hg-git]_ extension for Mercurial which will +let it work with a repository which is Git on the serverside. + + +CPython Workflow is too Complicated +----------------------------------- + +One sentiment that came out of previous discussions was that the multi branch +model of CPython was too complicated for Github Pull Requests. It is the belief +of this PEP that statement is not accurate. + +Currently any particular change requires manually creating a patch for 2.7 and +3.x which won't change at all in this regards. + +If someone submits a fix for the current stable branch (currently 3.4) the +GitHub Pull Request workflow can be used to create, in the browser, a Pull +Request to merge the current stable branch into the master branch (assuming +there is no merge conflicts). If there is a merge conflict that would need to +be handled locally. This provides an improvement over the current situation +where the merge must always happen locally. + +Finally if someone submits a fix for the current development branch currently +then this has to be manually applied to the stable branch if it desired to +include it there as well. This must also happen locally as well in the new +workflow, however for minor changes it could easily be accomplished in the +GitHub web editor. + +Looking at this, I do not believe that *any* system can hide the complexities +involved in maintaining several long running branches. The only thing that the +tooling can do is make it as easy as possible to submit changes. Example: Scientific Python --------------------------- +========================== One of the key ideas behind the move to both git and Github is that a feature of a DVCS, the repository hosting, and the workflow used is the social network @@ -190,66 +339,11 @@ workflow less reusable with other projects. -Migration -========= - -Through the use of hg-git [#hg-git]_ we can easily convert a Mercurial -repository to a Git repository by simply pushing the Mercurial repository to -the Git repository. People who wish to continue to use Mercurial locally can -then use hg-git going into the future using the new Github URL. However they -will need to re-clone their repositories as using Git as the server seems to -trigger a one time change of the changeset ids. - -As none of the selected repositories have any tags, branches, or bookmarks -other than the ``default`` branch the migration will simply map the ``default`` -branch in Mercurial to the ``master`` branch in git. - -In addition, since none of the selected projects have any great need of a -complex bug tracker, they will also migrate their issue handling to using the -GitHub issues. - -In addition to the migration of the repository hosting itself there are a -number of locations for each particular repository which will require updating. -The bulk of these will simply be changing commands from the hg equivalent to -the git equivalent. - -In particular this will include: - -* Updating www.python.org to generate PEPs using a git clone and link to - Github. -* Updating docs.python.org to pull from Github instead of hg.python.org for the - devguide. -* Enabling the ability to send an email to python-checkins at python.org for each - push. -* Enabling the ability to send an IRC message to #python-dev on Freenode for - each push. -* Migrate any issues for these projects to their respective bug tracker on - Github. -* Use hg-git to provide a read-only mirror on hg.python.org which will enable - read-only uses of the hg.python.org instances of the specified repositories - to remain the same. - -This will restore these repositories to similar functionality as they currently -have. In addition to this the migration will also include enabling testing for -each pull request using Travis CI [#travisci]_ where possible to ensure that -a new PR does not break the ability to render the documentation or PEPs. - - -User Access -=========== - -Moving to Github would involve adding an additional user account that will need -to be managed, however it also offers finer grained control, allowing the -ability to grant someone access to only one particular repository instead of -the coarser grained ACLs available on hg.python.org. - - References ========== .. [#openhub-stats] `Open Hub Statistics ` -.. [#hg-git] `hg-git ` -.. [#travisci] `Travis CI ` +.. [#hg-git] `Hg-Git mercurial plugin ` Copyright -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Feb 1 18:06:35 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 01 Feb 2015 17:06:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Don=27t_seek_to_the_start_?= =?utf-8?q?of_the_file_when_open_ZipFile_with_the_=27w=27_mode?= Message-ID: <20150201170146.34404.37043@psf.io> https://hg.python.org/cpython/rev/4f96e9a8eee8 changeset: 94427:4f96e9a8eee8 user: Serhiy Storchaka date: Sun Feb 01 19:01:10 2015 +0200 summary: Don't seek to the start of the file when open ZipFile with the 'w' mode (regression introduced in issue #14099). files: Lib/zipfile.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1002,7 +1002,7 @@ # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True - self.start_dir = 0 + self.start_dir = self.fp.tell() elif mode == 'a': try: # See if file is a zip file -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:21:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:21:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjQu?= Message-ID: <20150201182100.96074.43470@psf.io> https://hg.python.org/cpython/rev/9835a186573b changeset: 94430:9835a186573b parent: 94427:4f96e9a8eee8 parent: 94429:4d95956a748e user: Stefan Krah date: Sun Feb 01 19:19:49 2015 +0100 summary: Merge from 3.4. files: Modules/_testcapimodule.c | 51 +++++++++++++++++++++++++++ Objects/abstract.c | 4 +- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2468,6 +2468,56 @@ return NULL; return PyMemoryView_FromBuffer(&info); } + +static PyObject * +test_from_contiguous(PyObject* self, PyObject *noargs) +{ + int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; + int init[5] = {0, 1, 2, 3, 4}; + Py_ssize_t itemsize = sizeof(int); + Py_ssize_t shape = 5; + Py_ssize_t strides = 2 * itemsize; + Py_buffer view = { + data, + NULL, + 5 * itemsize, + itemsize, + 1, + 1, + NULL, + &shape, + &strides, + NULL, + NULL + }; + int *ptr; + int i; + + PyBuffer_FromContiguous(&view, init, view.len, 'C'); + ptr = view.buf; + for (i = 0; i < 5; i++) { + if (ptr[2*i] != i) { + PyErr_SetString(TestError, + "test_from_contiguous: incorrect result"); + return NULL; + } + } + + view.buf = &data[8]; + view.strides[0] = -2 * itemsize; + + PyBuffer_FromContiguous(&view, init, view.len, 'C'); + ptr = view.buf; + for (i = 0; i < 5; i++) { + if (*(ptr-2*i) != i) { + PyErr_SetString(TestError, + "test_from_contiguous: incorrect result"); + return NULL; + } + } + + Py_RETURN_NONE; +} /* Test that the fatal error from not having a current thread doesn't cause an infinite loop. Run via Lib/test/test_capi.py */ @@ -3128,6 +3178,7 @@ {"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS}, {"test_unicode_compare_with_ascii", (PyCFunction)test_unicode_compare_with_ascii, METH_NOARGS}, {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, + {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, METH_VARARGS|METH_KEYWORDS}, diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -512,7 +512,7 @@ /* Otherwise a more elaborate scheme is needed */ - /* XXX(nnorwitz): need to check for overflow! */ + /* view->ndim <= 64 */ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); if (indices == NULL) { PyErr_NoMemory(); @@ -534,10 +534,10 @@ */ elements = len / view->itemsize; while (elements--) { - addone(view->ndim, indices, view->shape); ptr = PyBuffer_GetPointer(view, indices); memcpy(ptr, src, view->itemsize); src += view->itemsize; + addone(view->ndim, indices, view->shape); } PyMem_Free(indices); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:21:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:21:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzcw?= =?utf-8?q?=3A_Fix_off-by-one_error_for_non-contiguous_buffers=2E?= Message-ID: <20150201182100.34382.45415@psf.io> https://hg.python.org/cpython/rev/4d95956a748e changeset: 94429:4d95956a748e branch: 3.4 parent: 94425:35fa000406c4 user: Stefan Krah date: Sun Feb 01 16:19:23 2015 +0100 summary: Issue #23370: Fix off-by-one error for non-contiguous buffers. files: Modules/_testcapimodule.c | 51 +++++++++++++++++++++++++++ Objects/abstract.c | 4 +- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2467,6 +2467,56 @@ return NULL; return PyMemoryView_FromBuffer(&info); } + +static PyObject * +test_from_contiguous(PyObject* self, PyObject *noargs) +{ + int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; + int init[5] = {0, 1, 2, 3, 4}; + Py_ssize_t itemsize = sizeof(int); + Py_ssize_t shape = 5; + Py_ssize_t strides = 2 * itemsize; + Py_buffer view = { + data, + NULL, + 5 * itemsize, + itemsize, + 1, + 1, + NULL, + &shape, + &strides, + NULL, + NULL + }; + int *ptr; + int i; + + PyBuffer_FromContiguous(&view, init, view.len, 'C'); + ptr = view.buf; + for (i = 0; i < 5; i++) { + if (ptr[2*i] != i) { + PyErr_SetString(TestError, + "test_from_contiguous: incorrect result"); + return NULL; + } + } + + view.buf = &data[8]; + view.strides[0] = -2 * itemsize; + + PyBuffer_FromContiguous(&view, init, view.len, 'C'); + ptr = view.buf; + for (i = 0; i < 5; i++) { + if (*(ptr-2*i) != i) { + PyErr_SetString(TestError, + "test_from_contiguous: incorrect result"); + return NULL; + } + } + + Py_RETURN_NONE; +} /* Test that the fatal error from not having a current thread doesn't cause an infinite loop. Run via Lib/test/test_capi.py */ @@ -3031,6 +3081,7 @@ {"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS}, {"test_unicode_compare_with_ascii", (PyCFunction)test_unicode_compare_with_ascii, METH_NOARGS}, {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, + {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, METH_VARARGS|METH_KEYWORDS}, diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -488,7 +488,7 @@ /* Otherwise a more elaborate scheme is needed */ - /* XXX(nnorwitz): need to check for overflow! */ + /* view->ndim <= 64 */ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); if (indices == NULL) { PyErr_NoMemory(); @@ -510,10 +510,10 @@ */ elements = len / view->itemsize; while (elements--) { - addone(view->ndim, indices, view->shape); ptr = PyBuffer_GetPointer(view, indices); memcpy(ptr, src, view->itemsize); src += view->itemsize; + addone(view->ndim, indices, view->shape); } PyMem_Free(indices); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:21:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:21:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzMzcw?= =?utf-8?q?=3A_Fix_off-by-one_error_for_non-contiguous_buffers=2E?= Message-ID: <20150201182059.25845.22841@psf.io> https://hg.python.org/cpython/rev/209776d49a9a changeset: 94428:209776d49a9a branch: 2.7 parent: 94424:7ee7d9fac852 user: Stefan Krah date: Sun Feb 01 16:10:35 2015 +0100 summary: Issue #23370: Fix off-by-one error for non-contiguous buffers. files: Modules/_testcapimodule.c | 53 +++++++++++++++++++++++++++ Objects/abstract.c | 4 +- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -424,6 +424,58 @@ Py_RETURN_NONE; } +static PyObject * +test_from_contiguous(PyObject* self, PyObject *noargs) +{ + int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; + int init[5] = {0, 1, 2, 3, 4}; + Py_ssize_t itemsize = sizeof(int); + Py_ssize_t shape = 5; + Py_ssize_t strides = 2 * itemsize; + Py_buffer view = { + data, + NULL, + 5 * itemsize, + itemsize, + 1, + 1, + NULL, + &shape, + &strides, + NULL, + {0, 0}, + NULL + }; + int *ptr; + int i; + + PyBuffer_FromContiguous(&view, init, view.len, 'C'); + ptr = view.buf; + for (i = 0; i < 5; i++) { + if (ptr[2*i] != i) { + PyErr_SetString(TestError, + "test_from_contiguous: incorrect result"); + return NULL; + } + } + + view.buf = &data[8]; + view.strides[0] = -2 * itemsize; + + PyBuffer_FromContiguous(&view, init, view.len, 'C'); + ptr = view.buf; + for (i = 0; i < 5; i++) { + if (*(ptr-2*i) != i) { + PyErr_SetString(TestError, + "test_from_contiguous: incorrect result"); + return NULL; + } + } + + Py_RETURN_NONE; +} + + /* Tests of PyLong_{As, From}{Unsigned,}Long(), and (#ifdef HAVE_LONG_LONG) PyLong_{As, From}{Unsigned,}LongLong(). @@ -1833,6 +1885,7 @@ {"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS}, {"test_broken_memoryview", (PyCFunction)test_broken_memoryview,METH_NOARGS}, {"test_to_contiguous", (PyCFunction)test_to_contiguous, METH_NOARGS}, + {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, {"test_long_api", (PyCFunction)test_long_api, METH_NOARGS}, {"test_long_and_overflow", (PyCFunction)test_long_and_overflow, METH_NOARGS}, diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -550,7 +550,7 @@ /* Otherwise a more elaborate scheme is needed */ - /* XXX(nnorwitz): need to check for overflow! */ + /* view->ndim <= 64 */ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); if (indices == NULL) { PyErr_NoMemory(); @@ -572,10 +572,10 @@ */ elements = len / view->itemsize; while (elements--) { - addone(view->ndim, indices, view->shape); ptr = PyBuffer_GetPointer(view, indices); memcpy(ptr, src, view->itemsize); src += view->itemsize; + addone(view->ndim, indices, view->shape); } PyMem_Free(indices); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:51:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:51:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323352=3A_Merge_from_3=2E4=2E?= Message-ID: <20150201185055.25845.20792@psf.io> https://hg.python.org/cpython/rev/5d097a74766f changeset: 94433:5d097a74766f parent: 94430:9835a186573b parent: 94432:de5c8ee002bf user: Stefan Krah date: Sun Feb 01 19:42:45 2015 +0100 summary: Issue #23352: Merge from 3.4. files: Doc/c-api/buffer.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -198,6 +198,9 @@ indicates that no de-referencing should occur (striding in a contiguous memory block). + If all suboffsets are negative (i.e. no de-referencing is needed, then + this field must be NULL (the default value). + This type of array representation is used by the Python Imaging Library (PIL). See `complex arrays`_ for further information how to access elements of such an array. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:51:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:51:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Preserve_criti?= =?utf-8?q?cal_whitespace_in_Doc/*=2E?= Message-ID: <20150201185055.39292.28896@psf.io> https://hg.python.org/cpython/rev/17ab76dead0d changeset: 94437:17ab76dead0d branch: 2.7 parent: 94431:c4c1d68b6301 user: Stefan Krah date: Sun Feb 01 19:49:38 2015 +0100 summary: Preserve critical whitespace in Doc/*. files: Doc/c-api/buffer.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -99,7 +99,7 @@ occur (striding in a contiguous memory block). If all suboffsets are negative (i.e. no de-referencing is needed, then - this field must be NULL (the default value). + this field must be NULL (the default value). Here is a function that returns a pointer to the element in an N-D array pointed to by an N-dimensional index when there are both non-NULL strides -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:51:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:51:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Whitespace=2E?= Message-ID: <20150201185055.106370.27932@psf.io> https://hg.python.org/cpython/rev/5569ae9e2be2 changeset: 94434:5569ae9e2be2 user: Stefan Krah date: Sun Feb 01 19:45:14 2015 +0100 summary: Whitespace. files: Doc/c-api/buffer.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -199,7 +199,7 @@ memory block). If all suboffsets are negative (i.e. no de-referencing is needed, then - this field must be NULL (the default value). + this field must be NULL (the default value). This type of array representation is used by the Python Imaging Library (PIL). See `complex arrays`_ for further information how to access elements -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:51:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:51:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzUy?= =?utf-8?q?=3A_Document_that_Py=5Fbuffer=2Esuboffsets_must_be_NULL_if_no_s?= =?utf-8?q?uboffsets?= Message-ID: <20150201185054.39274.44459@psf.io> https://hg.python.org/cpython/rev/de5c8ee002bf changeset: 94432:de5c8ee002bf branch: 3.4 parent: 94429:4d95956a748e user: Stefan Krah date: Sun Feb 01 19:42:12 2015 +0100 summary: Issue #23352: Document that Py_buffer.suboffsets must be NULL if no suboffsets are required. files: Doc/c-api/buffer.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -198,6 +198,9 @@ indicates that no de-referencing should occur (striding in a contiguous memory block). + If all suboffsets are negative (i.e. no de-referencing is needed, then + this field must be NULL (the default value). + This type of array representation is used by the Python Imaging Library (PIL). See `complex arrays`_ for further information how to access elements of such an array. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:51:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:51:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Whitespace=2E?= Message-ID: <20150201185055.106249.38178@psf.io> https://hg.python.org/cpython/rev/24e3371cec2d changeset: 94435:24e3371cec2d branch: 3.4 parent: 94432:de5c8ee002bf user: Stefan Krah date: Sun Feb 01 19:46:31 2015 +0100 summary: Whitespace. files: Doc/c-api/buffer.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -199,7 +199,7 @@ memory block). If all suboffsets are negative (i.e. no de-referencing is needed, then - this field must be NULL (the default value). + this field must be NULL (the default value). This type of array representation is used by the Python Imaging Library (PIL). See `complex arrays`_ for further information how to access elements -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:51:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:51:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_cosmetic_change=2E?= Message-ID: <20150201185055.106379.6461@psf.io> https://hg.python.org/cpython/rev/582aabcce2fd changeset: 94436:582aabcce2fd parent: 94434:5569ae9e2be2 parent: 94435:24e3371cec2d user: Stefan Krah date: Sun Feb 01 19:47:25 2015 +0100 summary: Merge cosmetic change. files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 1 19:51:07 2015 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Feb 2015 18:51:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzMzUy?= =?utf-8?q?=3A_Document_that_Py=5Fbuffer=2Esuboffsets_must_be_NULL_if_no_s?= =?utf-8?q?uboffsets?= Message-ID: <20150201185054.39296.30133@psf.io> https://hg.python.org/cpython/rev/c4c1d68b6301 changeset: 94431:c4c1d68b6301 branch: 2.7 parent: 94428:209776d49a9a user: Stefan Krah date: Sun Feb 01 19:40:50 2015 +0100 summary: Issue #23352: Document that Py_buffer.suboffsets must be NULL if no suboffsets are required. files: Doc/c-api/buffer.rst | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -98,8 +98,11 @@ suboffset value that it negative indicates that no de-referencing should occur (striding in a contiguous memory block). + If all suboffsets are negative (i.e. no de-referencing is needed, then + this field must be NULL (the default value). + Here is a function that returns a pointer to the element in an N-D array - pointed to by an N-dimesional index when there are both non-NULL strides + pointed to by an N-dimensional index when there are both non-NULL strides and suboffsets:: void *get_item_pointer(int ndim, void *buf, Py_ssize_t *strides, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 00:02:56 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 01 Feb 2015 23:02:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150201230228.39278.47884@psf.io> https://hg.python.org/cpython/rev/cf4f7a572b79 changeset: 94443:cf4f7a572b79 parent: 94440:02aeca4974ac parent: 94442:a8737f0bbb7a user: Benjamin Peterson date: Sun Feb 01 18:02:21 2015 -0500 summary: merge 3.4 files: Lib/test/test_json/test_encode_basestring_ascii.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -45,4 +45,3 @@ s = "\uffff"*((2**32)//6 + 1) with self.assertRaises(OverflowError): self.json.encoder.encode_basestring_ascii(s) - -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 00:02:56 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 01 Feb 2015 23:02:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3?= Message-ID: <20150201230228.25847.54178@psf.io> https://hg.python.org/cpython/rev/a8737f0bbb7a changeset: 94442:a8737f0bbb7a branch: 3.4 parent: 94439:4f47509d7417 parent: 94441:1801b2571587 user: Benjamin Peterson date: Sun Feb 01 18:02:15 2015 -0500 summary: merge 3.3 files: Lib/test/test_json/test_encode_basestring_ascii.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -48,4 +48,3 @@ s = "\uffff"*((2**32)//6 + 1) with self.assertRaises(OverflowError): self.json.encoder.encode_basestring_ascii(s) - -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 00:02:56 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 01 Feb 2015 23:02:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_fix_possible_o?= =?utf-8?q?verflow_in_encode=5Fbasestring=5Fascii_=28closes_=2323369=29?= Message-ID: <20150201230227.25859.84821@psf.io> https://hg.python.org/cpython/rev/8699b3085db3 changeset: 94438:8699b3085db3 branch: 3.3 parent: 94340:6caed177a028 user: Benjamin Peterson date: Sun Feb 01 17:53:53 2015 -0500 summary: fix possible overflow in encode_basestring_ascii (closes #23369) files: Lib/test/test_json/test_encode_basestring_ascii.py | 9 +++++- Misc/NEWS | 6 ++++ Modules/_json.c | 15 +++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -1,5 +1,6 @@ from collections import OrderedDict from test.test_json import PyTest, CTest +from test.support import bigaddrspacetest CASES = [ @@ -41,4 +42,10 @@ class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass -class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): + @bigaddrspacetest + def test_overflow(self): + s = "\uffff"*((2**32)//6 + 1) + with self.assertRaises(OverflowError): + self.json.encoder.encode_basestring_ascii(s) + diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,12 @@ - Issue #23055: Fixed a buffer overflow in PyUnicode_FromFormatV. Analysis and fix by Guido Vranken. +Library +------- + +- Issue #23369: Fixed possible integer overflow in + _json.encode_basestring_ascii. + What's New in Python 3.3.6? =========================== diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -216,17 +216,24 @@ /* Compute the output size */ for (i = 0, output_size = 2; i < input_chars; i++) { Py_UCS4 c = PyUnicode_READ(kind, input, i); - if (S_CHAR(c)) - output_size++; + Py_ssize_t d; + if (S_CHAR(c)) { + d = 1; + } else { switch(c) { case '\\': case '"': case '\b': case '\f': case '\n': case '\r': case '\t': - output_size += 2; break; + d = 2; break; default: - output_size += c >= 0x10000 ? 12 : 6; + d = c >= 0x10000 ? 12 : 6; } } + if (output_size > PY_SSIZE_T_MAX - d) { + PyErr_SetString(PyExc_OverflowError, "string is too long to escape"); + return NULL; + } + output_size += d; } rval = PyUnicode_New(output_size, 127); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 00:02:56 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 01 Feb 2015 23:02:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_remove_extra_w?= =?utf-8?q?s?= Message-ID: <20150201230227.96098.99@psf.io> https://hg.python.org/cpython/rev/1801b2571587 changeset: 94441:1801b2571587 branch: 3.3 parent: 94438:8699b3085db3 user: Benjamin Peterson date: Sun Feb 01 18:02:09 2015 -0500 summary: remove extra ws files: Lib/test/test_json/test_encode_basestring_ascii.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -48,4 +48,3 @@ s = "\uffff"*((2**32)//6 + 1) with self.assertRaises(OverflowError): self.json.encoder.encode_basestring_ascii(s) - -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 00:02:56 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 01 Feb 2015 23:02:56 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjMzNjkp?= Message-ID: <20150201230227.96094.94005@psf.io> https://hg.python.org/cpython/rev/02aeca4974ac changeset: 94440:02aeca4974ac parent: 94436:582aabcce2fd parent: 94439:4f47509d7417 user: Benjamin Peterson date: Sun Feb 01 18:00:19 2015 -0500 summary: merge 3.4 (#23369) files: Lib/test/test_json/test_encode_basestring_ascii.py | 9 +++++- Misc/NEWS | 3 ++ Modules/_json.c | 15 +++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -1,5 +1,6 @@ from collections import OrderedDict from test.test_json import PyTest, CTest +from test.support import bigaddrspacetest CASES = [ @@ -38,4 +39,10 @@ class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass -class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): + @bigaddrspacetest + def test_overflow(self): + s = "\uffff"*((2**32)//6 + 1) + with self.assertRaises(OverflowError): + self.json.encoder.encode_basestring_ascii(s) + diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,9 @@ - Issue #23326: Removed __ne__ implementations. Since fixing default __ne__ implementation in issue #21408 they are redundant. +- Issue #23369: Fixed possible integer overflow in + _json.encode_basestring_ascii. + - Issue #23353: Fix the exception handling of generators in PyEval_EvalFrameEx(). At entry, save or swap the exception state even if PyEval_EvalFrameEx() is called with throwflag=0. At exit, the exception state diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -182,17 +182,24 @@ /* Compute the output size */ for (i = 0, output_size = 2; i < input_chars; i++) { Py_UCS4 c = PyUnicode_READ(kind, input, i); - if (S_CHAR(c)) - output_size++; + Py_ssize_t d; + if (S_CHAR(c)) { + d = 1; + } else { switch(c) { case '\\': case '"': case '\b': case '\f': case '\n': case '\r': case '\t': - output_size += 2; break; + d = 2; break; default: - output_size += c >= 0x10000 ? 12 : 6; + d = c >= 0x10000 ? 12 : 6; } } + if (output_size > PY_SSIZE_T_MAX - d) { + PyErr_SetString(PyExc_OverflowError, "string is too long to escape"); + return NULL; + } + output_size += d; } rval = PyUnicode_New(output_size, 127); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 00:02:56 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 01 Feb 2015 23:02:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3_=28=2323369=29?= Message-ID: <20150201230227.39270.86230@psf.io> https://hg.python.org/cpython/rev/4f47509d7417 changeset: 94439:4f47509d7417 branch: 3.4 parent: 94435:24e3371cec2d parent: 94438:8699b3085db3 user: Benjamin Peterson date: Sun Feb 01 17:59:49 2015 -0500 summary: merge 3.3 (#23369) files: Lib/test/test_json/test_encode_basestring_ascii.py | 9 +++++- Misc/NEWS | 3 ++ Modules/_json.c | 15 +++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -1,5 +1,6 @@ from collections import OrderedDict from test.test_json import PyTest, CTest +from test.support import bigaddrspacetest CASES = [ @@ -41,4 +42,10 @@ class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass -class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): pass +class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): + @bigaddrspacetest + def test_overflow(self): + s = "\uffff"*((2**32)//6 + 1) + with self.assertRaises(OverflowError): + self.json.encoder.encode_basestring_ascii(s) + diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,9 @@ Library ------- +- Issue #23369: Fixed possible integer overflow in + _json.encode_basestring_ascii. + - Issue #23353: Fix the exception handling of generators in PyEval_EvalFrameEx(). At entry, save or swap the exception state even if PyEval_EvalFrameEx() is called with throwflag=0. At exit, the exception state diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -182,17 +182,24 @@ /* Compute the output size */ for (i = 0, output_size = 2; i < input_chars; i++) { Py_UCS4 c = PyUnicode_READ(kind, input, i); - if (S_CHAR(c)) - output_size++; + Py_ssize_t d; + if (S_CHAR(c)) { + d = 1; + } else { switch(c) { case '\\': case '"': case '\b': case '\f': case '\n': case '\r': case '\t': - output_size += 2; break; + d = 2; break; default: - output_size += c >= 0x10000 ? 12 : 6; + d = c >= 0x10000 ? 12 : 6; } } + if (output_size > PY_SSIZE_T_MAX - d) { + PyErr_SetString(PyExc_OverflowError, "string is too long to escape"); + return NULL; + } + output_size += d; } rval = PyUnicode_New(output_size, 127); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 02:18:36 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 01:18:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150202011835.106317.94625@psf.io> https://hg.python.org/cpython/rev/3231a13a0c82 changeset: 94447:3231a13a0c82 parent: 94443:cf4f7a572b79 parent: 94445:fb65ac5aaaac user: Benjamin Peterson date: Sun Feb 01 20:18:29 2015 -0500 summary: merge 3.4 files: Lib/site.py | 2 +- Lib/test/test_site.py | 1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -366,7 +366,7 @@ dirs.extend([os.path.join(here, os.pardir), here, os.curdir]) builtins.license = _sitebuiltins._Printer( "license", - "See http://www.python.org/psf/license/", + "See https://www.python.org/psf/license/", files, dirs) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -410,6 +410,7 @@ self.fail("sitecustomize not imported automatically") @test.support.requires_resource('network') + @test.support.system_must_validate_cert @unittest.skipUnless(sys.version_info[3] == 'final', 'only for released versions') @unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 02:18:36 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 01:18:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_https_goodness?= Message-ID: <20150202011835.39274.52073@psf.io> https://hg.python.org/cpython/rev/fb65ac5aaaac changeset: 94445:fb65ac5aaaac branch: 3.4 user: Benjamin Peterson date: Sun Feb 01 20:17:22 2015 -0500 summary: https goodness files: Lib/site.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -373,7 +373,7 @@ dirs.extend([os.path.join(here, os.pardir), here, os.curdir]) builtins.license = _sitebuiltins._Printer( "license", - "See http://www.python.org/psf/license/", + "See https://www.python.org/psf/license/", files, dirs) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 02:18:36 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 01:18:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_https_goodness?= Message-ID: <20150202011835.96070.24107@psf.io> https://hg.python.org/cpython/rev/1cc37c52fed4 changeset: 94446:1cc37c52fed4 branch: 2.7 parent: 94437:17ab76dead0d user: Benjamin Peterson date: Sun Feb 01 20:17:22 2015 -0500 summary: https goodness files: Lib/site.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -436,7 +436,7 @@ for supporting Python development. See www.python.org for more information.""") here = os.path.dirname(os.__file__) __builtin__.license = _Printer( - "license", "See http://www.python.org/psf/license/", + "license", "See https://www.python.org/psf/license/", ["LICENSE.txt", "LICENSE"], [os.path.join(here, os.pardir), here, os.curdir]) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 02:18:36 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 01:18:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_fix_tests_on_s?= =?utf-8?q?ystems_that_can=27t_validate_python=2Eorg?= Message-ID: <20150202011834.96084.25941@psf.io> https://hg.python.org/cpython/rev/4bda963dcc11 changeset: 94444:4bda963dcc11 branch: 3.4 parent: 94442:a8737f0bbb7a user: Benjamin Peterson date: Sun Feb 01 20:16:59 2015 -0500 summary: fix tests on systems that can't validate python.org files: Lib/test/test_site.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -412,6 +412,7 @@ self.fail("sitecustomize not imported automatically") @test.support.requires_resource('network') + @test.support.system_must_validate_cert @unittest.skipUnless(sys.version_info[3] == 'final', 'only for released versions') @unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:05:12 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:05:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_detect_overflo?= =?utf-8?q?w_in_combinations_=28closes_=2323366=29?= Message-ID: <20150202020454.106346.23397@psf.io> https://hg.python.org/cpython/rev/fe203370c049 changeset: 94451:fe203370c049 branch: 2.7 parent: 94446:1cc37c52fed4 user: Benjamin Peterson date: Sun Feb 01 20:59:00 2015 -0500 summary: detect overflow in combinations (closes #23366) files: Lib/test/test_itertools.py | 5 +++++ Misc/NEWS | 2 ++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -137,6 +137,11 @@ self.assertEqual(result, list(combinations2(values, r))) # matches second pure python version self.assertEqual(result, list(combinations3(values, r))) # matches second pure python version + @test_support.bigaddrspacetest + def test_combinations_overflow(self): + with self.assertRaises(OverflowError): + combinations("AA", 2**29) + @test_support.impl_detail("tuple reuse is specific to CPython") def test_combinations_tuple_reuse(self): self.assertEqual(len(set(map(id, combinations('abcde', 3)))), 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,8 @@ Library ------- +- Issue #23366: Fixed possible integer overflow in itertools.combinations. + - Issue #23191: fnmatch functions that use caching are now threadsafe. - Issue #18518: timeit now rejects statements which can't be compiled outside diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2093,6 +2093,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:05:12 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:05:12 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3_=28=2323366=29?= Message-ID: <20150202020454.25867.11193@psf.io> https://hg.python.org/cpython/rev/2f73de7ffcf5 changeset: 94449:2f73de7ffcf5 branch: 3.4 parent: 94445:fb65ac5aaaac parent: 94448:014886dae5c4 user: Benjamin Peterson date: Sun Feb 01 21:00:15 2015 -0500 summary: merge 3.3 (#23366) files: Lib/test/test_itertools.py | 5 +++++ Misc/NEWS | 2 ++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -264,6 +264,11 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, combinations(values, r)) # test pickling + @support.bigaddrspacetest + def test_combinations_overflow(self): + with self.assertRaises(OverflowError): + combinations("AA", 2**29) + # Test implementation detail: tuple re-use @support.impl_detail("tuple reuse is specific to CPython") def test_combinations_tuple_reuse(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,8 @@ Library ------- +- Issue #23366: Fixed possible integer overflow in itertools.combinations. + - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2359,6 +2359,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:05:12 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:05:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjMzNjYp?= Message-ID: <20150202020454.39288.20159@psf.io> https://hg.python.org/cpython/rev/886559229911 changeset: 94450:886559229911 parent: 94447:3231a13a0c82 parent: 94449:2f73de7ffcf5 user: Benjamin Peterson date: Sun Feb 01 21:01:43 2015 -0500 summary: merge 3.4 (#23366) files: Lib/test/test_itertools.py | 5 +++++ Misc/NEWS | 2 ++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -264,6 +264,11 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, combinations(values, r)) # test pickling + @support.bigaddrspacetest + def test_combinations_overflow(self): + with self.assertRaises(OverflowError): + combinations("AA", 2**29) + # Test implementation detail: tuple re-use @support.impl_detail("tuple reuse is specific to CPython") def test_combinations_tuple_reuse(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,8 @@ - Issue #23326: Removed __ne__ implementations. Since fixing default __ne__ implementation in issue #21408 they are redundant. +- Issue #23366: Fixed possible integer overflow in itertools.combinations. + - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2359,6 +2359,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:05:12 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:05:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_detect_overflo?= =?utf-8?q?w_in_combinations_=28closes_=2323366=29?= Message-ID: <20150202020453.34396.20345@psf.io> https://hg.python.org/cpython/rev/014886dae5c4 changeset: 94448:014886dae5c4 branch: 3.3 parent: 94441:1801b2571587 user: Benjamin Peterson date: Sun Feb 01 20:59:00 2015 -0500 summary: detect overflow in combinations (closes #23366) files: Lib/test/test_itertools.py | 5 +++++ Misc/NEWS | 2 ++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -258,6 +258,11 @@ self.pickletest(combinations(values, r)) # test pickling + @support.bigaddrspacetest + def test_combinations_overflow(self): + with self.assertRaises(OverflowError): + combinations("AA", 2**29) + # Test implementation detail: tuple re-use @support.impl_detail("tuple reuse is specific to CPython") def test_combinations_tuple_reuse(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,8 @@ - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. +- Issue #23366: Fixed possible integer overflow in itertools.combinations. + What's New in Python 3.3.6? =========================== diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2326,6 +2326,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:13:50 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:13:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_check_for_over?= =?utf-8?q?flow_in_combinations=5Fwith=5Freplacement_=28closes_=2323365=29?= Message-ID: <20150202021350.34382.1937@psf.io> https://hg.python.org/cpython/rev/93d445cd5f70 changeset: 94452:93d445cd5f70 branch: 3.3 parent: 94448:014886dae5c4 user: Benjamin Peterson date: Sun Feb 01 21:10:47 2015 -0500 summary: check for overflow in combinations_with_replacement (closes #23365) files: Lib/test/test_itertools.py | 6 +++++- Misc/NEWS | 3 +++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -344,8 +344,12 @@ self.pickletest(cwr(values,r)) # test pickling + @support.bigaddrspacetest + def test_combinations_with_replacement_overflow(self): + with self.assertRaises(OverflowError): + combinations_with_replacement("AA", 2**30) + # Test implementation detail: tuple re-use - @support.impl_detail("tuple reuse is specific to CPython") def test_combinations_with_replacement_tuple_reuse(self): cwr = combinations_with_replacement diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,9 @@ - Issue #23366: Fixed possible integer overflow in itertools.combinations. +- Issue #23365: Fixed possible integer overflow in + itertools.combinations_with_replacement. + What's New in Python 3.3.6? =========================== diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2659,6 +2659,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:13:51 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:13:51 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3_=28=2323365=29?= Message-ID: <20150202021350.39276.15842@psf.io> https://hg.python.org/cpython/rev/2e7a02e4cf2c changeset: 94453:2e7a02e4cf2c branch: 3.4 parent: 94449:2f73de7ffcf5 parent: 94452:93d445cd5f70 user: Benjamin Peterson date: Sun Feb 01 21:11:39 2015 -0500 summary: merge 3.3 (#23365) files: Lib/test/test_itertools.py | 6 +++++- Misc/NEWS | 2 ++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -351,8 +351,12 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, cwr(values,r)) # test pickling + @support.bigaddrspacetest + def test_combinations_with_replacement_overflow(self): + with self.assertRaises(OverflowError): + combinations_with_replacement("AA", 2**30) + # Test implementation detail: tuple re-use - @support.impl_detail("tuple reuse is specific to CPython") def test_combinations_with_replacement_tuple_reuse(self): cwr = combinations_with_replacement diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ - Issue #23366: Fixed possible integer overflow in itertools.combinations. +- Issue #23366: Fixed possible integer overflow in itertools.combinations. + - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2704,6 +2704,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:13:51 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:13:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjMzNjUp?= Message-ID: <20150202021350.96098.81716@psf.io> https://hg.python.org/cpython/rev/4d875a690c01 changeset: 94454:4d875a690c01 parent: 94450:886559229911 parent: 94453:2e7a02e4cf2c user: Benjamin Peterson date: Sun Feb 01 21:11:54 2015 -0500 summary: merge 3.4 (#23365) files: Lib/test/test_itertools.py | 6 +++++- Misc/NEWS | 2 ++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -351,8 +351,12 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, cwr(values,r)) # test pickling + @support.bigaddrspacetest + def test_combinations_with_replacement_overflow(self): + with self.assertRaises(OverflowError): + combinations_with_replacement("AA", 2**30) + # Test implementation detail: tuple re-use - @support.impl_detail("tuple reuse is specific to CPython") def test_combinations_with_replacement_tuple_reuse(self): cwr = combinations_with_replacement diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -231,6 +231,8 @@ - Issue #23366: Fixed possible integer overflow in itertools.combinations. +- Issue #23366: Fixed possible integer overflow in itertools.combinations. + - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2704,6 +2704,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:13:51 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:13:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_check_for_over?= =?utf-8?q?flow_in_combinations=5Fwith=5Freplacement_=28closes_=2323365=29?= Message-ID: <20150202021351.106293.11136@psf.io> https://hg.python.org/cpython/rev/366018a91457 changeset: 94455:366018a91457 branch: 2.7 parent: 94451:fe203370c049 user: Benjamin Peterson date: Sun Feb 01 21:10:47 2015 -0500 summary: check for overflow in combinations_with_replacement (closes #23365) files: Lib/test/test_itertools.py | 5 +++++ Misc/NEWS | 3 +++ Modules/itertoolsmodule.c | 4 ++++ 3 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -213,6 +213,11 @@ self.assertEqual(result, list(cwr1(values, r))) # matches first pure python version self.assertEqual(result, list(cwr2(values, r))) # matches second pure python version + @test_support.bigaddrspacetest + def test_combinations_with_replacement_overflow(self): + with self.assertRaises(OverflowError): + combinations_with_replacement("AA", 2**30) + @test_support.impl_detail("tuple reuse is specific to CPython") def test_combinations_with_replacement_tuple_reuse(self): cwr = combinations_with_replacement diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #23365: Fixed possible integer overflow in + itertools.combinations_with_replacement. + - Issue #23366: Fixed possible integer overflow in itertools.combinations. - Issue #23191: fnmatch functions that use caching are now threadsafe. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2346,6 +2346,10 @@ goto error; } + if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "r is too big"); + goto error; + } indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL) { PyErr_NoMemory(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:39:20 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:39:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_check_for_over?= =?utf-8?q?flows_in_permutations=28=29_and_product=28=29_=28closes_=232336?= =?utf-8?q?3=2C_closes?= Message-ID: <20150202023854.106357.36009@psf.io> https://hg.python.org/cpython/rev/7133582b6769 changeset: 94456:7133582b6769 branch: 3.3 parent: 94452:93d445cd5f70 user: Benjamin Peterson date: Sun Feb 01 21:34:07 2015 -0500 summary: check for overflows in permutations() and product() (closes #23363, closes #23364) files: Lib/test/test_itertools.py | 12 ++++++++++++ Misc/NEWS | 4 ++++ Modules/itertoolsmodule.c | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -418,6 +418,13 @@ self.pickletest(permutations(values, r)) # test pickling + @support.bigaddrspacetest + def test_permutations_overflow(self): + with self.assertRaises(OverflowError): + permutations("A", 2**30) + with self.assertRaises(OverflowError): + permutations("A", 2, 2**30) + @support.impl_detail("tuple resuse is CPython specific") def test_permutations_tuple_reuse(self): self.assertEqual(len(set(map(id, permutations('abcde', 3)))), 1) @@ -930,6 +937,11 @@ args = map(iter, args) self.assertEqual(len(list(product(*args))), expected_len) + @support.bigaddrspacetest + def test_product_overflow(self): + with self.assertRaises(OverflowError): + product(["a"]*(2**16), repeat=2**16) + @support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): self.assertEqual(len(set(map(id, product('abc', 'def')))), 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,10 @@ Library ------- +- Issue #23363: Fix possible overflow in itertools.permutations. + +- Issue #23364: Fix possible overflow in itertools.product. + - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1998,8 +1998,17 @@ } } - assert(PyTuple_Check(args)); - nargs = (repeat == 0) ? 0 : PyTuple_GET_SIZE(args); + assert(PyTuple_CheckExact(args)); + if (repeat == 0) { + nargs = 0; + } else { + nargs = PyTuple_GET_SIZE(args); + if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); + return NULL; + } + } npools = nargs * repeat; indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); @@ -2992,6 +3001,11 @@ goto error; } + if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "parameters too large"); + goto error; + } indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL || cycles == NULL) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:39:20 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:39:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?b?IG1lcmdlIDMuMyAoIzIzMzY0LCAjMjMzNjMp?= Message-ID: <20150202023854.34408.32956@psf.io> https://hg.python.org/cpython/rev/9ae055c3db32 changeset: 94457:9ae055c3db32 branch: 3.4 parent: 94453:2e7a02e4cf2c parent: 94456:7133582b6769 user: Benjamin Peterson date: Sun Feb 01 21:35:34 2015 -0500 summary: merge 3.3 (#23364, #23363) files: Lib/test/test_itertools.py | 12 ++++++++++++ Misc/NEWS | 4 ++++ Modules/itertoolsmodule.c | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -426,6 +426,13 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, permutations(values, r)) # test pickling + @support.bigaddrspacetest + def test_permutations_overflow(self): + with self.assertRaises(OverflowError): + permutations("A", 2**30) + with self.assertRaises(OverflowError): + permutations("A", 2, 2**30) + @support.impl_detail("tuple reuse is specific to CPython") def test_permutations_tuple_reuse(self): self.assertEqual(len(set(map(id, permutations('abcde', 3)))), 1) @@ -955,6 +962,11 @@ args = map(iter, args) self.assertEqual(len(list(product(*args))), expected_len) + @support.bigaddrspacetest + def test_product_overflow(self): + with self.assertRaises(OverflowError): + product(["a"]*(2**16), repeat=2**16) + @support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): self.assertEqual(len(set(map(id, product('abc', 'def')))), 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,10 @@ Library ------- +- Issue #23363: Fix possible overflow in itertools.permutations. + +- Issue #23364: Fix possible overflow in itertools.product. + - Issue #23366: Fixed possible integer overflow in itertools.combinations. - Issue #23366: Fixed possible integer overflow in itertools.combinations. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2017,8 +2017,17 @@ } } - assert(PyTuple_Check(args)); - nargs = (repeat == 0) ? 0 : PyTuple_GET_SIZE(args); + assert(PyTuple_CheckExact(args)); + if (repeat == 0) { + nargs = 0; + } else { + nargs = PyTuple_GET_SIZE(args); + if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); + return NULL; + } + } npools = nargs * repeat; indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); @@ -3049,6 +3058,11 @@ goto error; } + if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "parameters too large"); + goto error; + } indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL || cycles == NULL) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:39:20 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:39:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_check_for_over?= =?utf-8?q?flows_in_permutations=28=29_and_product=28=29_=28closes_=232336?= =?utf-8?q?3=2C_closes?= Message-ID: <20150202023854.96098.35857@psf.io> https://hg.python.org/cpython/rev/acc2c3479f2e changeset: 94459:acc2c3479f2e branch: 2.7 parent: 94455:366018a91457 user: Benjamin Peterson date: Sun Feb 01 21:34:07 2015 -0500 summary: check for overflows in permutations() and product() (closes #23363, closes #23364) files: Lib/test/test_itertools.py | 12 ++++++++++++ Misc/NEWS | 4 ++++ Modules/itertoolsmodule.c | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -284,6 +284,13 @@ self.assertEqual(result, list(permutations(values, None))) # test r as None self.assertEqual(result, list(permutations(values))) # test default r + @test_support.bigaddrspacetest + def test_permutations_overflow(self): + with self.assertRaises(OverflowError): + permutations("A", 2**30) + with self.assertRaises(OverflowError): + permutations("A", 2, 2**30) + @test_support.impl_detail("tuple reuse is specific to CPython") def test_permutations_tuple_reuse(self): self.assertEqual(len(set(map(id, permutations('abcde', 3)))), 1) @@ -702,6 +709,11 @@ args = map(iter, args) self.assertEqual(len(list(product(*args))), expected_len) + @test_support.bigaddrspacetest + def test_product_overflow(self): + with self.assertRaises(OverflowError): + product(["a"]*(2**16), repeat=2**16) + @test_support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): self.assertEqual(len(set(map(id, product('abc', 'def')))), 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,10 @@ Library ------- +- Issue #23363: Fix possible overflow in itertools.permutations. + +- Issue #23364: Fix possible overflow in itertools.product. + - Issue #23365: Fixed possible integer overflow in itertools.combinations_with_replacement. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1842,8 +1842,17 @@ } } - assert(PyTuple_Check(args)); - nargs = (repeat == 0) ? 0 : PyTuple_GET_SIZE(args); + assert(PyTuple_CheckExact(args)); + if (repeat == 0) { + nargs = 0; + } else { + nargs = PyTuple_GET_SIZE(args); + if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); + return NULL; + } + } npools = nargs * repeat; indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); @@ -2603,6 +2612,11 @@ goto error; } + if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "parameters too large"); + goto error; + } indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL || cycles == NULL) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 03:39:20 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 02:39:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjMzNjQsICMyMzM2Myk=?= Message-ID: <20150202023854.96072.86609@psf.io> https://hg.python.org/cpython/rev/31dc5a40d2ab changeset: 94458:31dc5a40d2ab parent: 94454:4d875a690c01 parent: 94457:9ae055c3db32 user: Benjamin Peterson date: Sun Feb 01 21:36:01 2015 -0500 summary: merge 3.4 (#23364, #23363) files: Lib/test/test_itertools.py | 12 ++++++++++++ Misc/NEWS | 4 ++++ Modules/itertoolsmodule.c | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -426,6 +426,13 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, permutations(values, r)) # test pickling + @support.bigaddrspacetest + def test_permutations_overflow(self): + with self.assertRaises(OverflowError): + permutations("A", 2**30) + with self.assertRaises(OverflowError): + permutations("A", 2, 2**30) + @support.impl_detail("tuple reuse is specific to CPython") def test_permutations_tuple_reuse(self): self.assertEqual(len(set(map(id, permutations('abcde', 3)))), 1) @@ -955,6 +962,11 @@ args = map(iter, args) self.assertEqual(len(list(product(*args))), expected_len) + @support.bigaddrspacetest + def test_product_overflow(self): + with self.assertRaises(OverflowError): + product(["a"]*(2**16), repeat=2**16) + @support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): self.assertEqual(len(set(map(id, product('abc', 'def')))), 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,10 @@ - Issue #23326: Removed __ne__ implementations. Since fixing default __ne__ implementation in issue #21408 they are redundant. +- Issue #23363: Fix possible overflow in itertools.permutations. + +- Issue #23364: Fix possible overflow in itertools.product. + - Issue #23366: Fixed possible integer overflow in itertools.combinations. - Issue #23366: Fixed possible integer overflow in itertools.combinations. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2017,8 +2017,17 @@ } } - assert(PyTuple_Check(args)); - nargs = (repeat == 0) ? 0 : PyTuple_GET_SIZE(args); + assert(PyTuple_CheckExact(args)); + if (repeat == 0) { + nargs = 0; + } else { + nargs = PyTuple_GET_SIZE(args); + if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); + return NULL; + } + } npools = nargs * repeat; indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); @@ -3049,6 +3058,11 @@ goto error; } + if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || + r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { + PyErr_SetString(PyExc_OverflowError, "parameters too large"); + goto error; + } indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); if (indices == NULL || cycles == NULL) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 07:53:47 2015 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 02 Feb 2015 06:53:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Optimization_guides_sugges?= =?utf-8?q?t_copying_memory_in_an_ascending_direction_when?= Message-ID: <20150202065347.96080.89203@psf.io> https://hg.python.org/cpython/rev/673191aa1724 changeset: 94460:673191aa1724 parent: 94458:31dc5a40d2ab user: Raymond Hettinger date: Sun Feb 01 22:53:41 2015 -0800 summary: Optimization guides suggest copying memory in an ascending direction when possible. files: Modules/_collectionsmodule.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -534,13 +534,13 @@ if (m > leftindex) m = leftindex; assert (m > 0 && m <= len); - src = &rightblock->data[rightindex]; - dest = &leftblock->data[leftindex - 1]; rightindex -= m; leftindex -= m; + src = &rightblock->data[rightindex + 1]; + dest = &leftblock->data[leftindex]; n -= m; do { - *(dest--) = *(src--); + *(dest++) = *(src++); } while (--m); } if (rightindex == -1) { -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Feb 2 09:04:49 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 02 Feb 2015 09:04:49 +0100 Subject: [Python-checkins] Daily reference leaks (4d875a690c01): sum=1 Message-ID: results for 4d875a690c01 on branch "default" -------------------------------------------- test_collections leaked [-2, 0, 0] references, sum=-2 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2SFUL1', '-x'] From python-checkins at python.org Mon Feb 2 14:33:54 2015 From: python-checkins at python.org (berker.peksag) Date: Mon, 02 Feb 2015 13:33:54 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_448=3A_Update_from_Joshua?= =?utf-8?q?_Landau=2E?= Message-ID: <20150202133148.96076.87734@psf.io> https://hg.python.org/peps/rev/04cfd59d12fb changeset: 5687:04cfd59d12fb user: Berker Peksag date: Mon Feb 02 15:31:33 2015 +0200 summary: PEP 448: Update from Joshua Landau. files: pep-0448.txt | 41 ++++++++++++++++++++++----------------- 1 files changed, 23 insertions(+), 18 deletions(-) diff --git a/pep-0448.txt b/pep-0448.txt --- a/pep-0448.txt +++ b/pep-0448.txt @@ -16,11 +16,11 @@ ======== This PEP proposes extended usages of the ``*`` iterable unpacking -operator and ``**`` dictionary unpacking operator +operator and ``**`` dictionary unpacking operators to allow unpacking in more positions, an arbitrary number of -times, and in additional circumstances. Specifically -in function calls, in comprehensions and generator expressions, -and in displays. +times, and in additional circumstances. Specifically, +in function calls, in comprehensions and generator expressions, and +in displays. Function calls are proposed to support an arbitrary number of unpackings rather than just one:: @@ -42,8 +42,7 @@ >>> {'x': 1, **{'y': 2}} {'x': 1, 'y': 2} -In sets and dictionaries, this provides a concise overriding -notation:: +In dictionaries, later values will always override earlier ones:: >>> {'x': 1, **{'x': 2}} {'x': 2} @@ -124,7 +123,9 @@ The addition of unpacking to comprehensions is a logical extension. It's usage will primarily be a neat replacement for ``[i for j in -2D_list for i in j]``, as the more readable ``[*l for l in 2D_list]``. +list_of_lists for i in j]``, as the more readable +``[*l for l in list_of_lists]``. The iterable version, +``(*l for l in list_of_lists)``, replaces ``itertools.chain.from_iterable``. Other uses are possible, but expected to occur rarely. @@ -143,7 +144,7 @@ Currently, if an argument is given multiple times ? such as a positional argument given both positionally and by keyword ? a ``TypeError`` is raised. This remains true for duplicate arguments -provided through multiple keyword argument unpackings, +provided through multiple ``**`` unpackings, e.g. ``f(**{'x': 2}, **{'x': 3})``. A function looks like this:: @@ -176,22 +177,26 @@ {**locals(), "override": None} -However, ``f(*x for x in it)`` and ``f(**x for x in it)`` continue -to raise SyntaxError. +Unbracketed comprehensions in function calls, such as ``f(x for x in it)``, +are already valid. These could be extended to:: + + f(*x for x in it) == f((*x for x in it)) + f(**x for x in it) == f({**x for x in it}) + +However, this is likely to be confusing and is not included in this +PEP. These will throw ``SyntaxError`` and comprehensions with explicit +brackets should be used instead. Disadvantages ============= -The allowable orders for arguments in a function call is more -complicated than before. -The simplest explanation for the rules may be "positional arguments -come first and keyword arguments follow, but iterable unpackings are -allowed after keyword arguments" or "iterable arguments precede -all keyword arguments and keyword argument unpackings, and iterable -argument unpackings precede all keyword argument unpackings". +The allowable orders for arguments in a function call are more +complicated than before. The simplest explanation for the rules +may be "positional arguments precede keyword arguments and ``**`` +unpacking; ``*`` unpacking precedes ``**`` unpacking". -While ``*elements, = iterable`` causes ``elements`` to be a list, +Whilst ``*elements, = iterable`` causes ``elements`` to be a list, ``elements = *iterable,`` causes ``elements`` to be a tuple. The reason for this may confuse people unfamiliar with the construct. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Feb 2 14:37:41 2015 From: python-checkins at python.org (berker.peksag) Date: Mon, 02 Feb 2015 13:37:41 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_editors_list=2E?= Message-ID: <20150202133705.96098.93407@psf.io> https://hg.python.org/peps/rev/803169da11e3 changeset: 5688:803169da11e3 user: Berker Peksag date: Mon Feb 02 15:37:11 2015 +0200 summary: Update PEP editors list. files: pep-0001.txt | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/pep-0001.txt b/pep-0001.txt --- a/pep-0001.txt +++ b/pep-0001.txt @@ -82,11 +82,13 @@ changing their status). See `PEP Editor Responsibilities & Workflow`_ for details. The current editors are: +* Chris Angelico * Anthony Baxter * Georg Brandl * Brett Cannon * David Goodger * Jesse Noller +* Berker Peksag * Guido van Rossum * Barry Warsaw -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Feb 2 16:53:42 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 15:53:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_revert_lineno_?= =?utf-8?q?and_col=5Foffset_changes_from_=2316795_=28closes_=2321295=29?= Message-ID: <20150202155303.96090.24843@psf.io> https://hg.python.org/cpython/rev/7d1c32ddc432 changeset: 94461:7d1c32ddc432 branch: 3.4 parent: 94457:9ae055c3db32 user: Benjamin Peterson date: Mon Feb 02 10:51:20 2015 -0500 summary: revert lineno and col_offset changes from #16795 (closes #21295) files: Lib/test/test_ast.py | 45 +- Misc/NEWS | 3 + Python/ast.c | 35 +- Python/importlib.h | 7812 +++++++++++++++--------------- 4 files changed, 3936 insertions(+), 3959 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -180,36 +180,20 @@ class AST_Tests(unittest.TestCase): - def _assertTrueorder(self, ast_node, parent_pos, reverse_check = False): - def should_reverse_check(parent, child): - # In some situations, the children of nodes occur before - # their parents, for example in a.b.c, a occurs before b - # but a is a child of b. - if isinstance(parent, ast.Call): - if parent.func == child: - return True - if isinstance(parent, (ast.Attribute, ast.Subscript)): - return True - return False - + def _assertTrueorder(self, ast_node, parent_pos): if not isinstance(ast_node, ast.AST) or ast_node._fields is None: return if isinstance(ast_node, (ast.expr, ast.stmt, ast.excepthandler)): node_pos = (ast_node.lineno, ast_node.col_offset) - if reverse_check: - self.assertTrue(node_pos <= parent_pos) - else: - self.assertTrue(node_pos >= parent_pos) + self.assertTrue(node_pos >= parent_pos) parent_pos = (ast_node.lineno, ast_node.col_offset) for name in ast_node._fields: value = getattr(ast_node, name) if isinstance(value, list): for child in value: - self._assertTrueorder(child, parent_pos, - should_reverse_check(ast_node, child)) + self._assertTrueorder(child, parent_pos) elif value is not None: - self._assertTrueorder(value, parent_pos, - should_reverse_check(ast_node, value)) + self._assertTrueorder(value, parent_pos) def test_AST_objects(self): x = ast.AST() @@ -278,9 +262,8 @@ def test_arguments(self): x = ast.arguments() - self.assertEqual(x._fields, ('args', 'vararg', - 'kwonlyargs', 'kw_defaults', - 'kwarg', 'defaults')) + self.assertEqual(x._fields, ('args', 'vararg', 'kwonlyargs', + 'kw_defaults', 'kwarg', 'defaults')) with self.assertRaises(AttributeError): x.vararg @@ -455,7 +438,7 @@ "lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), " "lineno=1, col_offset=5), Str(s='and cheese', lineno=1, " "col_offset=11)], keywords=[], starargs=None, kwargs=None, " - "lineno=1, col_offset=4), lineno=1, col_offset=0)])" + "lineno=1, col_offset=0), lineno=1, col_offset=0)])" ) def test_copy_location(self): @@ -476,7 +459,7 @@ "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), " "lineno=1, col_offset=0), args=[Str(s='spam', lineno=1, " "col_offset=6)], keywords=[], starargs=None, kwargs=None, " - "lineno=1, col_offset=5), lineno=1, col_offset=0), " + "lineno=1, col_offset=0), lineno=1, col_offset=0), " "Expr(value=Call(func=Name(id='spam', ctx=Load(), lineno=1, " "col_offset=0), args=[Str(s='eggs', lineno=1, col_offset=0)], " "keywords=[], starargs=None, kwargs=None, lineno=1, " @@ -973,7 +956,7 @@ ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None)], None, [], [], None, [('Num', (1, 8), 0)]), [('Pass', (1, 12))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], ('arg', (1, 7), 'args', None), [], [], None, []), [('Pass', (1, 14))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], ('arg', (1, 8), 'kwargs', None), []), [('Pass', (1, 17))], [], None)]), - ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None), ('arg', (1, 9), 'b', None), ('arg', (1, 14), 'c', None), ('arg', (1, 22), 'd', None), ('arg', (1, 28), 'e', None)], ('arg', (1, 35), 'args', None), [('arg', (1, 41), 'f', None)], [('Num', (1, 43), 42)], ('arg', (1, 49), 'kwargs', None), [('Num', (1, 11), 1), ('NameConstant', (1, 16), None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Pass', (1, 58))], [], None)]), +('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None), ('arg', (1, 9), 'b', None), ('arg', (1, 14), 'c', None), ('arg', (1, 22), 'd', None), ('arg', (1, 28), 'e', None)], ('arg', (1, 35), 'args', None), [('arg', (1, 41), 'f', None)], [('Num', (1, 43), 42)], ('arg', (1, 49), 'kwargs', None), [('Num', (1, 11), 1), ('NameConstant', (1, 16), None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Pass', (1, 58))], [], None)]), ('Module', [('ClassDef', (1, 0), 'C', [], [], None, None, [('Pass', (1, 8))], [])]), ('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], None, None, [('Pass', (1, 17))], [])]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Return', (1, 8), ('Num', (1, 15), 1))], [], None)]), @@ -985,7 +968,7 @@ ('Module', [('If', (1, 0), ('Name', (1, 3), 'v', ('Load',)), [('Pass', (1, 5))], [])]), ('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',)))], [('Pass', (1, 13))])]), ('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',))), ('withitem', ('Name', (1, 13), 'z', ('Load',)), ('Name', (1, 18), 'q', ('Store',)))], [('Pass', (1, 21))])]), -('Module', [('Raise', (1, 0), ('Call', (1, 15), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], [], None, None), None)]), +('Module', [('Raise', (1, 0), ('Call', (1, 6), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], [], None, None), None)]), ('Module', [('Try', (1, 0), [('Pass', (2, 2))], [('ExceptHandler', (3, 0), ('Name', (3, 7), 'Exception', ('Load',)), None, [('Pass', (4, 2))])], [], [])]), ('Module', [('Try', (1, 0), [('Pass', (2, 2))], [], [], [('Pass', (4, 2))])]), ('Module', [('Assert', (1, 0), ('Name', (1, 7), 'v', ('Load',)), None)]), @@ -1022,17 +1005,17 @@ ('Expression', ('ListComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('GeneratorExp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('Compare', (1, 0), ('Num', (1, 0), 1), [('Lt',), ('Lt',)], [('Num', (1, 4), 2), ('Num', (1, 8), 3)])), -('Expression', ('Call', (1, 1), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))), +('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))), ('Expression', ('Num', (1, 0), 10)), ('Expression', ('Str', (1, 0), 'string')), -('Expression', ('Attribute', (1, 2), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), -('Expression', ('Subscript', (1, 2), ('Name', (1, 0), 'a', ('Load',)), ('Slice', ('Name', (1, 2), 'b', ('Load',)), ('Name', (1, 4), 'c', ('Load',)), None), ('Load',))), +('Expression', ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), +('Expression', ('Subscript', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Slice', ('Name', (1, 2), 'b', ('Load',)), ('Name', (1, 4), 'c', ('Load',)), None), ('Load',))), ('Expression', ('Name', (1, 0), 'v', ('Load',))), ('Expression', ('List', (1, 0), [('Num', (1, 1), 1), ('Num', (1, 3), 2), ('Num', (1, 5), 3)], ('Load',))), ('Expression', ('List', (1, 0), [], ('Load',))), ('Expression', ('Tuple', (1, 0), [('Num', (1, 0), 1), ('Num', (1, 2), 2), ('Num', (1, 4), 3)], ('Load',))), ('Expression', ('Tuple', (1, 1), [('Num', (1, 1), 1), ('Num', (1, 3), 2), ('Num', (1, 5), 3)], ('Load',))), ('Expression', ('Tuple', (1, 0), [], ('Load',))), -('Expression', ('Call', (1, 7), ('Attribute', (1, 6), ('Attribute', (1, 4), ('Attribute', (1, 2), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 12), ('Attribute', (1, 10), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [], None, None)), +('Expression', ('Call', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8), ('Attribute', (1, 8), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [], None, None)), ] main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,6 +11,9 @@ Core and Builtins ----------------- +- Issue #21295: Revert some changes (issue #16795) to AST line numbers and + column offsets that constituted a regression. + - Issue #21408: The default __ne__() now returns NotImplemented if __eq__() returned NotImplemented. Original patch by Martin Panter. diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -1123,7 +1123,7 @@ identifier name; expr_ty annotation = NULL; node *ch; - arg_ty tmp; + arg_ty ret; assert(TYPE(n) == tfpdef || TYPE(n) == vfpdef); ch = CHILD(n, 0); @@ -1139,13 +1139,12 @@ return NULL; } - tmp = arg(name, annotation, c->c_arena); - if (!tmp) + ret = arg(name, annotation, c->c_arena); + if (!ret) return NULL; - - tmp->lineno = LINENO(n); - tmp->col_offset = n->n_col_offset; - return tmp; + ret->lineno = LINENO(n); + ret->col_offset = n->n_col_offset; + return ret; } /* returns -1 if failed to handle keyword only arguments @@ -2103,22 +2102,15 @@ if (NCH(n) == 2) return Call(left_expr, NULL, NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); - else { - expr_ty tmp = ast_for_call(c, CHILD(n, 1), left_expr); - if (!tmp) - return NULL; - - tmp->lineno = LINENO(n); - tmp->col_offset = n->n_col_offset; - return tmp; - } + else + return ast_for_call(c, CHILD(n, 1), left_expr); } - else if (TYPE(CHILD(n, 0)) == DOT ) { + else if (TYPE(CHILD(n, 0)) == DOT) { PyObject *attr_id = NEW_IDENTIFIER(CHILD(n, 1)); if (!attr_id) return NULL; return Attribute(left_expr, attr_id, Load, - LINENO(CHILD(n, 1)), CHILD(n, 1)->n_col_offset, c->c_arena); + LINENO(n), n->n_col_offset, c->c_arena); } else { REQ(CHILD(n, 0), LSQB); @@ -2219,16 +2211,15 @@ tmp = ast_for_trailer(c, ch, e); if (!tmp) return NULL; + tmp->lineno = e->lineno; + tmp->col_offset = e->col_offset; e = tmp; } if (TYPE(CHILD(n, NCH(n) - 1)) == factor) { expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1)); if (!f) return NULL; - tmp = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena); - if (!tmp) - return NULL; - e = tmp; + e = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena); } return e; } diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 16:53:41 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 15:53:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjEyOTUp?= Message-ID: <20150202155303.34398.88559@psf.io> https://hg.python.org/cpython/rev/8ab6b404248c changeset: 94462:8ab6b404248c parent: 94460:673191aa1724 parent: 94461:7d1c32ddc432 user: Benjamin Peterson date: Mon Feb 02 10:52:56 2015 -0500 summary: merge 3.4 (#21295) files: Lib/test/test_ast.py | 45 +- Misc/NEWS | 3 + Python/ast.c | 35 +- Python/importlib.h | 698 +++++++++++++++--------------- 4 files changed, 379 insertions(+), 402 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -180,36 +180,20 @@ class AST_Tests(unittest.TestCase): - def _assertTrueorder(self, ast_node, parent_pos, reverse_check = False): - def should_reverse_check(parent, child): - # In some situations, the children of nodes occur before - # their parents, for example in a.b.c, a occurs before b - # but a is a child of b. - if isinstance(parent, ast.Call): - if parent.func == child: - return True - if isinstance(parent, (ast.Attribute, ast.Subscript)): - return True - return False - + def _assertTrueorder(self, ast_node, parent_pos): if not isinstance(ast_node, ast.AST) or ast_node._fields is None: return if isinstance(ast_node, (ast.expr, ast.stmt, ast.excepthandler)): node_pos = (ast_node.lineno, ast_node.col_offset) - if reverse_check: - self.assertTrue(node_pos <= parent_pos) - else: - self.assertTrue(node_pos >= parent_pos) + self.assertTrue(node_pos >= parent_pos) parent_pos = (ast_node.lineno, ast_node.col_offset) for name in ast_node._fields: value = getattr(ast_node, name) if isinstance(value, list): for child in value: - self._assertTrueorder(child, parent_pos, - should_reverse_check(ast_node, child)) + self._assertTrueorder(child, parent_pos) elif value is not None: - self._assertTrueorder(value, parent_pos, - should_reverse_check(ast_node, value)) + self._assertTrueorder(value, parent_pos) def test_AST_objects(self): x = ast.AST() @@ -278,9 +262,8 @@ def test_arguments(self): x = ast.arguments() - self.assertEqual(x._fields, ('args', 'vararg', - 'kwonlyargs', 'kw_defaults', - 'kwarg', 'defaults')) + self.assertEqual(x._fields, ('args', 'vararg', 'kwonlyargs', + 'kw_defaults', 'kwarg', 'defaults')) with self.assertRaises(AttributeError): x.vararg @@ -455,7 +438,7 @@ "lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), " "lineno=1, col_offset=5), Str(s='and cheese', lineno=1, " "col_offset=11)], keywords=[], starargs=None, kwargs=None, " - "lineno=1, col_offset=4), lineno=1, col_offset=0)])" + "lineno=1, col_offset=0), lineno=1, col_offset=0)])" ) def test_copy_location(self): @@ -476,7 +459,7 @@ "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), " "lineno=1, col_offset=0), args=[Str(s='spam', lineno=1, " "col_offset=6)], keywords=[], starargs=None, kwargs=None, " - "lineno=1, col_offset=5), lineno=1, col_offset=0), " + "lineno=1, col_offset=0), lineno=1, col_offset=0), " "Expr(value=Call(func=Name(id='spam', ctx=Load(), lineno=1, " "col_offset=0), args=[Str(s='eggs', lineno=1, col_offset=0)], " "keywords=[], starargs=None, kwargs=None, lineno=1, " @@ -973,7 +956,7 @@ ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None)], None, [], [], None, [('Num', (1, 8), 0)]), [('Pass', (1, 12))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], ('arg', (1, 7), 'args', None), [], [], None, []), [('Pass', (1, 14))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], ('arg', (1, 8), 'kwargs', None), []), [('Pass', (1, 17))], [], None)]), - ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None), ('arg', (1, 9), 'b', None), ('arg', (1, 14), 'c', None), ('arg', (1, 22), 'd', None), ('arg', (1, 28), 'e', None)], ('arg', (1, 35), 'args', None), [('arg', (1, 41), 'f', None)], [('Num', (1, 43), 42)], ('arg', (1, 49), 'kwargs', None), [('Num', (1, 11), 1), ('NameConstant', (1, 16), None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Pass', (1, 58))], [], None)]), +('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None), ('arg', (1, 9), 'b', None), ('arg', (1, 14), 'c', None), ('arg', (1, 22), 'd', None), ('arg', (1, 28), 'e', None)], ('arg', (1, 35), 'args', None), [('arg', (1, 41), 'f', None)], [('Num', (1, 43), 42)], ('arg', (1, 49), 'kwargs', None), [('Num', (1, 11), 1), ('NameConstant', (1, 16), None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Pass', (1, 58))], [], None)]), ('Module', [('ClassDef', (1, 0), 'C', [], [], None, None, [('Pass', (1, 8))], [])]), ('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], None, None, [('Pass', (1, 17))], [])]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Return', (1, 8), ('Num', (1, 15), 1))], [], None)]), @@ -985,7 +968,7 @@ ('Module', [('If', (1, 0), ('Name', (1, 3), 'v', ('Load',)), [('Pass', (1, 5))], [])]), ('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',)))], [('Pass', (1, 13))])]), ('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',))), ('withitem', ('Name', (1, 13), 'z', ('Load',)), ('Name', (1, 18), 'q', ('Store',)))], [('Pass', (1, 21))])]), -('Module', [('Raise', (1, 0), ('Call', (1, 15), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], [], None, None), None)]), +('Module', [('Raise', (1, 0), ('Call', (1, 6), ('Name', (1, 6), 'Exception', ('Load',)), [('Str', (1, 16), 'string')], [], None, None), None)]), ('Module', [('Try', (1, 0), [('Pass', (2, 2))], [('ExceptHandler', (3, 0), ('Name', (3, 7), 'Exception', ('Load',)), None, [('Pass', (4, 2))])], [], [])]), ('Module', [('Try', (1, 0), [('Pass', (2, 2))], [], [], [('Pass', (4, 2))])]), ('Module', [('Assert', (1, 0), ('Name', (1, 7), 'v', ('Load',)), None)]), @@ -1022,17 +1005,17 @@ ('Expression', ('ListComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('GeneratorExp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('Compare', (1, 0), ('Num', (1, 0), 1), [('Lt',), ('Lt',)], [('Num', (1, 4), 2), ('Num', (1, 8), 3)])), -('Expression', ('Call', (1, 1), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))), +('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))), ('Expression', ('Num', (1, 0), 10)), ('Expression', ('Str', (1, 0), 'string')), -('Expression', ('Attribute', (1, 2), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), -('Expression', ('Subscript', (1, 2), ('Name', (1, 0), 'a', ('Load',)), ('Slice', ('Name', (1, 2), 'b', ('Load',)), ('Name', (1, 4), 'c', ('Load',)), None), ('Load',))), +('Expression', ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), +('Expression', ('Subscript', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Slice', ('Name', (1, 2), 'b', ('Load',)), ('Name', (1, 4), 'c', ('Load',)), None), ('Load',))), ('Expression', ('Name', (1, 0), 'v', ('Load',))), ('Expression', ('List', (1, 0), [('Num', (1, 1), 1), ('Num', (1, 3), 2), ('Num', (1, 5), 3)], ('Load',))), ('Expression', ('List', (1, 0), [], ('Load',))), ('Expression', ('Tuple', (1, 0), [('Num', (1, 0), 1), ('Num', (1, 2), 2), ('Num', (1, 4), 3)], ('Load',))), ('Expression', ('Tuple', (1, 1), [('Num', (1, 1), 1), ('Num', (1, 3), 2), ('Num', (1, 5), 3)], ('Load',))), ('Expression', ('Tuple', (1, 0), [], ('Load',))), -('Expression', ('Call', (1, 7), ('Attribute', (1, 6), ('Attribute', (1, 4), ('Attribute', (1, 2), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 12), ('Attribute', (1, 10), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [], None, None)), +('Expression', ('Call', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8), ('Attribute', (1, 8), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [], None, None)), ] main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #21295: Revert some changes (issue #16795) to AST line numbers and + column offsets that constituted a regression. + - Issue #22986: Allow changing an object's __class__ between a dynamic type and static type in some cases. diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -1127,7 +1127,7 @@ identifier name; expr_ty annotation = NULL; node *ch; - arg_ty tmp; + arg_ty ret; assert(TYPE(n) == tfpdef || TYPE(n) == vfpdef); ch = CHILD(n, 0); @@ -1143,13 +1143,12 @@ return NULL; } - tmp = arg(name, annotation, c->c_arena); - if (!tmp) + ret = arg(name, annotation, c->c_arena); + if (!ret) return NULL; - - tmp->lineno = LINENO(n); - tmp->col_offset = n->n_col_offset; - return tmp; + ret->lineno = LINENO(n); + ret->col_offset = n->n_col_offset; + return ret; } /* returns -1 if failed to handle keyword only arguments @@ -2107,22 +2106,15 @@ if (NCH(n) == 2) return Call(left_expr, NULL, NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); - else { - expr_ty tmp = ast_for_call(c, CHILD(n, 1), left_expr); - if (!tmp) - return NULL; - - tmp->lineno = LINENO(n); - tmp->col_offset = n->n_col_offset; - return tmp; - } + else + return ast_for_call(c, CHILD(n, 1), left_expr); } - else if (TYPE(CHILD(n, 0)) == DOT ) { + else if (TYPE(CHILD(n, 0)) == DOT) { PyObject *attr_id = NEW_IDENTIFIER(CHILD(n, 1)); if (!attr_id) return NULL; return Attribute(left_expr, attr_id, Load, - LINENO(CHILD(n, 1)), CHILD(n, 1)->n_col_offset, c->c_arena); + LINENO(n), n->n_col_offset, c->c_arena); } else { REQ(CHILD(n, 0), LSQB); @@ -2223,16 +2215,15 @@ tmp = ast_for_trailer(c, ch, e); if (!tmp) return NULL; + tmp->lineno = e->lineno; + tmp->col_offset = e->col_offset; e = tmp; } if (TYPE(CHILD(n, NCH(n) - 1)) == factor) { expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1)); if (!f) return NULL; - tmp = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena); - if (!tmp) - return NULL; - e = tmp; + e = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena); } return e; } diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 17:35:27 2015 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 02 Feb 2015 16:35:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_23359=3A_Tighten_inn?= =?utf-8?q?er_search_loop_for_sets_=28don=27t_and-mask_every_entry?= Message-ID: <20150202163507.25859.398@psf.io> https://hg.python.org/cpython/rev/0b3bc51341aa changeset: 94463:0b3bc51341aa user: Raymond Hettinger date: Mon Feb 02 08:35:00 2015 -0800 summary: Issue 23359: Tighten inner search loop for sets (don't and-mask every entry lookup). files: Objects/setobject.c | 77 ++++++++++++++++++++++---------- 1 files changed, 53 insertions(+), 24 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -88,31 +88,60 @@ if (entry->key == dummy && freeslot == NULL) freeslot = entry; - for (j = 1 ; j <= LINEAR_PROBES ; j++) { - entry = &table[(i + j) & mask]; - if (entry->key == NULL) - goto found_null; - if (entry->hash == hash) { - PyObject *startkey = entry->key; - assert(startkey != dummy); - if (startkey == key) - return entry; - if (PyUnicode_CheckExact(startkey) - && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) - return entry; - Py_INCREF(startkey); - cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); - Py_DECREF(startkey); - if (cmp < 0) - return NULL; - if (table != so->table || entry->key != startkey) - return set_lookkey(so, key, hash); - if (cmp > 0) - return entry; + if (i + LINEAR_PROBES <= mask) { + for (j = 1 ; j <= LINEAR_PROBES ; j++) { + entry++; + if (entry->key == NULL) + goto found_null; + if (entry->hash == hash) { + PyObject *startkey = entry->key; + assert(startkey != dummy); + if (startkey == key) + return entry; + if (PyUnicode_CheckExact(startkey) + && PyUnicode_CheckExact(key) + && unicode_eq(startkey, key)) + return entry; + Py_INCREF(startkey); + cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + Py_DECREF(startkey); + if (cmp < 0) + return NULL; + if (table != so->table || entry->key != startkey) + return set_lookkey(so, key, hash); + if (cmp > 0) + return entry; + } + if (entry->key == dummy && freeslot == NULL) + freeslot = entry; } - if (entry->key == dummy && freeslot == NULL) - freeslot = entry; + } else { + for (j = 1 ; j <= LINEAR_PROBES ; j++) { + entry = &table[(i + j) & mask]; + if (entry->key == NULL) + goto found_null; + if (entry->hash == hash) { + PyObject *startkey = entry->key; + assert(startkey != dummy); + if (startkey == key) + return entry; + if (PyUnicode_CheckExact(startkey) + && PyUnicode_CheckExact(key) + && unicode_eq(startkey, key)) + return entry; + Py_INCREF(startkey); + cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + Py_DECREF(startkey); + if (cmp < 0) + return NULL; + if (table != so->table || entry->key != startkey) + return set_lookkey(so, key, hash); + if (cmp > 0) + return entry; + } + if (entry->key == dummy && freeslot == NULL) + freeslot = entry; + } } perturb >>= PERTURB_SHIFT; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 18:38:10 2015 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 Feb 2015 17:38:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20150202173756.39270.61855@psf.io> https://hg.python.org/cpython/rev/42b376c8cf60 changeset: 94465:42b376c8cf60 parent: 94463:0b3bc51341aa parent: 94464:2cd6621a9fbc user: Victor Stinner date: Mon Feb 02 18:36:59 2015 +0100 summary: Merge 3.4 (asyncio) files: Lib/asyncio/test_utils.py | 4 ++++ Lib/asyncio/unix_events.py | 12 ++++++++++-- Lib/asyncio/windows_events.py | 11 +++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py --- a/Lib/asyncio/test_utils.py +++ b/Lib/asyncio/test_utils.py @@ -416,6 +416,10 @@ def tearDown(self): events.set_event_loop(None) + # Detect CPython bug #23353: ensure that yield/yield-from is not used + # in an except block of a generator + self.assertEqual(sys.exc_info(), (None, None, None)) + @contextlib.contextmanager def disable_logger(): diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -186,10 +186,18 @@ self._child_watcher_callback, transp) try: yield from waiter - except: + except Exception as exc: + # Workaround CPython bug #23353: using yield/yield-from in an + # except block of a generator doesn't clear properly + # sys.exc_info() + err = exc + else: + err = None + + if err is not None: transp.close() yield from transp._wait() - raise + raise err return transp diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -373,10 +373,17 @@ **kwargs) try: yield from waiter - except: + except Exception as exc: + # Workaround CPython bug #23353: using yield/yield-from in an + # except block of a generator doesn't clear properly sys.exc_info() + err = exc + else: + err = None + + if err is not None: transp.close() yield from transp._wait() - raise + raise err return transp -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 18:38:13 2015 From: python-checkins at python.org (victor.stinner) Date: Mon, 02 Feb 2015 17:38:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzUz?= =?utf-8?q?=2C_asyncio=3A_Workaround_CPython_bug_=2323353?= Message-ID: <20150202173755.25859.54709@psf.io> https://hg.python.org/cpython/rev/2cd6621a9fbc changeset: 94464:2cd6621a9fbc branch: 3.4 parent: 94461:7d1c32ddc432 user: Victor Stinner date: Mon Feb 02 18:36:31 2015 +0100 summary: Issue #23353, asyncio: Workaround CPython bug #23353 Don't use yield/yield-from in an except block of a generator. Store the exception and handle it outside the except block. files: Lib/asyncio/test_utils.py | 4 ++++ Lib/asyncio/unix_events.py | 12 ++++++++++-- Lib/asyncio/windows_events.py | 11 +++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py --- a/Lib/asyncio/test_utils.py +++ b/Lib/asyncio/test_utils.py @@ -416,6 +416,10 @@ def tearDown(self): events.set_event_loop(None) + # Detect CPython bug #23353: ensure that yield/yield-from is not used + # in an except block of a generator + self.assertEqual(sys.exc_info(), (None, None, None)) + @contextlib.contextmanager def disable_logger(): diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -186,10 +186,18 @@ self._child_watcher_callback, transp) try: yield from waiter - except: + except Exception as exc: + # Workaround CPython bug #23353: using yield/yield-from in an + # except block of a generator doesn't clear properly + # sys.exc_info() + err = exc + else: + err = None + + if err is not None: transp.close() yield from transp._wait() - raise + raise err return transp diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -373,10 +373,17 @@ **kwargs) try: yield from waiter - except: + except Exception as exc: + # Workaround CPython bug #23353: using yield/yield-from in an + # except block of a generator doesn't clear properly sys.exc_info() + err = exc + else: + err = None + + if err is not None: transp.close() yield from transp._wait() - raise + raise err return transp -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 20:06:38 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 19:06:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogX2NsZWFyX3R5cGVf?= =?utf-8?q?cache_is_cpython-only?= Message-ID: <20150202190633.106327.12022@psf.io> https://hg.python.org/cpython/rev/70966f32793d changeset: 94467:70966f32793d branch: 3.4 parent: 94464:2cd6621a9fbc user: Benjamin Peterson date: Mon Feb 02 14:06:11 2015 -0500 summary: _clear_type_cache is cpython-only files: Lib/test/test_sys.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -539,6 +539,7 @@ test.support.get_attribute(sys, "getwindowsversion") self.assert_raise_on_new_sys_type(sys.getwindowsversion()) + @test.test_support.cpython_only def test_clear_type_cache(self): sys._clear_type_cache() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 20:06:38 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 19:06:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150202190633.106264.71652@psf.io> https://hg.python.org/cpython/rev/c670249c7956 changeset: 94468:c670249c7956 parent: 94465:42b376c8cf60 parent: 94467:70966f32793d user: Benjamin Peterson date: Mon Feb 02 14:06:29 2015 -0500 summary: merge 3.4 files: Lib/test/test_sys.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -539,6 +539,7 @@ test.support.get_attribute(sys, "getwindowsversion") self.assert_raise_on_new_sys_type(sys.getwindowsversion()) + @test.test_support.cpython_only def test_clear_type_cache(self): sys._clear_type_cache() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 20:06:38 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 19:06:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogX2NsZWFyX3R5cGVf?= =?utf-8?q?cache_is_cpython-only?= Message-ID: <20150202190633.34388.58215@psf.io> https://hg.python.org/cpython/rev/83b75b016c77 changeset: 94466:83b75b016c77 branch: 2.7 parent: 94459:acc2c3479f2e user: Benjamin Peterson date: Mon Feb 02 14:06:11 2015 -0500 summary: _clear_type_cache is cpython-only files: Lib/test/test_sys.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -425,6 +425,7 @@ self.assertEqual(type(getattr(sys.flags, attr)), int, attr) self.assertTrue(repr(sys.flags)) + @test.test_support.cpython_only def test_clear_type_cache(self): sys._clear_type_cache() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 20:22:29 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 19:22:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_adjust_for_py3?= =?utf-8?q?k_module_renaming?= Message-ID: <20150202192225.34390.27827@psf.io> https://hg.python.org/cpython/rev/dc699f150fd3 changeset: 94469:dc699f150fd3 branch: 3.4 parent: 94467:70966f32793d user: Benjamin Peterson date: Mon Feb 02 14:22:13 2015 -0500 summary: adjust for py3k module renaming files: Lib/test/test_sys.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -539,7 +539,7 @@ test.support.get_attribute(sys, "getwindowsversion") self.assert_raise_on_new_sys_type(sys.getwindowsversion()) - @test.test_support.cpython_only + @test.support.cpython_only def test_clear_type_cache(self): sys._clear_type_cache() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 20:22:29 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 19:22:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150202192225.25867.49368@psf.io> https://hg.python.org/cpython/rev/298f56ee74f4 changeset: 94470:298f56ee74f4 parent: 94468:c670249c7956 parent: 94469:dc699f150fd3 user: Benjamin Peterson date: Mon Feb 02 14:22:19 2015 -0500 summary: merge 3.4 files: Lib/test/test_sys.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -539,7 +539,7 @@ test.support.get_attribute(sys, "getwindowsversion") self.assert_raise_on_new_sys_type(sys.getwindowsversion()) - @test.test_support.cpython_only + @test.support.cpython_only def test_clear_type_cache(self): sys._clear_type_cache() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 21:39:28 2015 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 02 Feb 2015 20:39:28 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_with_latest_change?= =?utf-8?q?s=2E?= Message-ID: <20150202203858.96068.23038@psf.io> https://hg.python.org/peps/rev/9cdb1b30f643 changeset: 5689:9cdb1b30f643 user: Antoine Pitrou date: Mon Feb 02 21:38:52 2015 +0100 summary: Update PEP with latest changes. files: pep-0475.txt | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/pep-0475.txt b/pep-0475.txt --- a/pep-0475.txt +++ b/pep-0475.txt @@ -167,6 +167,7 @@ Example of standard library functions that need to be modified to comply with this PEP: +* ``open()``, ``os.open()`` * ``os.read()``, ``io.FileIO.read()``, ``io.FileIO.readinto()`` * ``os.write()``, ``io.FileIO.write()`` * ``os.waitpid()`` @@ -187,6 +188,12 @@ (note: the ``selector`` module already retries on ``InterruptedError``, but it doesn't recompute the timeout yet) +``os.close`` and ``close()`` methods are a special case: they will ignore +EINTR instead of retrying. The reason is complex but involves behaviour +under Linux and the fact that `the file descriptor may really be closed +`_ even if EINTR is returned. + + InterruptedError handling ------------------------- -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Feb 2 21:47:18 2015 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 02 Feb 2015 20:47:18 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Mark_accepted?= Message-ID: <20150202204701.106379.91104@psf.io> https://hg.python.org/peps/rev/7edc0eddb68f changeset: 5690:7edc0eddb68f user: Antoine Pitrou date: Mon Feb 02 21:46:57 2015 +0100 summary: Mark accepted files: pep-0475.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0475.txt b/pep-0475.txt --- a/pep-0475.txt +++ b/pep-0475.txt @@ -4,11 +4,12 @@ Last-Modified: $Date$ Author: Charles-Fran?ois Natali , Victor Stinner BDFL-Delegate: Antoine Pitrou -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 29-July-2014 Python-Version: 3.5 +Resolution: https://mail.python.org/pipermail/python-dev/2015-February/138018.html Abstract -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Feb 2 23:47:39 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 22:47:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_reduce_memory_?= =?utf-8?q?usage_of_test_=28closes_=2323369=29?= Message-ID: <20150202224736.106317.76992@psf.io> https://hg.python.org/cpython/rev/5c730d30ffbc changeset: 94471:5c730d30ffbc branch: 3.3 parent: 94456:7133582b6769 user: Benjamin Peterson date: Mon Feb 02 17:47:07 2015 -0500 summary: reduce memory usage of test (closes #23369) files: Lib/test/test_json/test_encode_basestring_ascii.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -45,6 +45,7 @@ class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): @bigaddrspacetest def test_overflow(self): - s = "\uffff"*((2**32)//6 + 1) + size = (2**32)//6 + 1 + s = "\x00"*size with self.assertRaises(OverflowError): self.json.encoder.encode_basestring_ascii(s) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 23:47:39 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 22:47:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150202224736.96094.55799@psf.io> https://hg.python.org/cpython/rev/651aa21433ba changeset: 94473:651aa21433ba parent: 94470:298f56ee74f4 parent: 94472:b883bb8bd744 user: Benjamin Peterson date: Mon Feb 02 17:47:31 2015 -0500 summary: merge 3.4 files: Lib/test/test_json/test_encode_basestring_ascii.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -42,6 +42,7 @@ class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): @bigaddrspacetest def test_overflow(self): - s = "\uffff"*((2**32)//6 + 1) + size = (2**32)//6 + 1 + s = "\x00"*size with self.assertRaises(OverflowError): self.json.encoder.encode_basestring_ascii(s) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 2 23:47:39 2015 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 02 Feb 2015 22:47:39 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3?= Message-ID: <20150202224736.39292.30713@psf.io> https://hg.python.org/cpython/rev/b883bb8bd744 changeset: 94472:b883bb8bd744 branch: 3.4 parent: 94469:dc699f150fd3 parent: 94471:5c730d30ffbc user: Benjamin Peterson date: Mon Feb 02 17:47:26 2015 -0500 summary: merge 3.3 files: Lib/test/test_json/test_encode_basestring_ascii.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_json/test_encode_basestring_ascii.py b/Lib/test/test_json/test_encode_basestring_ascii.py --- a/Lib/test/test_json/test_encode_basestring_ascii.py +++ b/Lib/test/test_json/test_encode_basestring_ascii.py @@ -45,6 +45,7 @@ class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest): @bigaddrspacetest def test_overflow(self): - s = "\uffff"*((2**32)//6 + 1) + size = (2**32)//6 + 1 + s = "\x00"*size with self.assertRaises(OverflowError): self.json.encoder.encode_basestring_ascii(s) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 01:05:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 00:05:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMDk5?= =?utf-8?q?=3A_Closing_io=2EBytesIO_with_exported_buffer_is_rejected_now_t?= =?utf-8?q?o?= Message-ID: <20150203000516.106346.11737@psf.io> https://hg.python.org/cpython/rev/e62d54128bd3 changeset: 94480:e62d54128bd3 branch: 3.4 parent: 94477:98c720c3e061 user: Serhiy Storchaka date: Tue Feb 03 02:00:18 2015 +0200 summary: Issue #23099: Closing io.BytesIO with exported buffer is rejected now to prevent corrupting exported buffer. files: Doc/library/io.rst | 13 +++++++------ Lib/_pyio.py | 6 ++++++ Lib/test/test_memoryio.py | 7 ++++++- Misc/NEWS | 3 +++ Modules/_io/bytesio.c | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -563,7 +563,8 @@ .. class:: BytesIO([initial_bytes]) A stream implementation using an in-memory bytes buffer. It inherits - :class:`BufferedIOBase`. + :class:`BufferedIOBase`. The buffer is discarded when the + :meth:`~IOBase.close` method is called. The argument *initial_bytes* contains optional initial :class:`bytes` data. @@ -584,7 +585,7 @@ .. note:: As long as the view exists, the :class:`BytesIO` object cannot be - resized. + resized or closed. .. versionadded:: 3.2 @@ -592,6 +593,7 @@ Return :class:`bytes` containing the entire contents of the buffer. + .. method:: read1() In :class:`BytesIO`, this is the same as :meth:`read`. @@ -858,7 +860,8 @@ .. class:: StringIO(initial_value='', newline='\\n') - An in-memory stream for text I/O. + An in-memory stream for text I/O. The text buffer is discarded when the + :meth:`~IOBase.close` method is called. The initial value of the buffer (an empty string by default) can be set by providing *initial_value*. The *newline* argument works like that of @@ -870,9 +873,7 @@ .. method:: getvalue() - Return a ``str`` containing the entire contents of the buffer at any - time before the :class:`StringIO` object's :meth:`close` method is - called. + Return a ``str`` containing the entire contents of the buffer. Example usage:: diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -833,8 +833,14 @@ def getbuffer(self): """Return a readable and writable view of the buffer. """ + if self.closed: + raise ValueError("getbuffer on closed file") return memoryview(self._buffer) + def close(self): + self._buffer.clear() + super().close() + def read(self, size=None): if self.closed: raise ValueError("read from closed file") diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -398,14 +398,19 @@ # raises a BufferError. self.assertRaises(BufferError, memio.write, b'x' * 100) self.assertRaises(BufferError, memio.truncate) + self.assertRaises(BufferError, memio.close) + self.assertFalse(memio.closed) # Mutating the buffer updates the BytesIO buf[3:6] = b"abc" self.assertEqual(bytes(buf), b"123abc7890") self.assertEqual(memio.getvalue(), b"123abc7890") - # After the buffer gets released, we can resize the BytesIO again + # After the buffer gets released, we can resize and close the BytesIO + # again del buf support.gc_collect() memio.truncate() + memio.close() + self.assertRaises(ValueError, memio.getbuffer) class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,9 @@ Library ------- +- Issue #23099: Closing io.BytesIO with exported buffer is rejected now to + prevent corrupting exported buffer. + - Issue #23363: Fix possible overflow in itertools.permutations. - Issue #23364: Fix possible overflow in itertools.product. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -657,6 +657,7 @@ static PyObject * bytesio_close(bytesio *self) { + CHECK_EXPORTS(self); if (self->buf != NULL) { PyMem_Free(self->buf); self->buf = NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 01:05:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 00:05:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogSXNzdWVzICMyMzM2MywgIzIzMzY0LCAjMjMzNjUsICMyMzM2NjogRml4?= =?utf-8?q?ed_itertools_overflow_tests=2E?= Message-ID: <20150203000516.39272.69905@psf.io> https://hg.python.org/cpython/rev/4cb316fe6bf2 changeset: 94479:4cb316fe6bf2 parent: 94478:0024537a4687 parent: 94477:98c720c3e061 user: Serhiy Storchaka date: Tue Feb 03 01:50:31 2015 +0200 summary: Issues #23363, #23364, #23365, #23366: Fixed itertools overflow tests. Used PyMem_New to check overflow. files: Lib/test/test_itertools.py | 12 +++++------- Modules/itertoolsmodule.c | 26 ++++++-------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -266,7 +266,7 @@ @support.bigaddrspacetest def test_combinations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations("AA", 2**29) # Test implementation detail: tuple re-use @@ -353,7 +353,7 @@ @support.bigaddrspacetest def test_combinations_with_replacement_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations_with_replacement("AA", 2**30) # Test implementation detail: tuple re-use @@ -428,10 +428,8 @@ @support.bigaddrspacetest def test_permutations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): permutations("A", 2**30) - with self.assertRaises(OverflowError): - permutations("A", 2, 2**30) @support.impl_detail("tuple reuse is specific to CPython") def test_permutations_tuple_reuse(self): @@ -964,8 +962,8 @@ @support.bigaddrspacetest def test_product_overflow(self): - with self.assertRaises(OverflowError): - product(["a"]*(2**16), repeat=2**16) + with self.assertRaises((OverflowError, MemoryError)): + product(*(['ab']*2**5), repeat=2**25) @support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2022,15 +2022,14 @@ nargs = 0; } else { nargs = PyTuple_GET_SIZE(args); - if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + if ((size_t)nargs > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)/repeat) { PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); return NULL; } } npools = nargs * repeat; - indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, npools); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2368,11 +2367,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2713,11 +2708,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -3058,13 +3049,8 @@ goto error; } - if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "parameters too large"); - goto error; - } - indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); - cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, n); + cycles = PyMem_New(Py_ssize_t, r); if (indices == NULL || cycles == NULL) { PyErr_NoMemory(); goto error; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 01:05:58 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 00:05:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322896=3A_Fixed_us?= =?utf-8?q?ing_=5Fgetbuffer=28=29_in_recently_added_=5FPyBytes=5FFormat=28?= =?utf-8?b?KS4=?= Message-ID: <20150203000515.39296.45267@psf.io> https://hg.python.org/cpython/rev/0024537a4687 changeset: 94478:0024537a4687 parent: 94475:2e684ce772de user: Serhiy Storchaka date: Tue Feb 03 01:49:18 2015 +0200 summary: Issue #22896: Fixed using _getbuffer() in recently added _PyBytes_Format(). files: Objects/bytesobject.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -622,14 +622,13 @@ int isnumok; PyObject *v = NULL; PyObject *temp = NULL; - Py_buffer buf; + Py_buffer buf = {NULL, NULL}; char *pbuf; int sign; Py_ssize_t len; char formatbuf[FORMATBUFLEN]; /* For format{int,char}() */ - buf.obj = NULL; fmt++; if (*fmt == '(') { char *keystart; @@ -790,7 +789,7 @@ Py_DECREF(temp); goto error; } - if (_getbuffer(repr, &buf) < 0) { + if (PyObject_GetBuffer(repr, &buf, PyBUF_SIMPLE) != 0) { temp = format_obj(repr); if (temp == NULL) { Py_DECREF(repr); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 01:05:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 00:05:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_Issues_=2323363=2C_=2323364=2C_=2323365=2C_=2323366=3A_Fixed_i?= =?utf-8?q?tertools_overflow_tests=2E?= Message-ID: <20150203000515.96094.80555@psf.io> https://hg.python.org/cpython/rev/98c720c3e061 changeset: 94477:98c720c3e061 branch: 3.4 parent: 94474:1da9630e9b7f parent: 94476:356ed025dbae user: Serhiy Storchaka date: Tue Feb 03 01:35:10 2015 +0200 summary: Issues #23363, #23364, #23365, #23366: Fixed itertools overflow tests. Used PyMem_New to check overflow. files: Lib/test/test_itertools.py | 12 +++++------- Modules/itertoolsmodule.c | 26 ++++++-------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -266,7 +266,7 @@ @support.bigaddrspacetest def test_combinations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations("AA", 2**29) # Test implementation detail: tuple re-use @@ -353,7 +353,7 @@ @support.bigaddrspacetest def test_combinations_with_replacement_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations_with_replacement("AA", 2**30) # Test implementation detail: tuple re-use @@ -428,10 +428,8 @@ @support.bigaddrspacetest def test_permutations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): permutations("A", 2**30) - with self.assertRaises(OverflowError): - permutations("A", 2, 2**30) @support.impl_detail("tuple reuse is specific to CPython") def test_permutations_tuple_reuse(self): @@ -964,8 +962,8 @@ @support.bigaddrspacetest def test_product_overflow(self): - with self.assertRaises(OverflowError): - product(["a"]*(2**16), repeat=2**16) + with self.assertRaises((OverflowError, MemoryError)): + product(*(['ab']*2**5), repeat=2**25) @support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2022,15 +2022,14 @@ nargs = 0; } else { nargs = PyTuple_GET_SIZE(args); - if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + if ((size_t)nargs > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)/repeat) { PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); return NULL; } } npools = nargs * repeat; - indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, npools); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2368,11 +2367,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2713,11 +2708,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -3058,13 +3049,8 @@ goto error; } - if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "parameters too large"); - goto error; - } - indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); - cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, n); + cycles = PyMem_New(Py_ssize_t, r); if (indices == NULL || cycles == NULL) { PyErr_NoMemory(); goto error; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 01:05:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 00:05:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWVzICMyMzM2?= =?utf-8?q?3=2C_=2323364=2C_=2323365=2C_=2323366=3A_Fixed_itertools_overfl?= =?utf-8?q?ow_tests=2E?= Message-ID: <20150203000515.106264.31815@psf.io> https://hg.python.org/cpython/rev/356ed025dbae changeset: 94476:356ed025dbae branch: 3.3 parent: 94471:5c730d30ffbc user: Serhiy Storchaka date: Tue Feb 03 01:34:09 2015 +0200 summary: Issues #23363, #23364, #23365, #23366: Fixed itertools overflow tests. Used PyMem_New to check overflow. files: Lib/test/test_itertools.py | 12 +++++------- Modules/itertoolsmodule.c | 26 ++++++-------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -260,7 +260,7 @@ @support.bigaddrspacetest def test_combinations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations("AA", 2**29) # Test implementation detail: tuple re-use @@ -346,7 +346,7 @@ @support.bigaddrspacetest def test_combinations_with_replacement_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations_with_replacement("AA", 2**30) # Test implementation detail: tuple re-use @@ -420,10 +420,8 @@ @support.bigaddrspacetest def test_permutations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): permutations("A", 2**30) - with self.assertRaises(OverflowError): - permutations("A", 2, 2**30) @support.impl_detail("tuple resuse is CPython specific") def test_permutations_tuple_reuse(self): @@ -939,8 +937,8 @@ @support.bigaddrspacetest def test_product_overflow(self): - with self.assertRaises(OverflowError): - product(["a"]*(2**16), repeat=2**16) + with self.assertRaises((OverflowError, MemoryError)): + product(*(['ab']*2**5), repeat=2**25) @support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2003,15 +2003,14 @@ nargs = 0; } else { nargs = PyTuple_GET_SIZE(args); - if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + if ((size_t)nargs > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)/repeat) { PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); return NULL; } } npools = nargs * repeat; - indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, npools); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2335,11 +2334,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2668,11 +2663,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -3001,13 +2992,8 @@ goto error; } - if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "parameters too large"); - goto error; - } - indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); - cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, n); + cycles = PyMem_New(Py_ssize_t, r); if (indices == NULL || cycles == NULL) { PyErr_NoMemory(); goto error; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 01:05:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 00:05:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322896=3A_Avoid_to_use_PyObject=5FAsCharBuffer?= =?utf-8?b?KCksIFB5T2JqZWN0X0FzUmVhZEJ1ZmZlcigp?= Message-ID: <20150203000515.96070.13019@psf.io> https://hg.python.org/cpython/rev/2e684ce772de changeset: 94475:2e684ce772de parent: 94473:651aa21433ba parent: 94474:1da9630e9b7f user: Serhiy Storchaka date: Tue Feb 03 01:25:42 2015 +0200 summary: Issue #22896: Avoid to use PyObject_AsCharBuffer(), PyObject_AsReadBuffer() and PyObject_AsWriteBuffer(). files: Include/bytes_methods.h | 2 +- Lib/ctypes/test/test_frombuffer.py | 50 ++- Misc/NEWS | 3 + Modules/_codecsmodule.c | 24 +- Modules/_ctypes/_ctypes.c | 59 ++- Modules/_io/bytesio.c | 10 +- Modules/_sqlite/connection.c | 11 +- Modules/_sqlite/statement.c | 13 +- Modules/_struct.c | 23 +- Objects/abstract.c | 82 +--- Objects/bytearrayobject.c | 146 ++++----- Objects/bytes_methods.c | 46 +-- Objects/bytesobject.c | 272 +++++++++------- Objects/complexobject.c | 9 +- Objects/exceptions.c | 32 +- Objects/floatobject.c | 8 +- Objects/stringlib/join.h | 9 +- Python/bltinmodule.c | 38 +- 18 files changed, 431 insertions(+), 406 deletions(-) diff --git a/Include/bytes_methods.h b/Include/bytes_methods.h --- a/Include/bytes_methods.h +++ b/Include/bytes_methods.h @@ -22,7 +22,7 @@ extern void _Py_bytes_swapcase(char *result, char *s, Py_ssize_t len); /* The maketrans() static method. */ -extern PyObject* _Py_bytes_maketrans(PyObject *frm, PyObject *to); +extern PyObject* _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to); /* Shared __doc__ strings. */ extern const char _Py_isspace__doc__[]; diff --git a/Lib/ctypes/test/test_frombuffer.py b/Lib/ctypes/test/test_frombuffer.py --- a/Lib/ctypes/test/test_frombuffer.py +++ b/Lib/ctypes/test/test_frombuffer.py @@ -10,7 +10,7 @@ self._init_called = True class Test(unittest.TestCase): - def test_fom_buffer(self): + def test_from_buffer(self): a = array.array("i", range(16)) x = (c_int * 16).from_buffer(a) @@ -23,25 +23,37 @@ a[0], a[-1] = 200, -200 self.assertEqual(x[:], a.tolist()) - self.assertIn(a, x._objects.values()) + self.assertRaises(BufferError, a.append, 100) + self.assertRaises(BufferError, a.pop) - self.assertRaises(ValueError, - c_int.from_buffer, a, -1) + del x; del y; gc.collect(); gc.collect(); gc.collect() + a.append(100) + a.pop() + x = (c_int * 16).from_buffer(a) + + self.assertIn(a, [obj.obj if isinstance(obj, memoryview) else obj + for obj in x._objects.values()]) expected = x[:] del a; gc.collect(); gc.collect(); gc.collect() self.assertEqual(x[:], expected) - self.assertRaises(TypeError, - (c_char * 16).from_buffer, "a" * 16) + with self.assertRaises(TypeError): + (c_char * 16).from_buffer(b"a" * 16) + with self.assertRaises(TypeError): + (c_char * 16).from_buffer("a" * 16) - def test_fom_buffer_with_offset(self): + def test_from_buffer_with_offset(self): a = array.array("i", range(16)) x = (c_int * 15).from_buffer(a, sizeof(c_int)) self.assertEqual(x[:], a.tolist()[1:]) - self.assertRaises(ValueError, lambda: (c_int * 16).from_buffer(a, sizeof(c_int))) - self.assertRaises(ValueError, lambda: (c_int * 1).from_buffer(a, 16 * sizeof(c_int))) + with self.assertRaises(ValueError): + c_int.from_buffer(a, -1) + with self.assertRaises(ValueError): + (c_int * 16).from_buffer(a, sizeof(c_int)) + with self.assertRaises(ValueError): + (c_int * 1).from_buffer(a, 16 * sizeof(c_int)) def test_from_buffer_copy(self): a = array.array("i", range(16)) @@ -56,26 +68,30 @@ a[0], a[-1] = 200, -200 self.assertEqual(x[:], list(range(16))) + a.append(100) + self.assertEqual(x[:], list(range(16))) + self.assertEqual(x._objects, None) - self.assertRaises(ValueError, - c_int.from_buffer, a, -1) - del a; gc.collect(); gc.collect(); gc.collect() self.assertEqual(x[:], list(range(16))) x = (c_char * 16).from_buffer_copy(b"a" * 16) self.assertEqual(x[:], b"a" * 16) + with self.assertRaises(TypeError): + (c_char * 16).from_buffer_copy("a" * 16) - def test_fom_buffer_copy_with_offset(self): + def test_from_buffer_copy_with_offset(self): a = array.array("i", range(16)) x = (c_int * 15).from_buffer_copy(a, sizeof(c_int)) self.assertEqual(x[:], a.tolist()[1:]) - self.assertRaises(ValueError, - (c_int * 16).from_buffer_copy, a, sizeof(c_int)) - self.assertRaises(ValueError, - (c_int * 1).from_buffer_copy, a, 16 * sizeof(c_int)) + with self.assertRaises(ValueError): + c_int.from_buffer_copy(a, -1) + with self.assertRaises(ValueError): + (c_int * 16).from_buffer_copy(a, sizeof(c_int)) + with self.assertRaises(ValueError): + (c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int)) if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #22896: Avoid using PyObject_AsCharBuffer(), PyObject_AsReadBuffer() + and PyObject_AsWriteBuffer(). + - Issue #21295: Revert some changes (issue #16795) to AST line numbers and column offsets that constituted a regression. diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -288,8 +288,6 @@ { PyObject *obj; const char *errors = NULL; - const char *data; - Py_ssize_t size; if (!PyArg_ParseTuple(args, "O|z:unicode_internal_decode", &obj, &errors)) @@ -302,11 +300,16 @@ return codec_tuple(obj, PyUnicode_GET_LENGTH(obj)); } else { - if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) + Py_buffer view; + PyObject *result; + if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) return NULL; - return codec_tuple(_PyUnicode_DecodeUnicodeInternal(data, size, errors), - size); + result = codec_tuple( + _PyUnicode_DecodeUnicodeInternal(view.buf, view.len, errors), + view.len); + PyBuffer_Release(&view); + return result; } } @@ -731,8 +734,6 @@ { PyObject *obj; const char *errors = NULL; - const char *data; - Py_ssize_t len, size; if (PyErr_WarnEx(PyExc_DeprecationWarning, "unicode_internal codec has been deprecated", @@ -745,6 +746,7 @@ if (PyUnicode_Check(obj)) { Py_UNICODE *u; + Py_ssize_t len, size; if (PyUnicode_READY(obj) < 0) return NULL; @@ -759,9 +761,13 @@ PyUnicode_GET_LENGTH(obj)); } else { - if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) + Py_buffer view; + PyObject *result; + if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) return NULL; - return codec_tuple(PyBytes_FromStringAndSize(data, size), size); + result = codec_tuple(PyBytes_FromStringAndSize(view.buf, view.len), view.len); + PyBuffer_Release(&view); + return result; } } diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -463,39 +463,45 @@ static PyObject * CDataType_from_buffer(PyObject *type, PyObject *args) { - void *buffer; - Py_ssize_t buffer_len; + Py_buffer buffer; Py_ssize_t offset = 0; - PyObject *obj, *result; + PyObject *result, *mv; StgDictObject *dict = PyType_stgdict(type); assert (dict); - if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset)) - return NULL; - - if (-1 == PyObject_AsWriteBuffer(obj, &buffer, &buffer_len)) + if (!PyArg_ParseTuple(args, "w*|n:from_buffer", &buffer, &offset)) return NULL; if (offset < 0) { PyErr_SetString(PyExc_ValueError, "offset cannot be negative"); + PyBuffer_Release(&buffer); return NULL; } - if (dict->size > buffer_len - offset) { + if (dict->size > buffer.len - offset) { PyErr_Format(PyExc_ValueError, "Buffer size too small (%zd instead of at least %zd bytes)", - buffer_len, dict->size + offset); + buffer.len, dict->size + offset); + PyBuffer_Release(&buffer); return NULL; } - result = PyCData_AtAddress(type, (char *)buffer + offset); - if (result == NULL) + result = PyCData_AtAddress(type, (char *)buffer.buf + offset); + if (result == NULL) { + PyBuffer_Release(&buffer); return NULL; - - Py_INCREF(obj); - if (-1 == KeepRef((CDataObject *)result, -1, obj)) { + } + + mv = PyMemoryView_FromBuffer(&buffer); + if (mv == NULL) { + PyBuffer_Release(&buffer); return NULL; } + /* Hack the memoryview so that it will release the buffer. */ + ((PyMemoryViewObject *)mv)->mbuf->master.obj = buffer.obj; + ((PyMemoryViewObject *)mv)->view.obj = buffer.obj; + if (-1 == KeepRef((CDataObject *)result, -1, mv)) + result = NULL; return result; } @@ -508,37 +514,36 @@ static PyObject * CDataType_from_buffer_copy(PyObject *type, PyObject *args) { - const void *buffer; - Py_ssize_t buffer_len; + Py_buffer buffer; Py_ssize_t offset = 0; - PyObject *obj, *result; + PyObject *result; StgDictObject *dict = PyType_stgdict(type); assert (dict); - if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset)) - return NULL; - - if (-1 == PyObject_AsReadBuffer(obj, (const void**)&buffer, &buffer_len)) + if (!PyArg_ParseTuple(args, "y*|n:from_buffer", &buffer, &offset)) return NULL; if (offset < 0) { PyErr_SetString(PyExc_ValueError, "offset cannot be negative"); + PyBuffer_Release(&buffer); return NULL; } - if (dict->size > buffer_len - offset) { + if (dict->size > buffer.len - offset) { PyErr_Format(PyExc_ValueError, "Buffer size too small (%zd instead of at least %zd bytes)", - buffer_len, dict->size + offset); + buffer.len, dict->size + offset); + PyBuffer_Release(&buffer); return NULL; } result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL); - if (result == NULL) - return NULL; - memcpy(((CDataObject *)result)->b_ptr, - (char *)buffer+offset, dict->size); + if (result != NULL) { + memcpy(((CDataObject *)result)->b_ptr, + (char *)buffer.buf + offset, dict->size); + } + PyBuffer_Release(&buffer); return result; } diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -553,17 +553,18 @@ "is set not to block as has no data to read."); static PyObject * -bytesio_readinto(bytesio *self, PyObject *buffer) +bytesio_readinto(bytesio *self, PyObject *arg) { - void *raw_buffer; + Py_buffer buffer; Py_ssize_t len, n; CHECK_CLOSED(self, NULL); - if (PyObject_AsWriteBuffer(buffer, &raw_buffer, &len) == -1) + if (!PyArg_Parse(arg, "w*", &buffer)) return NULL; /* adjust invalid sizes */ + len = buffer.len; n = self->string_size - self->pos; if (len > n) { len = n; @@ -571,10 +572,11 @@ len = 0; } - memcpy(raw_buffer, self->buf + self->pos, len); + memcpy(buffer.buf, self->buf + self->pos, len); assert(self->pos + len < PY_SSIZE_T_MAX); assert(len >= 0); self->pos += len; + PyBuffer_Release(&buffer); return PyLong_FromSsize_t(len); } diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -522,19 +522,20 @@ return -1; sqlite3_result_text(context, str, -1, SQLITE_TRANSIENT); } else if (PyObject_CheckBuffer(py_val)) { - const char* buffer; - Py_ssize_t buflen; - if (PyObject_AsCharBuffer(py_val, &buffer, &buflen) != 0) { + Py_buffer view; + if (PyObject_GetBuffer(py_val, &view, PyBUF_SIMPLE) != 0) { PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); return -1; } - if (buflen > INT_MAX) { + if (view.len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "BLOB longer than INT_MAX bytes"); + PyBuffer_Release(&view); return -1; } - sqlite3_result_blob(context, buffer, (int)buflen, SQLITE_TRANSIENT); + sqlite3_result_blob(context, view.buf, (int)view.len, SQLITE_TRANSIENT); + PyBuffer_Release(&view); } else { return -1; } diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c --- a/Modules/_sqlite/statement.c +++ b/Modules/_sqlite/statement.c @@ -94,7 +94,6 @@ int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter) { int rc = SQLITE_OK; - const char* buffer; char* string; Py_ssize_t buflen; parameter_type paramtype; @@ -145,18 +144,22 @@ } rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT); break; - case TYPE_BUFFER: - if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) != 0) { + case TYPE_BUFFER: { + Py_buffer view; + if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) { PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); return -1; } - if (buflen > INT_MAX) { + if (view.len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "BLOB longer than INT_MAX bytes"); + PyBuffer_Release(&view); return -1; } - rc = sqlite3_bind_blob(self->st, pos, buffer, buflen, SQLITE_TRANSIENT); + rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT); + PyBuffer_Release(&view); break; + } case TYPE_UNKNOWN: rc = -1; } diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1842,8 +1842,8 @@ s_pack_into(PyObject *self, PyObject *args) { PyStructObject *soself; - char *buffer; - Py_ssize_t buffer_len, offset; + Py_buffer buffer; + Py_ssize_t offset; /* Validate arguments. +1 is for the first arg as buffer. */ soself = (PyStructObject *)self; @@ -1868,34 +1868,37 @@ } /* Extract a writable memory buffer from the first argument */ - if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0), - (void**)&buffer, &buffer_len) == -1 ) { + if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buffer)) return NULL; - } - assert( buffer_len >= 0 ); + assert(buffer.len >= 0); /* Extract the offset from the first argument */ offset = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 1), PyExc_IndexError); - if (offset == -1 && PyErr_Occurred()) + if (offset == -1 && PyErr_Occurred()) { + PyBuffer_Release(&buffer); return NULL; + } /* Support negative offsets. */ if (offset < 0) - offset += buffer_len; + offset += buffer.len; /* Check boundaries */ - if (offset < 0 || (buffer_len - offset) < soself->s_size) { + if (offset < 0 || (buffer.len - offset) < soself->s_size) { PyErr_Format(StructError, "pack_into requires a buffer of at least %zd bytes", soself->s_size); + PyBuffer_Release(&buffer); return NULL; } /* Call the guts */ - if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) { + if (s_pack_internal(soself, args, 2, (char*)buffer.buf + offset) != 0) { + PyBuffer_Release(&buffer); return NULL; } + PyBuffer_Release(&buffer); Py_RETURN_NONE; } diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -250,27 +250,7 @@ const char **buffer, Py_ssize_t *buffer_len) { - PyBufferProcs *pb; - Py_buffer view; - - if (obj == NULL || buffer == NULL || buffer_len == NULL) { - null_error(); - return -1; - } - pb = obj->ob_type->tp_as_buffer; - if (pb == NULL || pb->bf_getbuffer == NULL) { - PyErr_SetString(PyExc_TypeError, - "expected a bytes-like object"); - return -1; - } - if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1; - - *buffer = view.buf; - *buffer_len = view.len; - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(obj, &view); - Py_XDECREF(view.obj); - return 0; + return PyObject_AsReadBuffer(obj, (const void **)buffer, buffer_len); } int @@ -294,28 +274,18 @@ const void **buffer, Py_ssize_t *buffer_len) { - PyBufferProcs *pb; Py_buffer view; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } - pb = obj->ob_type->tp_as_buffer; - if (pb == NULL || - pb->bf_getbuffer == NULL) { - PyErr_SetString(PyExc_TypeError, - "expected a bytes-like object"); + if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) return -1; - } - - if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1; *buffer = view.buf; *buffer_len = view.len; - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(obj, &view); - Py_XDECREF(view.obj); + PyBuffer_Release(&view); return 0; } @@ -341,9 +311,7 @@ *buffer = view.buf; *buffer_len = view.len; - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(obj, &view); - Py_XDECREF(view.obj); + PyBuffer_Release(&view); return 0; } @@ -352,13 +320,15 @@ int PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (!PyObject_CheckBuffer(obj)) { + PyBufferProcs *pb = obj->ob_type->tp_as_buffer; + + if (pb == NULL || pb->bf_getbuffer == NULL) { PyErr_Format(PyExc_TypeError, "a bytes-like object is required, not '%.100s'", Py_TYPE(obj)->tp_name); return -1; } - return (*(obj->ob_type->tp_as_buffer->bf_getbuffer))(obj, view, flags); + return (*pb->bf_getbuffer)(obj, view, flags); } static int @@ -676,10 +646,14 @@ PyBuffer_Release(Py_buffer *view) { PyObject *obj = view->obj; - if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer) - Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view); - Py_XDECREF(obj); + PyBufferProcs *pb; + if (obj == NULL) + return; + pb = Py_TYPE(obj)->tp_as_buffer; + if (pb && pb->bf_releasebuffer) + pb->bf_releasebuffer(obj, view); view->obj = NULL; + Py_DECREF(obj); } PyObject * @@ -1288,8 +1262,7 @@ { PyNumberMethods *m; PyObject *trunc_func; - const char *buffer; - Py_ssize_t buffer_len; + Py_buffer view; _Py_IDENTIFIER(__trunc__); if (o == NULL) @@ -1327,21 +1300,22 @@ if (PyErr_Occurred()) return NULL; - if (PyBytes_Check(o)) + if (PyUnicode_Check(o)) + /* The below check is done in PyLong_FromUnicode(). */ + return PyLong_FromUnicodeObject(o, 10); + + if (PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) == 0) { /* need to do extra error checking that PyLong_FromString() * doesn't do. In particular int('9\x005') must raise an * exception, not truncate at the null. */ - return _PyLong_FromBytes(PyBytes_AS_STRING(o), - PyBytes_GET_SIZE(o), 10); - if (PyUnicode_Check(o)) - /* The above check is done in PyLong_FromUnicode(). */ - return PyLong_FromUnicodeObject(o, 10); - if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) - return _PyLong_FromBytes(buffer, buffer_len, 10); - - return type_error("int() argument must be a string or a " - "number, not '%.200s'", o); + PyObject *result = _PyLong_FromBytes(view.buf, view.len, 10); + PyBuffer_Release(&view); + return result; + } + + return type_error("int() argument must be a string, a bytes-like object " + "or a number, not '%.200s'", o); } PyObject * diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -80,24 +80,6 @@ obj->ob_exports--; } -static Py_ssize_t -_getbuffer(PyObject *obj, Py_buffer *view) -{ - PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer; - - if (buffer == NULL || buffer->bf_getbuffer == NULL) - { - PyErr_Format(PyExc_TypeError, - "a bytes-like object is required, not '%.100s'", - Py_TYPE(obj)->tp_name); - return -1; - } - - if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) - return -1; - return view->len; -} - static int _canresize(PyByteArrayObject *self) { @@ -268,8 +250,8 @@ va.len = -1; vb.len = -1; - if (_getbuffer(a, &va) < 0 || - _getbuffer(b, &vb) < 0) { + if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 || + PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); goto done; @@ -335,7 +317,7 @@ Py_ssize_t size; Py_buffer vo; - if (_getbuffer(other, &vo) < 0) { + if (PyObject_GetBuffer(other, &vo, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(other)->tp_name, Py_TYPE(self)->tp_name); return NULL; @@ -595,14 +577,14 @@ needed = 0; } else { - if (_getbuffer(values, &vbytes) < 0) { - PyErr_Format(PyExc_TypeError, - "can't set bytearray slice from %.100s", - Py_TYPE(values)->tp_name); - return -1; - } - needed = vbytes.len; - bytes = vbytes.buf; + if (PyObject_GetBuffer(values, &vbytes, PyBUF_SIMPLE) != 0) { + PyErr_Format(PyExc_TypeError, + "can't set bytearray slice from %.100s", + Py_TYPE(values)->tp_name); + return -1; + } + needed = vbytes.len; + bytes = vbytes.buf; } if (lo < 0) @@ -1047,18 +1029,18 @@ Py_RETURN_NOTIMPLEMENTED; } - self_size = _getbuffer(self, &self_bytes); - if (self_size < 0) { + if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) { PyErr_Clear(); Py_RETURN_NOTIMPLEMENTED; } - - other_size = _getbuffer(other, &other_bytes); - if (other_size < 0) { + self_size = self_bytes.len; + + if (PyObject_GetBuffer(other, &other_bytes, PyBUF_SIMPLE) != 0) { PyErr_Clear(); PyBuffer_Release(&self_bytes); Py_RETURN_NOTIMPLEMENTED; } + other_size = other_bytes.len; if (self_size != other_size && (op == Py_EQ || op == Py_NE)) { /* Shortcut: if the lengths differ, the objects differ */ @@ -1170,7 +1152,7 @@ return -2; if (subobj) { - if (_getbuffer(subobj, &subbuf) < 0) + if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0) return -2; sub = subbuf.buf; @@ -1238,7 +1220,7 @@ return NULL; if (sub_obj) { - if (_getbuffer(sub_obj, &vsub) < 0) + if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; @@ -1397,7 +1379,7 @@ Py_buffer varg; Py_ssize_t pos; PyErr_Clear(); - if (_getbuffer(arg, &varg) < 0) + if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0) return -1; pos = stringlib_find(PyByteArray_AS_STRING(self), Py_SIZE(self), varg.buf, varg.len, 0); @@ -1428,7 +1410,7 @@ str = PyByteArray_AS_STRING(self); - if (_getbuffer(substr, &vsubstr) < 0) + if (PyObject_GetBuffer(substr, &vsubstr, PyBUF_SIMPLE) != 0) return -1; ADJUST_INDICES(start, end, len); @@ -1621,7 +1603,7 @@ if (table == Py_None) { table_chars = NULL; table = NULL; - } else if (_getbuffer(table, &vtable) < 0) { + } else if (PyObject_GetBuffer(table, &vtable, PyBUF_SIMPLE) != 0) { return NULL; } else { if (vtable.len != 256) { @@ -1634,7 +1616,7 @@ } if (deletechars != NULL) { - if (_getbuffer(deletechars, &vdel) < 0) { + if (PyObject_GetBuffer(deletechars, &vdel, PyBUF_SIMPLE) != 0) { if (table != NULL) PyBuffer_Release(&vtable); return NULL; @@ -1699,8 +1681,8 @@ @staticmethod bytearray.maketrans - frm: object - to: object + frm: Py_buffer + to: Py_buffer / Return a translation table useable for the bytes or bytearray translate method. @@ -1726,28 +1708,35 @@ {"maketrans", (PyCFunction)bytearray_maketrans, METH_VARARGS|METH_STATIC, bytearray_maketrans__doc__}, static PyObject * -bytearray_maketrans_impl(PyObject *frm, PyObject *to); +bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to); static PyObject * bytearray_maketrans(void *null, PyObject *args) { PyObject *return_value = NULL; - PyObject *frm; - PyObject *to; - - if (!PyArg_UnpackTuple(args, "maketrans", - 2, 2, + Py_buffer frm = {NULL, NULL}; + Py_buffer to = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*y*:maketrans", &frm, &to)) goto exit; - return_value = bytearray_maketrans_impl(frm, to); + return_value = bytearray_maketrans_impl(&frm, &to); exit: + /* Cleanup for frm */ + if (frm.obj) + PyBuffer_Release(&frm); + /* Cleanup for to */ + if (to.obj) + PyBuffer_Release(&to); + return return_value; } static PyObject * -bytearray_maketrans_impl(PyObject *frm, PyObject *to) -/*[clinic end generated code: output=307752019d9b25b5 input=ea9bdc6b328c15e2]*/ +bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to) +/*[clinic end generated code: output=d332622814c26f4b input=5925a81d2fbbf151]*/ { return _Py_bytes_maketrans(frm, to); } @@ -2243,8 +2232,8 @@ /*[clinic input] bytearray.replace - old: object - new: object + old: Py_buffer + new: Py_buffer count: Py_ssize_t = -1 Maximum number of occurrences to replace. -1 (the default value) means replace all occurrences. @@ -2273,47 +2262,40 @@ {"replace", (PyCFunction)bytearray_replace, METH_VARARGS, bytearray_replace__doc__}, static PyObject * -bytearray_replace_impl(PyByteArrayObject *self, PyObject *old, PyObject *new, Py_ssize_t count); +bytearray_replace_impl(PyByteArrayObject *self, Py_buffer *old, Py_buffer *new, Py_ssize_t count); static PyObject * bytearray_replace(PyByteArrayObject *self, PyObject *args) { PyObject *return_value = NULL; - PyObject *old; - PyObject *new; + Py_buffer old = {NULL, NULL}; + Py_buffer new = {NULL, NULL}; Py_ssize_t count = -1; if (!PyArg_ParseTuple(args, - "OO|n:replace", + "y*y*|n:replace", &old, &new, &count)) goto exit; - return_value = bytearray_replace_impl(self, old, new, count); + return_value = bytearray_replace_impl(self, &old, &new, count); exit: + /* Cleanup for old */ + if (old.obj) + PyBuffer_Release(&old); + /* Cleanup for new */ + if (new.obj) + PyBuffer_Release(&new); + return return_value; } static PyObject * -bytearray_replace_impl(PyByteArrayObject *self, PyObject *old, PyObject *new, Py_ssize_t count) -/*[clinic end generated code: output=4d2e3c9130da0f96 input=9aaaa123608dfc1f]*/ +bytearray_replace_impl(PyByteArrayObject *self, Py_buffer *old, Py_buffer *new, Py_ssize_t count) +/*[clinic end generated code: output=9997fbbd5bac4883 input=aa379d988637c7fb]*/ { - PyObject *res; - Py_buffer vold, vnew; - - if (_getbuffer(old, &vold) < 0) - return NULL; - if (_getbuffer(new, &vnew) < 0) { - PyBuffer_Release(&vold); - return NULL; - } - - res = (PyObject *)replace((PyByteArrayObject *) self, - vold.buf, vold.len, - vnew.buf, vnew.len, count); - - PyBuffer_Release(&vold); - PyBuffer_Release(&vnew); - return res; + return (PyObject *)replace((PyByteArrayObject *) self, + old->buf, old->len, + new->buf, new->len, count); } /*[clinic input] @@ -2383,7 +2365,7 @@ if (sep == Py_None) return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(sep, &vsub) < 0) + if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -2566,7 +2548,7 @@ if (sep == Py_None) return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(sep, &vsub) < 0) + if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -3088,7 +3070,7 @@ byteslen = 6; } else { - if (_getbuffer(bytes, &vbytes) < 0) + if (PyObject_GetBuffer(bytes, &vbytes, PyBUF_SIMPLE) != 0) return NULL; bytesptr = (char *) vbytes.buf; byteslen = vbytes.len; @@ -3159,7 +3141,7 @@ byteslen = 6; } else { - if (_getbuffer(bytes, &vbytes) < 0) + if (PyObject_GetBuffer(bytes, &vbytes, PyBUF_SIMPLE) != 0) return NULL; bytesptr = (char *) vbytes.buf; byteslen = vbytes.len; @@ -3227,7 +3209,7 @@ byteslen = 6; } else { - if (_getbuffer(bytes, &vbytes) < 0) + if (PyObject_GetBuffer(bytes, &vbytes, PyBUF_SIMPLE) != 0) return NULL; bytesptr = (char *) vbytes.buf; byteslen = vbytes.len; diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -363,59 +363,27 @@ in frm is mapped to the byte at the same position in to.\n\ The bytes objects frm and to must be of the same length."); -static Py_ssize_t -_getbuffer(PyObject *obj, Py_buffer *view) -{ - PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer; - - if (buffer == NULL || buffer->bf_getbuffer == NULL) - { - PyErr_Format(PyExc_TypeError, - "a bytes-like object is required, not '%.100s'", - Py_TYPE(obj)->tp_name); - return -1; - } - - if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) - return -1; - return view->len; -} - PyObject * -_Py_bytes_maketrans(PyObject *frm, PyObject *to) +_Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to) { PyObject *res = NULL; - Py_buffer bfrm, bto; Py_ssize_t i; char *p; - bfrm.len = -1; - bto.len = -1; - - if (_getbuffer(frm, &bfrm) < 0) - return NULL; - if (_getbuffer(to, &bto) < 0) - goto done; - if (bfrm.len != bto.len) { + if (frm->len != to->len) { PyErr_Format(PyExc_ValueError, "maketrans arguments must have same length"); - goto done; + return NULL; } res = PyBytes_FromStringAndSize(NULL, 256); - if (!res) { - goto done; - } + if (!res) + return NULL; p = PyBytes_AS_STRING(res); for (i = 0; i < 256; i++) p[i] = (char) i; - for (i = 0; i < bfrm.len; i++) { - p[((unsigned char *)bfrm.buf)[i]] = ((char *)bto.buf)[i]; + for (i = 0; i < frm->len; i++) { + p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i]; } -done: - if (bfrm.len != -1) - PyBuffer_Release(&bfrm); - if (bto.len != -1) - PyBuffer_Release(&bto); return res; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -12,33 +12,6 @@ [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1a1d9102afc1b00c]*/ -static Py_ssize_t -_getbuffer(PyObject *obj, Py_buffer *view) -{ - PyBufferProcs *bufferprocs; - if (PyBytes_CheckExact(obj)) { - /* Fast path, e.g. for .join() of many bytes objects */ - Py_INCREF(obj); - view->obj = obj; - view->buf = PyBytes_AS_STRING(obj); - view->len = PyBytes_GET_SIZE(obj); - return view->len; - } - - bufferprocs = Py_TYPE(obj)->tp_as_buffer; - if (bufferprocs == NULL || bufferprocs->bf_getbuffer == NULL) - { - PyErr_Format(PyExc_TypeError, - "a bytes-like object is required, not '%.100s'", - Py_TYPE(obj)->tp_name); - return -1; - } - - if (bufferprocs->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) - return -1; - return view->len; -} - #ifdef COUNT_ALLOCS Py_ssize_t null_strings, one_strings; #endif @@ -1349,8 +1322,8 @@ va.len = -1; vb.len = -1; - if (_getbuffer(a, &va) < 0 || - _getbuffer(b, &vb) < 0) { + if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 || + PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); goto done; @@ -1448,7 +1421,7 @@ Py_buffer varg; Py_ssize_t pos; PyErr_Clear(); - if (_getbuffer(arg, &varg) < 0) + if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0) return -1; pos = stringlib_find(PyBytes_AS_STRING(self), Py_SIZE(self), varg.buf, varg.len, 0); @@ -1737,7 +1710,7 @@ maxsplit = PY_SSIZE_T_MAX; if (sep == Py_None) return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(sep, &vsub) < 0) + if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -1751,7 +1724,7 @@ bytes.partition self: self(type="PyBytesObject *") - sep: object + sep: Py_buffer / Partition the bytes into three parts using the given separator. @@ -1778,26 +1751,39 @@ "object and two empty bytes objects."); #define BYTES_PARTITION_METHODDEF \ - {"partition", (PyCFunction)bytes_partition, METH_O, bytes_partition__doc__}, + {"partition", (PyCFunction)bytes_partition, METH_VARARGS, bytes_partition__doc__}, static PyObject * -bytes_partition(PyBytesObject *self, PyObject *sep) -/*[clinic end generated code: output=b41e119c873c08bc input=6c5b9dcc5a9fd62e]*/ +bytes_partition_impl(PyBytesObject *self, Py_buffer *sep); + +static PyObject * +bytes_partition(PyBytesObject *self, PyObject *args) { - const char *sep_chars; - Py_ssize_t sep_len; - - if (PyBytes_Check(sep)) { - sep_chars = PyBytes_AS_STRING(sep); - sep_len = PyBytes_GET_SIZE(sep); - } - else if (PyObject_AsCharBuffer(sep, &sep_chars, &sep_len)) - return NULL; - + PyObject *return_value = NULL; + Py_buffer sep = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:partition", + &sep)) + goto exit; + return_value = bytes_partition_impl(self, &sep); + +exit: + /* Cleanup for sep */ + if (sep.obj) + PyBuffer_Release(&sep); + + return return_value; +} + +static PyObject * +bytes_partition_impl(PyBytesObject *self, Py_buffer *sep) +/*[clinic end generated code: output=3006727cfbf83aa4 input=bc855dc63ca949de]*/ +{ return stringlib_partition( (PyObject*) self, PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), - sep, sep_chars, sep_len + sep->obj, (const char *)sep->buf, sep->len ); } @@ -1805,7 +1791,7 @@ bytes.rpartition self: self(type="PyBytesObject *") - sep: object + sep: Py_buffer / Partition the bytes into three parts using the given separator. @@ -1832,26 +1818,39 @@ "objects and the original bytes object."); #define BYTES_RPARTITION_METHODDEF \ - {"rpartition", (PyCFunction)bytes_rpartition, METH_O, bytes_rpartition__doc__}, + {"rpartition", (PyCFunction)bytes_rpartition, METH_VARARGS, bytes_rpartition__doc__}, static PyObject * -bytes_rpartition(PyBytesObject *self, PyObject *sep) -/*[clinic end generated code: output=3a620803657196ee input=79bc2932e78e5ce0]*/ +bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep); + +static PyObject * +bytes_rpartition(PyBytesObject *self, PyObject *args) { - const char *sep_chars; - Py_ssize_t sep_len; - - if (PyBytes_Check(sep)) { - sep_chars = PyBytes_AS_STRING(sep); - sep_len = PyBytes_GET_SIZE(sep); - } - else if (PyObject_AsCharBuffer(sep, &sep_chars, &sep_len)) - return NULL; - + PyObject *return_value = NULL; + Py_buffer sep = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:rpartition", + &sep)) + goto exit; + return_value = bytes_rpartition_impl(self, &sep); + +exit: + /* Cleanup for sep */ + if (sep.obj) + PyBuffer_Release(&sep); + + return return_value; +} + +static PyObject * +bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep) +/*[clinic end generated code: output=57b169dc47fa90e8 input=6588fff262a9170e]*/ +{ return stringlib_rpartition( (PyObject*) self, PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), - sep, sep_chars, sep_len + sep->obj, (const char *)sep->buf, sep->len ); } @@ -1916,7 +1915,7 @@ maxsplit = PY_SSIZE_T_MAX; if (sep == Py_None) return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(sep, &vsub) < 0) + if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -2003,7 +2002,7 @@ return -2; if (subobj) { - if (_getbuffer(subobj, &subbuf) < 0) + if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0) return -2; sub = subbuf.buf; @@ -2118,7 +2117,7 @@ Py_ssize_t seplen; Py_ssize_t i, j; - if (_getbuffer(sepobj, &vsep) < 0) + if (PyObject_GetBuffer(sepobj, &vsep, PyBUF_SIMPLE) != 0) return NULL; sep = vsep.buf; seplen = vsep.len; @@ -2360,7 +2359,7 @@ return NULL; if (sub_obj) { - if (_getbuffer(sub_obj, &vsub) < 0) + if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; @@ -2450,6 +2449,8 @@ /*[clinic end generated code: output=f0f29a57f41df5d8 input=d8fa5519d7cc4be7]*/ { char *input, *output; + Py_buffer table_view = {NULL, NULL}; + Py_buffer del_table_view = {NULL, NULL}; const char *table_chars; Py_ssize_t i, c, changed = 0; PyObject *input_obj = (PyObject*)self; @@ -2466,12 +2467,17 @@ table_chars = NULL; tablen = 256; } - else if (PyObject_AsCharBuffer(table, &table_chars, &tablen)) - return NULL; + else { + if (PyObject_GetBuffer(table, &table_view, PyBUF_SIMPLE) != 0) + return NULL; + table_chars = table_view.buf; + tablen = table_view.len; + } if (tablen != 256) { PyErr_SetString(PyExc_ValueError, "translation table must be 256 characters long"); + PyBuffer_Release(&table_view); return NULL; } @@ -2480,8 +2486,14 @@ del_table_chars = PyBytes_AS_STRING(deletechars); dellen = PyBytes_GET_SIZE(deletechars); } - else if (PyObject_AsCharBuffer(deletechars, &del_table_chars, &dellen)) - return NULL; + else { + if (PyObject_GetBuffer(deletechars, &del_table_view, PyBUF_SIMPLE) != 0) { + PyBuffer_Release(&table_view); + return NULL; + } + del_table_chars = del_table_view.buf; + dellen = del_table_view.len; + } } else { del_table_chars = NULL; @@ -2490,8 +2502,11 @@ inlen = PyBytes_GET_SIZE(input_obj); result = PyBytes_FromStringAndSize((char *)NULL, inlen); - if (result == NULL) + if (result == NULL) { + PyBuffer_Release(&del_table_view); + PyBuffer_Release(&table_view); return NULL; + } output_start = output = PyBytes_AsString(result); input = PyBytes_AS_STRING(input_obj); @@ -2502,11 +2517,14 @@ if (Py_CHARMASK((*output++ = table_chars[c])) != c) changed = 1; } - if (changed || !PyBytes_CheckExact(input_obj)) - return result; - Py_DECREF(result); - Py_INCREF(input_obj); - return input_obj; + if (!changed && PyBytes_CheckExact(input_obj)) { + Py_INCREF(input_obj); + Py_DECREF(result); + result = input_obj; + } + PyBuffer_Release(&del_table_view); + PyBuffer_Release(&table_view); + return result; } if (table_chars == NULL) { @@ -2516,9 +2534,11 @@ for (i = 0; i < 256; i++) trans_table[i] = Py_CHARMASK(table_chars[i]); } + PyBuffer_Release(&table_view); for (i = 0; i < dellen; i++) trans_table[(int) Py_CHARMASK(del_table_chars[i])] = -1; + PyBuffer_Release(&del_table_view); for (i = inlen; --i >= 0; ) { c = Py_CHARMASK(*input++); @@ -2544,8 +2564,8 @@ @staticmethod bytes.maketrans - frm: object - to: object + frm: Py_buffer + to: Py_buffer / Return a translation table useable for the bytes or bytearray translate method. @@ -2571,28 +2591,35 @@ {"maketrans", (PyCFunction)bytes_maketrans, METH_VARARGS|METH_STATIC, bytes_maketrans__doc__}, static PyObject * -bytes_maketrans_impl(PyObject *frm, PyObject *to); +bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to); static PyObject * bytes_maketrans(void *null, PyObject *args) { PyObject *return_value = NULL; - PyObject *frm; - PyObject *to; - - if (!PyArg_UnpackTuple(args, "maketrans", - 2, 2, + Py_buffer frm = {NULL, NULL}; + Py_buffer to = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*y*:maketrans", &frm, &to)) goto exit; - return_value = bytes_maketrans_impl(frm, to); + return_value = bytes_maketrans_impl(&frm, &to); exit: + /* Cleanup for frm */ + if (frm.obj) + PyBuffer_Release(&frm); + /* Cleanup for to */ + if (to.obj) + PyBuffer_Release(&to); + return return_value; } static PyObject * -bytes_maketrans_impl(PyObject *frm, PyObject *to) -/*[clinic end generated code: output=89a3c3556975e466 input=d204f680f85da382]*/ +bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to) +/*[clinic end generated code: output=7df47390c476ac60 input=de7a8fc5632bb8f1]*/ { return _Py_bytes_maketrans(frm, to); } @@ -3093,8 +3120,8 @@ /*[clinic input] bytes.replace - old: object - new: object + old: Py_buffer + new: Py_buffer count: Py_ssize_t = -1 Maximum number of occurrences to replace. -1 (the default value) means replace all occurrences. @@ -3123,50 +3150,40 @@ {"replace", (PyCFunction)bytes_replace, METH_VARARGS, bytes_replace__doc__}, static PyObject * -bytes_replace_impl(PyBytesObject*self, PyObject *old, PyObject *new, Py_ssize_t count); +bytes_replace_impl(PyBytesObject*self, Py_buffer *old, Py_buffer *new, Py_ssize_t count); static PyObject * bytes_replace(PyBytesObject*self, PyObject *args) { PyObject *return_value = NULL; - PyObject *old; - PyObject *new; + Py_buffer old = {NULL, NULL}; + Py_buffer new = {NULL, NULL}; Py_ssize_t count = -1; if (!PyArg_ParseTuple(args, - "OO|n:replace", + "y*y*|n:replace", &old, &new, &count)) goto exit; - return_value = bytes_replace_impl(self, old, new, count); + return_value = bytes_replace_impl(self, &old, &new, count); exit: + /* Cleanup for old */ + if (old.obj) + PyBuffer_Release(&old); + /* Cleanup for new */ + if (new.obj) + PyBuffer_Release(&new); + return return_value; } static PyObject * -bytes_replace_impl(PyBytesObject*self, PyObject *old, PyObject *new, Py_ssize_t count) -/*[clinic end generated code: output=14ce72f4f9cb91cf input=d3ac254ea50f4ac1]*/ +bytes_replace_impl(PyBytesObject*self, Py_buffer *old, Py_buffer *new, Py_ssize_t count) +/*[clinic end generated code: output=f07bd9ecf29ee8d8 input=b2fbbf0bf04de8e5]*/ { - const char *old_s, *new_s; - Py_ssize_t old_len, new_len; - - if (PyBytes_Check(old)) { - old_s = PyBytes_AS_STRING(old); - old_len = PyBytes_GET_SIZE(old); - } - else if (PyObject_AsCharBuffer(old, &old_s, &old_len)) - return NULL; - - if (PyBytes_Check(new)) { - new_s = PyBytes_AS_STRING(new); - new_len = PyBytes_GET_SIZE(new); - } - else if (PyObject_AsCharBuffer(new, &new_s, &new_len)) - return NULL; - return (PyObject *)replace((PyBytesObject *) self, - old_s, old_len, - new_s, new_len, count); + (const char *)old->buf, old->len, + (const char *)new->buf, new->len, count); } /** End DALKE **/ @@ -3181,6 +3198,7 @@ { Py_ssize_t len = PyBytes_GET_SIZE(self); Py_ssize_t slen; + Py_buffer sub_view = {NULL, NULL}; const char* sub; const char* str; @@ -3188,8 +3206,12 @@ sub = PyBytes_AS_STRING(substr); slen = PyBytes_GET_SIZE(substr); } - else if (PyObject_AsCharBuffer(substr, &sub, &slen)) - return -1; + else { + if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0) + return -1; + sub = sub_view.buf; + slen = sub_view.len; + } str = PyBytes_AS_STRING(self); ADJUST_INDICES(start, end, len); @@ -3197,17 +3219,25 @@ if (direction < 0) { /* startswith */ if (start+slen > len) - return 0; + goto notfound; } else { /* endswith */ if (end-start < slen || start > len) - return 0; + goto notfound; if (end-slen > start) start = end - slen; } - if (end-start >= slen) - return ! memcmp(str+start, sub, slen); + if (end-start < slen) + goto notfound; + if (memcmp(str+start, sub, slen) != 0) + goto notfound; + + PyBuffer_Release(&sub_view); + return 1; + +notfound: + PyBuffer_Release(&sub_view); return 0; } @@ -3978,7 +4008,7 @@ Py_buffer wb; wb.len = -1; - if (_getbuffer(w, &wb) < 0) { + if (PyObject_GetBuffer(w, &wb, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(w)->tp_name, Py_TYPE(*pv)->tp_name); Py_CLEAR(*pv); diff --git a/Objects/complexobject.c b/Objects/complexobject.c --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -767,6 +767,7 @@ int got_bracket=0; PyObject *s_buffer = NULL; Py_ssize_t len; + Py_buffer view = {NULL, NULL}; if (PyUnicode_Check(v)) { s_buffer = _PyUnicode_TransformDecimalAndSpaceToASCII(v); @@ -776,7 +777,11 @@ if (s == NULL) goto error; } - else if (PyObject_AsCharBuffer(v, &s, &len)) { + else if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) == 0) { + s = (const char *)view.buf; + len = view.len; + } + else { PyErr_Format(PyExc_TypeError, "complex() argument must be a string or a number, not '%.200s'", Py_TYPE(v)->tp_name); @@ -890,6 +895,7 @@ if (s-start != len) goto parse_error; + PyBuffer_Release(&view); Py_XDECREF(s_buffer); return complex_subtype_from_doubles(type, x, y); @@ -897,6 +903,7 @@ PyErr_SetString(PyExc_ValueError, "complex() arg is a malformed string"); error: + PyBuffer_Release(&view); Py_XDECREF(s_buffer); return NULL; } diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1922,8 +1922,6 @@ UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) { PyUnicodeErrorObject *ude; - const char *data; - Py_ssize_t size; if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; @@ -1944,21 +1942,27 @@ return -1; } + Py_INCREF(ude->encoding); + Py_INCREF(ude->object); + Py_INCREF(ude->reason); + if (!PyBytes_Check(ude->object)) { - if (PyObject_AsReadBuffer(ude->object, (const void **)&data, &size)) { - ude->encoding = ude->object = ude->reason = NULL; - return -1; - } - ude->object = PyBytes_FromStringAndSize(data, size); + Py_buffer view; + if (PyObject_GetBuffer(ude->object, &view, PyBUF_SIMPLE) != 0) + goto error; + Py_CLEAR(ude->object); + ude->object = PyBytes_FromStringAndSize(view.buf, view.len); + PyBuffer_Release(&view); + if (!ude->object) + goto error; } - else { - Py_INCREF(ude->object); - } - - Py_INCREF(ude->encoding); - Py_INCREF(ude->reason); - return 0; + +error: + Py_CLEAR(ude->encoding); + Py_CLEAR(ude->object); + Py_CLEAR(ude->reason); + return -1; } static PyObject * diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -131,6 +131,7 @@ double x; PyObject *s_buffer = NULL; Py_ssize_t len; + Py_buffer view = {NULL, NULL}; PyObject *result = NULL; if (PyUnicode_Check(v)) { @@ -143,7 +144,11 @@ return NULL; } } - else if (PyObject_AsCharBuffer(v, &s, &len)) { + else if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) == 0) { + s = (const char *)view.buf; + len = view.len; + } + else { PyErr_Format(PyExc_TypeError, "float() argument must be a string or a number, not '%.200s'", Py_TYPE(v)->tp_name); @@ -170,6 +175,7 @@ else result = PyFloat_FromDouble(x); + PyBuffer_Release(&view); Py_XDECREF(s_buffer); return result; } diff --git a/Objects/stringlib/join.h b/Objects/stringlib/join.h --- a/Objects/stringlib/join.h +++ b/Objects/stringlib/join.h @@ -58,7 +58,14 @@ for (i = 0, nbufs = 0; i < seqlen; i++) { Py_ssize_t itemlen; item = PySequence_Fast_GET_ITEM(seq, i); - if (_getbuffer(item, &buffers[i]) < 0) { + if (PyBytes_CheckExact(item)) { + /* Fast path. */ + Py_INCREF(item); + buffers[i].obj = item; + buffers[i].buf = PyBytes_AS_STRING(item); + buffers[i].len = PyBytes_GET_SIZE(item); + } + else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "sequence item %zd: expected a bytes-like object, " "%.80s found", diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -723,10 +723,10 @@ } -static char * -source_as_string(PyObject *cmd, char *funcname, char *what, PyCompilerFlags *cf) +static const char * +source_as_string(PyObject *cmd, const char *funcname, const char *what, PyCompilerFlags *cf, Py_buffer *view) { - char *str; + const char *str; Py_ssize_t size; if (PyUnicode_Check(cmd)) { @@ -735,19 +735,21 @@ if (str == NULL) return NULL; } - else if (!PyObject_CheckReadBuffer(cmd)) { + else if (PyObject_GetBuffer(cmd, view, PyBUF_SIMPLE) == 0) { + str = (const char *)view->buf; + size = view->len; + } + else { PyErr_Format(PyExc_TypeError, "%s() arg 1 must be a %s object", funcname, what); return NULL; } - else if (PyObject_AsReadBuffer(cmd, (const void **)&str, &size) < 0) { - return NULL; - } - - if (strlen(str) != (size_t)size) { + + if (strlen(str) != (size_t)size) { PyErr_SetString(PyExc_ValueError, "source code string cannot contain null bytes"); + PyBuffer_Release(view); return NULL; } return str; @@ -827,7 +829,8 @@ builtin_compile_impl(PyModuleDef *module, PyObject *source, PyObject *filename, const char *mode, int flags, int dont_inherit, int optimize) /*[clinic end generated code: output=c72d197809d178fc input=c6212a9d21472f7e]*/ { - char *str; + Py_buffer view = {NULL, NULL}; + const char *str; int compile_mode = -1; int is_ast; PyCompilerFlags cf; @@ -898,11 +901,12 @@ goto finally; } - str = source_as_string(source, "compile", "string, bytes or AST", &cf); + str = source_as_string(source, "compile", "string, bytes or AST", &cf, &view); if (str == NULL) goto error; result = Py_CompileStringObject(str, filename, start[compile_mode], &cf, optimize); + PyBuffer_Release(&view); goto finally; error: @@ -1042,7 +1046,8 @@ /*[clinic end generated code: output=644fd59012538ce6 input=31e42c1d2125b50b]*/ { PyObject *result, *tmp = NULL; - char *str; + Py_buffer view = {NULL, NULL}; + const char *str; PyCompilerFlags cf; if (locals != Py_None && !PyMapping_Check(locals)) { @@ -1089,7 +1094,7 @@ } cf.cf_flags = PyCF_SOURCE_IS_UTF8; - str = source_as_string(source, "eval", "string, bytes or code", &cf); + str = source_as_string(source, "eval", "string, bytes or code", &cf, &view); if (str == NULL) return NULL; @@ -1098,6 +1103,7 @@ (void)PyEval_MergeCompilerFlags(&cf); result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); + PyBuffer_Release(&view); Py_XDECREF(tmp); return result; } @@ -1204,11 +1210,12 @@ v = PyEval_EvalCode(source, globals, locals); } else { - char *str; + Py_buffer view = {NULL, NULL}; + const char *str; PyCompilerFlags cf; cf.cf_flags = PyCF_SOURCE_IS_UTF8; str = source_as_string(source, "exec", - "string, bytes or code", &cf); + "string, bytes or code", &cf, &view); if (str == NULL) return NULL; if (PyEval_MergeCompilerFlags(&cf)) @@ -1216,6 +1223,7 @@ locals, &cf); else v = PyRun_String(str, Py_file_input, globals, locals); + PyBuffer_Release(&view); } if (v == NULL) return NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 01:05:58 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 00:05:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODk2?= =?utf-8?q?=3A_Avoid_to_use_PyObject=5FAsCharBuffer=28=29=2C_PyObject=5FAs?= =?utf-8?q?ReadBuffer=28=29?= Message-ID: <20150203000514.39292.99884@psf.io> https://hg.python.org/cpython/rev/1da9630e9b7f changeset: 94474:1da9630e9b7f branch: 3.4 parent: 94472:b883bb8bd744 user: Serhiy Storchaka date: Tue Feb 03 01:21:08 2015 +0200 summary: Issue #22896: Avoid to use PyObject_AsCharBuffer(), PyObject_AsReadBuffer() and PyObject_AsWriteBuffer(). files: Lib/ctypes/test/test_frombuffer.py | 50 +++- Misc/NEWS | 3 + Modules/_codecsmodule.c | 24 +- Modules/_ctypes/_ctypes.c | 59 +++-- Modules/_io/bytesio.c | 10 +- Modules/_sqlite/connection.c | 11 +- Modules/_sqlite/statement.c | 13 +- Modules/_struct.c | 23 +- Objects/abstract.c | 81 ++----- Objects/bytearrayobject.c | 98 +++----- Objects/bytes_methods.c | 33 +-- Objects/bytesobject.c | 179 ++++++++-------- Objects/complexobject.c | 9 +- Objects/exceptions.c | 32 +- Objects/floatobject.c | 8 +- Objects/stringlib/join.h | 9 +- Python/bltinmodule.c | 34 +- 17 files changed, 334 insertions(+), 342 deletions(-) diff --git a/Lib/ctypes/test/test_frombuffer.py b/Lib/ctypes/test/test_frombuffer.py --- a/Lib/ctypes/test/test_frombuffer.py +++ b/Lib/ctypes/test/test_frombuffer.py @@ -10,7 +10,7 @@ self._init_called = True class Test(unittest.TestCase): - def test_fom_buffer(self): + def test_from_buffer(self): a = array.array("i", range(16)) x = (c_int * 16).from_buffer(a) @@ -23,25 +23,37 @@ a[0], a[-1] = 200, -200 self.assertEqual(x[:], a.tolist()) - self.assertIn(a, x._objects.values()) + self.assertRaises(BufferError, a.append, 100) + self.assertRaises(BufferError, a.pop) - self.assertRaises(ValueError, - c_int.from_buffer, a, -1) + del x; del y; gc.collect(); gc.collect(); gc.collect() + a.append(100) + a.pop() + x = (c_int * 16).from_buffer(a) + + self.assertIn(a, [obj.obj if isinstance(obj, memoryview) else obj + for obj in x._objects.values()]) expected = x[:] del a; gc.collect(); gc.collect(); gc.collect() self.assertEqual(x[:], expected) - self.assertRaises(TypeError, - (c_char * 16).from_buffer, "a" * 16) + with self.assertRaises(TypeError): + (c_char * 16).from_buffer(b"a" * 16) + with self.assertRaises(TypeError): + (c_char * 16).from_buffer("a" * 16) - def test_fom_buffer_with_offset(self): + def test_from_buffer_with_offset(self): a = array.array("i", range(16)) x = (c_int * 15).from_buffer(a, sizeof(c_int)) self.assertEqual(x[:], a.tolist()[1:]) - self.assertRaises(ValueError, lambda: (c_int * 16).from_buffer(a, sizeof(c_int))) - self.assertRaises(ValueError, lambda: (c_int * 1).from_buffer(a, 16 * sizeof(c_int))) + with self.assertRaises(ValueError): + c_int.from_buffer(a, -1) + with self.assertRaises(ValueError): + (c_int * 16).from_buffer(a, sizeof(c_int)) + with self.assertRaises(ValueError): + (c_int * 1).from_buffer(a, 16 * sizeof(c_int)) def test_from_buffer_copy(self): a = array.array("i", range(16)) @@ -56,26 +68,30 @@ a[0], a[-1] = 200, -200 self.assertEqual(x[:], list(range(16))) + a.append(100) + self.assertEqual(x[:], list(range(16))) + self.assertEqual(x._objects, None) - self.assertRaises(ValueError, - c_int.from_buffer, a, -1) - del a; gc.collect(); gc.collect(); gc.collect() self.assertEqual(x[:], list(range(16))) x = (c_char * 16).from_buffer_copy(b"a" * 16) self.assertEqual(x[:], b"a" * 16) + with self.assertRaises(TypeError): + (c_char * 16).from_buffer_copy("a" * 16) - def test_fom_buffer_copy_with_offset(self): + def test_from_buffer_copy_with_offset(self): a = array.array("i", range(16)) x = (c_int * 15).from_buffer_copy(a, sizeof(c_int)) self.assertEqual(x[:], a.tolist()[1:]) - self.assertRaises(ValueError, - (c_int * 16).from_buffer_copy, a, sizeof(c_int)) - self.assertRaises(ValueError, - (c_int * 1).from_buffer_copy, a, 16 * sizeof(c_int)) + with self.assertRaises(ValueError): + c_int.from_buffer_copy(a, -1) + with self.assertRaises(ValueError): + (c_int * 16).from_buffer_copy(a, sizeof(c_int)) + with self.assertRaises(ValueError): + (c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int)) if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,6 +11,9 @@ Core and Builtins ----------------- +- Issue #22896: Avoid using PyObject_AsCharBuffer(), PyObject_AsReadBuffer() + and PyObject_AsWriteBuffer(). + - Issue #21295: Revert some changes (issue #16795) to AST line numbers and column offsets that constituted a regression. diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -284,8 +284,6 @@ { PyObject *obj; const char *errors = NULL; - const char *data; - Py_ssize_t size; if (!PyArg_ParseTuple(args, "O|z:unicode_internal_decode", &obj, &errors)) @@ -298,11 +296,16 @@ return codec_tuple(obj, PyUnicode_GET_LENGTH(obj)); } else { - if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) + Py_buffer view; + PyObject *result; + if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) return NULL; - return codec_tuple(_PyUnicode_DecodeUnicodeInternal(data, size, errors), - size); + result = codec_tuple( + _PyUnicode_DecodeUnicodeInternal(view.buf, view.len, errors), + view.len); + PyBuffer_Release(&view); + return result; } } @@ -727,8 +730,6 @@ { PyObject *obj; const char *errors = NULL; - const char *data; - Py_ssize_t len, size; if (PyErr_WarnEx(PyExc_DeprecationWarning, "unicode_internal codec has been deprecated", @@ -741,6 +742,7 @@ if (PyUnicode_Check(obj)) { Py_UNICODE *u; + Py_ssize_t len, size; if (PyUnicode_READY(obj) < 0) return NULL; @@ -755,9 +757,13 @@ PyUnicode_GET_LENGTH(obj)); } else { - if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) + Py_buffer view; + PyObject *result; + if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) return NULL; - return codec_tuple(PyBytes_FromStringAndSize(data, size), size); + result = codec_tuple(PyBytes_FromStringAndSize(view.buf, view.len), view.len); + PyBuffer_Release(&view); + return result; } } diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -463,39 +463,45 @@ static PyObject * CDataType_from_buffer(PyObject *type, PyObject *args) { - void *buffer; - Py_ssize_t buffer_len; + Py_buffer buffer; Py_ssize_t offset = 0; - PyObject *obj, *result; + PyObject *result, *mv; StgDictObject *dict = PyType_stgdict(type); assert (dict); - if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset)) - return NULL; - - if (-1 == PyObject_AsWriteBuffer(obj, &buffer, &buffer_len)) + if (!PyArg_ParseTuple(args, "w*|n:from_buffer", &buffer, &offset)) return NULL; if (offset < 0) { PyErr_SetString(PyExc_ValueError, "offset cannot be negative"); + PyBuffer_Release(&buffer); return NULL; } - if (dict->size > buffer_len - offset) { + if (dict->size > buffer.len - offset) { PyErr_Format(PyExc_ValueError, "Buffer size too small (%zd instead of at least %zd bytes)", - buffer_len, dict->size + offset); + buffer.len, dict->size + offset); + PyBuffer_Release(&buffer); return NULL; } - result = PyCData_AtAddress(type, (char *)buffer + offset); - if (result == NULL) + result = PyCData_AtAddress(type, (char *)buffer.buf + offset); + if (result == NULL) { + PyBuffer_Release(&buffer); return NULL; - - Py_INCREF(obj); - if (-1 == KeepRef((CDataObject *)result, -1, obj)) { + } + + mv = PyMemoryView_FromBuffer(&buffer); + if (mv == NULL) { + PyBuffer_Release(&buffer); return NULL; } + /* Hack the memoryview so that it will release the buffer. */ + ((PyMemoryViewObject *)mv)->mbuf->master.obj = buffer.obj; + ((PyMemoryViewObject *)mv)->view.obj = buffer.obj; + if (-1 == KeepRef((CDataObject *)result, -1, mv)) + result = NULL; return result; } @@ -508,37 +514,36 @@ static PyObject * CDataType_from_buffer_copy(PyObject *type, PyObject *args) { - const void *buffer; - Py_ssize_t buffer_len; + Py_buffer buffer; Py_ssize_t offset = 0; - PyObject *obj, *result; + PyObject *result; StgDictObject *dict = PyType_stgdict(type); assert (dict); - if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset)) - return NULL; - - if (-1 == PyObject_AsReadBuffer(obj, (const void**)&buffer, &buffer_len)) + if (!PyArg_ParseTuple(args, "y*|n:from_buffer", &buffer, &offset)) return NULL; if (offset < 0) { PyErr_SetString(PyExc_ValueError, "offset cannot be negative"); + PyBuffer_Release(&buffer); return NULL; } - if (dict->size > buffer_len - offset) { + if (dict->size > buffer.len - offset) { PyErr_Format(PyExc_ValueError, "Buffer size too small (%zd instead of at least %zd bytes)", - buffer_len, dict->size + offset); + buffer.len, dict->size + offset); + PyBuffer_Release(&buffer); return NULL; } result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL); - if (result == NULL) - return NULL; - memcpy(((CDataObject *)result)->b_ptr, - (char *)buffer+offset, dict->size); + if (result != NULL) { + memcpy(((CDataObject *)result)->b_ptr, + (char *)buffer.buf + offset, dict->size); + } + PyBuffer_Release(&buffer); return result; } diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -437,17 +437,18 @@ "is set not to block as has no data to read."); static PyObject * -bytesio_readinto(bytesio *self, PyObject *buffer) +bytesio_readinto(bytesio *self, PyObject *arg) { - void *raw_buffer; + Py_buffer buffer; Py_ssize_t len, n; CHECK_CLOSED(self); - if (PyObject_AsWriteBuffer(buffer, &raw_buffer, &len) == -1) + if (!PyArg_Parse(arg, "w*", &buffer)) return NULL; /* adjust invalid sizes */ + len = buffer.len; n = self->string_size - self->pos; if (len > n) { len = n; @@ -455,10 +456,11 @@ len = 0; } - memcpy(raw_buffer, self->buf + self->pos, len); + memcpy(buffer.buf, self->buf + self->pos, len); assert(self->pos + len < PY_SSIZE_T_MAX); assert(len >= 0); self->pos += len; + PyBuffer_Release(&buffer); return PyLong_FromSsize_t(len); } diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -522,19 +522,20 @@ return -1; sqlite3_result_text(context, str, -1, SQLITE_TRANSIENT); } else if (PyObject_CheckBuffer(py_val)) { - const char* buffer; - Py_ssize_t buflen; - if (PyObject_AsCharBuffer(py_val, &buffer, &buflen) != 0) { + Py_buffer view; + if (PyObject_GetBuffer(py_val, &view, PyBUF_SIMPLE) != 0) { PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); return -1; } - if (buflen > INT_MAX) { + if (view.len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "BLOB longer than INT_MAX bytes"); + PyBuffer_Release(&view); return -1; } - sqlite3_result_blob(context, buffer, (int)buflen, SQLITE_TRANSIENT); + sqlite3_result_blob(context, view.buf, (int)view.len, SQLITE_TRANSIENT); + PyBuffer_Release(&view); } else { return -1; } diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c --- a/Modules/_sqlite/statement.c +++ b/Modules/_sqlite/statement.c @@ -94,7 +94,6 @@ int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter) { int rc = SQLITE_OK; - const char* buffer; char* string; Py_ssize_t buflen; parameter_type paramtype; @@ -145,18 +144,22 @@ } rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT); break; - case TYPE_BUFFER: - if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) != 0) { + case TYPE_BUFFER: { + Py_buffer view; + if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) { PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); return -1; } - if (buflen > INT_MAX) { + if (view.len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "BLOB longer than INT_MAX bytes"); + PyBuffer_Release(&view); return -1; } - rc = sqlite3_bind_blob(self->st, pos, buffer, buflen, SQLITE_TRANSIENT); + rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT); + PyBuffer_Release(&view); break; + } case TYPE_UNKNOWN: rc = -1; } diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1842,8 +1842,8 @@ s_pack_into(PyObject *self, PyObject *args) { PyStructObject *soself; - char *buffer; - Py_ssize_t buffer_len, offset; + Py_buffer buffer; + Py_ssize_t offset; /* Validate arguments. +1 is for the first arg as buffer. */ soself = (PyStructObject *)self; @@ -1868,34 +1868,37 @@ } /* Extract a writable memory buffer from the first argument */ - if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0), - (void**)&buffer, &buffer_len) == -1 ) { + if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buffer)) return NULL; - } - assert( buffer_len >= 0 ); + assert(buffer.len >= 0); /* Extract the offset from the first argument */ offset = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 1), PyExc_IndexError); - if (offset == -1 && PyErr_Occurred()) + if (offset == -1 && PyErr_Occurred()) { + PyBuffer_Release(&buffer); return NULL; + } /* Support negative offsets. */ if (offset < 0) - offset += buffer_len; + offset += buffer.len; /* Check boundaries */ - if (offset < 0 || (buffer_len - offset) < soself->s_size) { + if (offset < 0 || (buffer.len - offset) < soself->s_size) { PyErr_Format(StructError, "pack_into requires a buffer of at least %zd bytes", soself->s_size); + PyBuffer_Release(&buffer); return NULL; } /* Call the guts */ - if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) { + if (s_pack_internal(soself, args, 2, (char*)buffer.buf + offset) != 0) { + PyBuffer_Release(&buffer); return NULL; } + PyBuffer_Release(&buffer); Py_RETURN_NONE; } diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -250,28 +250,7 @@ const char **buffer, Py_ssize_t *buffer_len) { - PyBufferProcs *pb; - Py_buffer view; - - if (obj == NULL || buffer == NULL || buffer_len == NULL) { - null_error(); - return -1; - } - pb = obj->ob_type->tp_as_buffer; - if (pb == NULL || pb->bf_getbuffer == NULL) { - PyErr_SetString(PyExc_TypeError, - "expected bytes, bytearray " - "or buffer compatible object"); - return -1; - } - if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1; - - *buffer = view.buf; - *buffer_len = view.len; - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(obj, &view); - Py_XDECREF(view.obj); - return 0; + return PyObject_AsReadBuffer(obj, (const void **)buffer, buffer_len); } int @@ -295,28 +274,18 @@ const void **buffer, Py_ssize_t *buffer_len) { - PyBufferProcs *pb; Py_buffer view; if (obj == NULL || buffer == NULL || buffer_len == NULL) { null_error(); return -1; } - pb = obj->ob_type->tp_as_buffer; - if (pb == NULL || - pb->bf_getbuffer == NULL) { - PyErr_SetString(PyExc_TypeError, - "expected an object with a buffer interface"); + if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) return -1; - } - - if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1; *buffer = view.buf; *buffer_len = view.len; - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(obj, &view); - Py_XDECREF(view.obj); + PyBuffer_Release(&view); return 0; } @@ -342,9 +311,7 @@ *buffer = view.buf; *buffer_len = view.len; - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(obj, &view); - Py_XDECREF(view.obj); + PyBuffer_Release(&view); return 0; } @@ -353,13 +320,15 @@ int PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { - if (!PyObject_CheckBuffer(obj)) { + PyBufferProcs *pb = obj->ob_type->tp_as_buffer; + + if (pb == NULL || pb->bf_getbuffer == NULL) { PyErr_Format(PyExc_TypeError, "'%.100s' does not support the buffer interface", Py_TYPE(obj)->tp_name); return -1; } - return (*(obj->ob_type->tp_as_buffer->bf_getbuffer))(obj, view, flags); + return (*pb->bf_getbuffer)(obj, view, flags); } static int @@ -652,10 +621,14 @@ PyBuffer_Release(Py_buffer *view) { PyObject *obj = view->obj; - if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer) - Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view); - Py_XDECREF(obj); + PyBufferProcs *pb; + if (obj == NULL) + return; + pb = Py_TYPE(obj)->tp_as_buffer; + if (pb && pb->bf_releasebuffer) + pb->bf_releasebuffer(obj, view); view->obj = NULL; + Py_DECREF(obj); } PyObject * @@ -1249,8 +1222,7 @@ { PyNumberMethods *m; PyObject *trunc_func; - const char *buffer; - Py_ssize_t buffer_len; + Py_buffer view; _Py_IDENTIFIER(__trunc__); if (o == NULL) @@ -1288,21 +1260,22 @@ if (PyErr_Occurred()) return NULL; - if (PyBytes_Check(o)) + if (PyUnicode_Check(o)) + /* The below check is done in PyLong_FromUnicode(). */ + return PyLong_FromUnicodeObject(o, 10); + + if (PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) == 0) { /* need to do extra error checking that PyLong_FromString() * doesn't do. In particular int('9\x005') must raise an * exception, not truncate at the null. */ - return _PyLong_FromBytes(PyBytes_AS_STRING(o), - PyBytes_GET_SIZE(o), 10); - if (PyUnicode_Check(o)) - /* The above check is done in PyLong_FromUnicode(). */ - return PyLong_FromUnicodeObject(o, 10); - if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) - return _PyLong_FromBytes(buffer, buffer_len, 10); + PyObject *result = _PyLong_FromBytes(view.buf, view.len, 10); + PyBuffer_Release(&view); + return result; + } - return type_error("int() argument must be a string or a " - "number, not '%.200s'", o); + return type_error("int() argument must be a string, a bytes-like object " + "or a number, not '%.200s'", o); } PyObject * diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -74,24 +74,6 @@ obj->ob_exports--; } -static Py_ssize_t -_getbuffer(PyObject *obj, Py_buffer *view) -{ - PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer; - - if (buffer == NULL || buffer->bf_getbuffer == NULL) - { - PyErr_Format(PyExc_TypeError, - "Type %.100s doesn't support the buffer API", - Py_TYPE(obj)->tp_name); - return -1; - } - - if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) - return -1; - return view->len; -} - static int _canresize(PyByteArrayObject *self) { @@ -262,8 +244,8 @@ va.len = -1; vb.len = -1; - if (_getbuffer(a, &va) < 0 || - _getbuffer(b, &vb) < 0) { + if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 || + PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); goto done; @@ -304,7 +286,7 @@ Py_ssize_t size; Py_buffer vo; - if (_getbuffer(other, &vo) < 0) { + if (PyObject_GetBuffer(other, &vo, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(other)->tp_name, Py_TYPE(self)->tp_name); return NULL; @@ -562,14 +544,14 @@ needed = 0; } else { - if (_getbuffer(values, &vbytes) < 0) { - PyErr_Format(PyExc_TypeError, - "can't set bytearray slice from %.100s", - Py_TYPE(values)->tp_name); - return -1; - } - needed = vbytes.len; - bytes = vbytes.buf; + if (PyObject_GetBuffer(values, &vbytes, PyBUF_SIMPLE) != 0) { + PyErr_Format(PyExc_TypeError, + "can't set bytearray slice from %.100s", + Py_TYPE(values)->tp_name); + return -1; + } + needed = vbytes.len; + bytes = vbytes.buf; } if (lo < 0) @@ -1012,18 +994,18 @@ Py_RETURN_NOTIMPLEMENTED; } - self_size = _getbuffer(self, &self_bytes); - if (self_size < 0) { + if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) { PyErr_Clear(); Py_RETURN_NOTIMPLEMENTED; } - - other_size = _getbuffer(other, &other_bytes); - if (other_size < 0) { + self_size = self_bytes.len; + + if (PyObject_GetBuffer(other, &other_bytes, PyBUF_SIMPLE) != 0) { PyErr_Clear(); PyBuffer_Release(&self_bytes); Py_RETURN_NOTIMPLEMENTED; } + other_size = other_bytes.len; if (self_size != other_size && (op == Py_EQ || op == Py_NE)) { /* Shortcut: if the lengths differ, the objects differ */ @@ -1135,7 +1117,7 @@ return -2; if (subobj) { - if (_getbuffer(subobj, &subbuf) < 0) + if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0) return -2; sub = subbuf.buf; @@ -1203,7 +1185,7 @@ return NULL; if (sub_obj) { - if (_getbuffer(sub_obj, &vsub) < 0) + if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; @@ -1318,7 +1300,7 @@ Py_buffer varg; Py_ssize_t pos; PyErr_Clear(); - if (_getbuffer(arg, &varg) < 0) + if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0) return -1; pos = stringlib_find(PyByteArray_AS_STRING(self), Py_SIZE(self), varg.buf, varg.len, 0); @@ -1349,7 +1331,7 @@ str = PyByteArray_AS_STRING(self); - if (_getbuffer(substr, &vsubstr) < 0) + if (PyObject_GetBuffer(substr, &vsubstr, PyBUF_SIMPLE) != 0) return -1; ADJUST_INDICES(start, end, len); @@ -1493,7 +1475,7 @@ if (tableobj == Py_None) { table = NULL; tableobj = NULL; - } else if (_getbuffer(tableobj, &vtable) < 0) { + } else if (PyObject_GetBuffer(tableobj, &vtable, PyBUF_SIMPLE) != 0) { return NULL; } else { if (vtable.len != 256) { @@ -1506,7 +1488,7 @@ } if (delobj != NULL) { - if (_getbuffer(delobj, &vdel) < 0) { + if (PyObject_GetBuffer(delobj, &vdel, PyBUF_SIMPLE) != 0) { if (tableobj != NULL) PyBuffer_Release(&vtable); return NULL; @@ -2070,26 +2052,20 @@ static PyObject * bytearray_replace(PyByteArrayObject *self, PyObject *args) { + PyObject *res; + Py_buffer old = {NULL, NULL}; + Py_buffer new = {NULL, NULL}; Py_ssize_t count = -1; - PyObject *from, *to, *res; - Py_buffer vfrom, vto; - - if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count)) + + if (!PyArg_ParseTuple(args, "y*y*|n:replace", &old, &new, &count)) return NULL; - if (_getbuffer(from, &vfrom) < 0) - return NULL; - if (_getbuffer(to, &vto) < 0) { - PyBuffer_Release(&vfrom); - return NULL; - } - res = (PyObject *)replace((PyByteArrayObject *) self, - vfrom.buf, vfrom.len, - vto.buf, vto.len, count); - - PyBuffer_Release(&vfrom); - PyBuffer_Release(&vto); + (const char *)old.buf, old.len, + (const char *)new.buf, new.len, count); + + PyBuffer_Release(&old); + PyBuffer_Release(&new); return res; } @@ -2120,7 +2096,7 @@ if (subobj == Py_None) return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(subobj, &vsub) < 0) + if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -2215,7 +2191,7 @@ if (subobj == Py_None) return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(subobj, &vsub) < 0) + if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -2503,7 +2479,7 @@ argsize = 6; } else { - if (_getbuffer(arg, &varg) < 0) + if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0) return NULL; argptr = (char *) varg.buf; argsize = varg.len; @@ -2540,7 +2516,7 @@ argsize = 6; } else { - if (_getbuffer(arg, &varg) < 0) + if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0) return NULL; argptr = (char *) varg.buf; argsize = varg.len; @@ -2574,7 +2550,7 @@ argsize = 6; } else { - if (_getbuffer(arg, &varg) < 0) + if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0) return NULL; argptr = (char *) varg.buf; argsize = varg.len; diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -363,41 +363,20 @@ in frm is mapped to the byte at the same position in to.\n\ The bytes objects frm and to must be of the same length."); -static Py_ssize_t -_getbuffer(PyObject *obj, Py_buffer *view) -{ - PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer; - - if (buffer == NULL || buffer->bf_getbuffer == NULL) - { - PyErr_Format(PyExc_TypeError, - "Type %.100s doesn't support the buffer API", - Py_TYPE(obj)->tp_name); - return -1; - } - - if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) - return -1; - return view->len; -} - PyObject * _Py_bytes_maketrans(PyObject *args) { - PyObject *frm, *to, *res = NULL; - Py_buffer bfrm, bto; + PyObject *res = NULL; + Py_buffer bfrm = {NULL, NULL}; + Py_buffer bto = {NULL, NULL}; Py_ssize_t i; char *p; bfrm.len = -1; bto.len = -1; - if (!PyArg_ParseTuple(args, "OO:maketrans", &frm, &to)) + if (!PyArg_ParseTuple(args, "y*y*:maketrans", &bfrm, &bto)) return NULL; - if (_getbuffer(frm, &bfrm) < 0) - return NULL; - if (_getbuffer(to, &bto) < 0) - goto done; if (bfrm.len != bto.len) { PyErr_Format(PyExc_ValueError, "maketrans arguments must have same length"); @@ -415,9 +394,9 @@ } done: - if (bfrm.len != -1) + if (bfrm.obj != NULL) PyBuffer_Release(&bfrm); - if (bto.len != -1) + if (bfrm.obj != NULL) PyBuffer_Release(&bto); return res; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -7,33 +7,6 @@ #include "bytes_methods.h" #include -static Py_ssize_t -_getbuffer(PyObject *obj, Py_buffer *view) -{ - PyBufferProcs *bufferprocs; - if (PyBytes_CheckExact(obj)) { - /* Fast path, e.g. for .join() of many bytes objects */ - Py_INCREF(obj); - view->obj = obj; - view->buf = PyBytes_AS_STRING(obj); - view->len = PyBytes_GET_SIZE(obj); - return view->len; - } - - bufferprocs = Py_TYPE(obj)->tp_as_buffer; - if (bufferprocs == NULL || bufferprocs->bf_getbuffer == NULL) - { - PyErr_Format(PyExc_TypeError, - "Type %.100s doesn't support the buffer API", - Py_TYPE(obj)->tp_name); - return -1; - } - - if (bufferprocs->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0) - return -1; - return view->len; -} - #ifdef COUNT_ALLOCS Py_ssize_t null_strings, one_strings; #endif @@ -695,8 +668,8 @@ va.len = -1; vb.len = -1; - if (_getbuffer(a, &va) < 0 || - _getbuffer(b, &vb) < 0) { + if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 || + PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); goto done; @@ -794,7 +767,7 @@ Py_buffer varg; Py_ssize_t pos; PyErr_Clear(); - if (_getbuffer(arg, &varg) < 0) + if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0) return -1; pos = stringlib_find(PyBytes_AS_STRING(self), Py_SIZE(self), varg.buf, varg.len, 0); @@ -1048,7 +1021,7 @@ maxsplit = PY_SSIZE_T_MAX; if (subobj == Py_None) return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(subobj, &vsub) < 0) + if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -1068,21 +1041,19 @@ static PyObject * bytes_partition(PyBytesObject *self, PyObject *sep_obj) { - const char *sep; - Py_ssize_t sep_len; - - if (PyBytes_Check(sep_obj)) { - sep = PyBytes_AS_STRING(sep_obj); - sep_len = PyBytes_GET_SIZE(sep_obj); - } - else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len)) + Py_buffer sep = {NULL, NULL}; + PyObject *res; + + if (PyObject_GetBuffer(sep_obj, &sep, PyBUF_SIMPLE) != 0) return NULL; - return stringlib_partition( + res = stringlib_partition( (PyObject*) self, PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), - sep_obj, sep, sep_len + sep_obj, sep.buf, sep.len ); + PyBuffer_Release(&sep); + return res; } PyDoc_STRVAR(rpartition__doc__, @@ -1096,21 +1067,19 @@ static PyObject * bytes_rpartition(PyBytesObject *self, PyObject *sep_obj) { - const char *sep; - Py_ssize_t sep_len; - - if (PyBytes_Check(sep_obj)) { - sep = PyBytes_AS_STRING(sep_obj); - sep_len = PyBytes_GET_SIZE(sep_obj); - } - else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len)) + Py_buffer sep = {NULL, NULL}; + PyObject *res; + + if (PyObject_GetBuffer(sep_obj, &sep, PyBUF_SIMPLE) != 0) return NULL; - return stringlib_rpartition( + res = stringlib_rpartition( (PyObject*) self, PyBytes_AS_STRING(self), PyBytes_GET_SIZE(self), - sep_obj, sep, sep_len + sep_obj, sep.buf, sep.len ); + PyBuffer_Release(&sep); + return res; } PyDoc_STRVAR(rsplit__doc__, @@ -1140,7 +1109,7 @@ maxsplit = PY_SSIZE_T_MAX; if (subobj == Py_None) return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit); - if (_getbuffer(subobj, &vsub) < 0) + if (PyObject_GetBuffer(subobj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; n = vsub.len; @@ -1202,7 +1171,7 @@ return -2; if (subobj) { - if (_getbuffer(subobj, &subbuf) < 0) + if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0) return -2; sub = subbuf.buf; @@ -1317,7 +1286,7 @@ Py_ssize_t seplen; Py_ssize_t i, j; - if (_getbuffer(sepobj, &vsep) < 0) + if (PyObject_GetBuffer(sepobj, &vsep, PyBUF_SIMPLE) != 0) return NULL; sep = vsep.buf; seplen = vsep.len; @@ -1462,7 +1431,7 @@ return NULL; if (sub_obj) { - if (_getbuffer(sub_obj, &vsub) < 0) + if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0) return NULL; sub = vsub.buf; @@ -1498,6 +1467,8 @@ bytes_translate(PyBytesObject *self, PyObject *args) { char *input, *output; + Py_buffer table_view = {NULL, NULL}; + Py_buffer del_table_view = {NULL, NULL}; const char *table; Py_ssize_t i, c, changed = 0; PyObject *input_obj = (PyObject*)self; @@ -1519,12 +1490,17 @@ table = NULL; tablen = 256; } - else if (PyObject_AsCharBuffer(tableobj, &table, &tablen)) - return NULL; + else { + if (PyObject_GetBuffer(tableobj, &table_view, PyBUF_SIMPLE) != 0) + return NULL; + table = table_view.buf; + tablen = table_view.len; + } if (tablen != 256) { PyErr_SetString(PyExc_ValueError, "translation table must be 256 characters long"); + PyBuffer_Release(&table_view); return NULL; } @@ -1533,8 +1509,14 @@ del_table = PyBytes_AS_STRING(delobj); dellen = PyBytes_GET_SIZE(delobj); } - else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen)) - return NULL; + else { + if (PyObject_GetBuffer(delobj, &del_table_view, PyBUF_SIMPLE) != 0) { + PyBuffer_Release(&table_view); + return NULL; + } + del_table = del_table_view.buf; + dellen = del_table_view.len; + } } else { del_table = NULL; @@ -1543,8 +1525,11 @@ inlen = PyBytes_GET_SIZE(input_obj); result = PyBytes_FromStringAndSize((char *)NULL, inlen); - if (result == NULL) + if (result == NULL) { + PyBuffer_Release(&del_table_view); + PyBuffer_Release(&table_view); return NULL; + } output_start = output = PyBytes_AsString(result); input = PyBytes_AS_STRING(input_obj); @@ -1555,11 +1540,14 @@ if (Py_CHARMASK((*output++ = table[c])) != c) changed = 1; } - if (changed || !PyBytes_CheckExact(input_obj)) - return result; - Py_DECREF(result); - Py_INCREF(input_obj); - return input_obj; + if (!changed && PyBytes_CheckExact(input_obj)) { + Py_INCREF(input_obj); + Py_DECREF(result); + result = input_obj; + } + PyBuffer_Release(&del_table_view); + PyBuffer_Release(&table_view); + return result; } if (table == NULL) { @@ -1569,9 +1557,11 @@ for (i = 0; i < 256; i++) trans_table[i] = Py_CHARMASK(table[i]); } + PyBuffer_Release(&table_view); for (i = 0; i < dellen; i++) trans_table[(int) Py_CHARMASK(del_table[i])] = -1; + PyBuffer_Release(&del_table_view); for (i = inlen; --i >= 0; ) { c = Py_CHARMASK(*input++); @@ -2100,31 +2090,21 @@ static PyObject * bytes_replace(PyBytesObject *self, PyObject *args) { + PyObject *res; + Py_buffer old = {NULL, NULL}; + Py_buffer new = {NULL, NULL}; Py_ssize_t count = -1; - PyObject *from, *to; - const char *from_s, *to_s; - Py_ssize_t from_len, to_len; - - if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count)) + + if (!PyArg_ParseTuple(args, "y*y*|n:replace", &old, &new, &count)) return NULL; - if (PyBytes_Check(from)) { - from_s = PyBytes_AS_STRING(from); - from_len = PyBytes_GET_SIZE(from); - } - else if (PyObject_AsCharBuffer(from, &from_s, &from_len)) - return NULL; - - if (PyBytes_Check(to)) { - to_s = PyBytes_AS_STRING(to); - to_len = PyBytes_GET_SIZE(to); - } - else if (PyObject_AsCharBuffer(to, &to_s, &to_len)) - return NULL; - - return (PyObject *)replace((PyBytesObject *) self, - from_s, from_len, - to_s, to_len, count); + res = (PyObject *)replace((PyBytesObject *) self, + (const char *)old.buf, old.len, + (const char *)new.buf, new.len, count); + + PyBuffer_Release(&old); + PyBuffer_Release(&new); + return res; } /** End DALKE **/ @@ -2139,6 +2119,7 @@ { Py_ssize_t len = PyBytes_GET_SIZE(self); Py_ssize_t slen; + Py_buffer sub_view = {NULL, NULL}; const char* sub; const char* str; @@ -2146,8 +2127,12 @@ sub = PyBytes_AS_STRING(substr); slen = PyBytes_GET_SIZE(substr); } - else if (PyObject_AsCharBuffer(substr, &sub, &slen)) - return -1; + else { + if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0) + return -1; + sub = sub_view.buf; + slen = sub_view.len; + } str = PyBytes_AS_STRING(self); ADJUST_INDICES(start, end, len); @@ -2155,17 +2140,25 @@ if (direction < 0) { /* startswith */ if (start+slen > len) - return 0; + goto notfound; } else { /* endswith */ if (end-start < slen || start > len) - return 0; + goto notfound; if (end-slen > start) start = end - slen; } - if (end-start >= slen) - return ! memcmp(str+start, sub, slen); + if (end-start < slen) + goto notfound; + if (memcmp(str+start, sub, slen) != 0) + goto notfound; + + PyBuffer_Release(&sub_view); + return 1; + +notfound: + PyBuffer_Release(&sub_view); return 0; } diff --git a/Objects/complexobject.c b/Objects/complexobject.c --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -767,6 +767,7 @@ int got_bracket=0; PyObject *s_buffer = NULL; Py_ssize_t len; + Py_buffer view = {NULL, NULL}; if (PyUnicode_Check(v)) { s_buffer = _PyUnicode_TransformDecimalAndSpaceToASCII(v); @@ -776,7 +777,11 @@ if (s == NULL) goto error; } - else if (PyObject_AsCharBuffer(v, &s, &len)) { + else if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) == 0) { + s = (const char *)view.buf; + len = view.len; + } + else { PyErr_Format(PyExc_TypeError, "complex() argument must be a string or a number, not '%.200s'", Py_TYPE(v)->tp_name); @@ -890,6 +895,7 @@ if (s-start != len) goto parse_error; + PyBuffer_Release(&view); Py_XDECREF(s_buffer); return complex_subtype_from_doubles(type, x, y); @@ -897,6 +903,7 @@ PyErr_SetString(PyExc_ValueError, "complex() arg is a malformed string"); error: + PyBuffer_Release(&view); Py_XDECREF(s_buffer); return NULL; } diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1922,8 +1922,6 @@ UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) { PyUnicodeErrorObject *ude; - const char *data; - Py_ssize_t size; if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; @@ -1944,21 +1942,27 @@ return -1; } + Py_INCREF(ude->encoding); + Py_INCREF(ude->object); + Py_INCREF(ude->reason); + if (!PyBytes_Check(ude->object)) { - if (PyObject_AsReadBuffer(ude->object, (const void **)&data, &size)) { - ude->encoding = ude->object = ude->reason = NULL; - return -1; - } - ude->object = PyBytes_FromStringAndSize(data, size); + Py_buffer view; + if (PyObject_GetBuffer(ude->object, &view, PyBUF_SIMPLE) != 0) + goto error; + Py_CLEAR(ude->object); + ude->object = PyBytes_FromStringAndSize(view.buf, view.len); + PyBuffer_Release(&view); + if (!ude->object) + goto error; } - else { - Py_INCREF(ude->object); - } - - Py_INCREF(ude->encoding); - Py_INCREF(ude->reason); - return 0; + +error: + Py_CLEAR(ude->encoding); + Py_CLEAR(ude->object); + Py_CLEAR(ude->reason); + return -1; } static PyObject * diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -131,6 +131,7 @@ double x; PyObject *s_buffer = NULL; Py_ssize_t len; + Py_buffer view = {NULL, NULL}; PyObject *result = NULL; if (PyUnicode_Check(v)) { @@ -143,7 +144,11 @@ return NULL; } } - else if (PyObject_AsCharBuffer(v, &s, &len)) { + else if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) == 0) { + s = (const char *)view.buf; + len = view.len; + } + else { PyErr_Format(PyExc_TypeError, "float() argument must be a string or a number, not '%.200s'", Py_TYPE(v)->tp_name); @@ -170,6 +175,7 @@ else result = PyFloat_FromDouble(x); + PyBuffer_Release(&view); Py_XDECREF(s_buffer); return result; } diff --git a/Objects/stringlib/join.h b/Objects/stringlib/join.h --- a/Objects/stringlib/join.h +++ b/Objects/stringlib/join.h @@ -58,7 +58,14 @@ for (i = 0, nbufs = 0; i < seqlen; i++) { Py_ssize_t itemlen; item = PySequence_Fast_GET_ITEM(seq, i); - if (_getbuffer(item, &buffers[i]) < 0) { + if (PyBytes_CheckExact(item)) { + /* Fast path. */ + Py_INCREF(item); + buffers[i].obj = item; + buffers[i].buf = PyBytes_AS_STRING(item); + buffers[i].len = PyBytes_GET_SIZE(item); + } + else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "sequence item %zd: expected a bytes-like object, " "%.80s found", diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -559,10 +559,10 @@ Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff."); -static char * -source_as_string(PyObject *cmd, char *funcname, char *what, PyCompilerFlags *cf) +static const char * +source_as_string(PyObject *cmd, const char *funcname, const char *what, PyCompilerFlags *cf, Py_buffer *view) { - char *str; + const char *str; Py_ssize_t size; if (PyUnicode_Check(cmd)) { @@ -571,19 +571,21 @@ if (str == NULL) return NULL; } - else if (!PyObject_CheckReadBuffer(cmd)) { + else if (PyObject_GetBuffer(cmd, view, PyBUF_SIMPLE) == 0) { + str = (const char *)view->buf; + size = view->len; + } + else { PyErr_Format(PyExc_TypeError, "%s() arg 1 must be a %s object", funcname, what); return NULL; } - else if (PyObject_AsReadBuffer(cmd, (const void **)&str, &size) < 0) { - return NULL; - } if (strlen(str) != size) { PyErr_SetString(PyExc_TypeError, "source code string cannot contain null bytes"); + PyBuffer_Release(view); return NULL; } return str; @@ -592,7 +594,8 @@ static PyObject * builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) { - char *str; + Py_buffer view = {NULL, NULL}; + const char *str; PyObject *filename; char *startstr; int mode = -1; @@ -678,11 +681,12 @@ goto finally; } - str = source_as_string(cmd, "compile", "string, bytes or AST", &cf); + str = source_as_string(cmd, "compile", "string, bytes or AST", &cf, &view); if (str == NULL) goto error; result = Py_CompileStringObject(str, filename, start[mode], &cf, optimize); + PyBuffer_Release(&view); goto finally; error: @@ -752,7 +756,8 @@ { PyObject *cmd, *result, *tmp = NULL; PyObject *globals = Py_None, *locals = Py_None; - char *str; + Py_buffer view = {NULL, NULL}; + const char *str; PyCompilerFlags cf; if (!PyArg_UnpackTuple(args, "eval", 1, 3, &cmd, &globals, &locals)) @@ -801,7 +806,7 @@ } cf.cf_flags = PyCF_SOURCE_IS_UTF8; - str = source_as_string(cmd, "eval", "string, bytes or code", &cf); + str = source_as_string(cmd, "eval", "string, bytes or code", &cf, &view); if (str == NULL) return NULL; @@ -810,6 +815,7 @@ (void)PyEval_MergeCompilerFlags(&cf); result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); + PyBuffer_Release(&view); Py_XDECREF(tmp); return result; } @@ -876,11 +882,12 @@ v = PyEval_EvalCode(prog, globals, locals); } else { - char *str; + Py_buffer view = {NULL, NULL}; + const char *str; PyCompilerFlags cf; cf.cf_flags = PyCF_SOURCE_IS_UTF8; str = source_as_string(prog, "exec", - "string, bytes or code", &cf); + "string, bytes or code", &cf, &view); if (str == NULL) return NULL; if (PyEval_MergeCompilerFlags(&cf)) @@ -888,6 +895,7 @@ locals, &cf); else v = PyRun_String(str, Py_file_input, globals, locals); + PyBuffer_Release(&view); } if (v == NULL) return NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 07:44:50 2015 From: python-checkins at python.org (berker.peksag) Date: Tue, 03 Feb 2015 06:44:50 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_328=3A_Fix_a_broken_link?= =?utf-8?q?=2E?= Message-ID: <20150203064444.39274.19498@psf.io> https://hg.python.org/peps/rev/8e6299fb8454 changeset: 5691:8e6299fb8454 user: Berker Peksag date: Tue Feb 03 08:44:51 2015 +0200 summary: PEP 328: Fix a broken link. files: pep-0328.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0328.txt b/pep-0328.txt --- a/pep-0328.txt +++ b/pep-0328.txt @@ -315,7 +315,7 @@ .. [1] http://mail.python.org/pipermail/python-dev/2004-March/043739.html -.. [2] http://www.python.org/doc/essays/packages.html +.. [2] https://www.python.org/doc/essays/packages/ Copyright -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Tue Feb 3 08:31:44 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 07:31:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323099=3A_Closing_io=2EBytesIO_with_exported_buf?= =?utf-8?q?fer_is_rejected_now_to?= Message-ID: <20150203073130.25847.70451@psf.io> https://hg.python.org/cpython/rev/b9d4c013b09a changeset: 94481:b9d4c013b09a parent: 94479:4cb316fe6bf2 parent: 94480:e62d54128bd3 user: Serhiy Storchaka date: Tue Feb 03 09:30:51 2015 +0200 summary: Issue #23099: Closing io.BytesIO with exported buffer is rejected now to prevent corrupting exported buffer. files: Doc/library/io.rst | 13 +++++++------ Lib/_pyio.py | 6 ++++++ Lib/test/test_memoryio.py | 7 ++++++- Misc/NEWS | 3 +++ Modules/_io/bytesio.c | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -578,7 +578,8 @@ .. class:: BytesIO([initial_bytes]) A stream implementation using an in-memory bytes buffer. It inherits - :class:`BufferedIOBase`. + :class:`BufferedIOBase`. The buffer is discarded when the + :meth:`~IOBase.close` method is called. The argument *initial_bytes* contains optional initial :class:`bytes` data. @@ -599,7 +600,7 @@ .. note:: As long as the view exists, the :class:`BytesIO` object cannot be - resized. + resized or closed. .. versionadded:: 3.2 @@ -607,6 +608,7 @@ Return :class:`bytes` containing the entire contents of the buffer. + .. method:: read1() In :class:`BytesIO`, this is the same as :meth:`read`. @@ -880,7 +882,8 @@ .. class:: StringIO(initial_value='', newline='\\n') - An in-memory stream for text I/O. + An in-memory stream for text I/O. The text buffer is discarded when the + :meth:`~IOBase.close` method is called. The initial value of the buffer (an empty string by default) can be set by providing *initial_value*. The *newline* argument works like that of @@ -892,9 +895,7 @@ .. method:: getvalue() - Return a ``str`` containing the entire contents of the buffer at any - time before the :class:`StringIO` object's :meth:`close` method is - called. + Return a ``str`` containing the entire contents of the buffer. Example usage:: diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -852,8 +852,14 @@ def getbuffer(self): """Return a readable and writable view of the buffer. """ + if self.closed: + raise ValueError("getbuffer on closed file") return memoryview(self._buffer) + def close(self): + self._buffer.clear() + super().close() + def read(self, size=None): if self.closed: raise ValueError("read from closed file") diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -399,14 +399,19 @@ # raises a BufferError. self.assertRaises(BufferError, memio.write, b'x' * 100) self.assertRaises(BufferError, memio.truncate) + self.assertRaises(BufferError, memio.close) + self.assertFalse(memio.closed) # Mutating the buffer updates the BytesIO buf[3:6] = b"abc" self.assertEqual(bytes(buf), b"123abc7890") self.assertEqual(memio.getvalue(), b"123abc7890") - # After the buffer gets released, we can resize the BytesIO again + # After the buffer gets released, we can resize and close the BytesIO + # again del buf support.gc_collect() memio.truncate() + memio.close() + self.assertRaises(ValueError, memio.getbuffer) class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -232,6 +232,9 @@ Library ------- +- Issue #23099: Closing io.BytesIO with exported buffer is rejected now to + prevent corrupting exported buffer. + - Issue #23326: Removed __ne__ implementations. Since fixing default __ne__ implementation in issue #21408 they are redundant. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -779,6 +779,7 @@ static PyObject * bytesio_close(bytesio *self) { + CHECK_EXPORTS(self); reset(self); Py_RETURN_NONE; } -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Tue Feb 3 09:02:33 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 03 Feb 2015 09:02:33 +0100 Subject: [Python-checkins] Daily reference leaks (4cb316fe6bf2): sum=3 Message-ID: results for 4cb316fe6bf2 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogbMOxGv', '-x'] From python-checkins at python.org Tue Feb 3 10:05:15 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 09:05:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322818=3A_Splittin?= =?utf-8?q?g_on_a_pattern_that_could_match_an_empty_string_now?= Message-ID: <20150203090510.106309.14683@psf.io> https://hg.python.org/cpython/rev/7c667d8ae10d changeset: 94482:7c667d8ae10d user: Serhiy Storchaka date: Tue Feb 03 11:04:19 2015 +0200 summary: Issue #22818: Splitting on a pattern that could match an empty string now raises a warning. Patterns that can only match empty strings are now rejected. files: Doc/library/re.rst | 32 +++++++++++++++++++++---- Doc/whatsnew/3.5.rst | 7 +++++ Lib/sre_compile.py | 10 ++++---- Lib/test/test_re.py | 39 ++++++++++++++++++++++++------- Misc/NEWS | 4 +++ Modules/_sre.c | 13 ++++++++++ 6 files changed, 85 insertions(+), 20 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -626,17 +626,37 @@ That way, separator components are always found at the same relative indices within the result list. - Note that *split* will never split a string on an empty pattern match. - For example: + .. note:: - >>> re.split('x*', 'foo') - ['foo'] - >>> re.split("(?m)^$", "foo\n\nbar\n") - ['foo\n\nbar\n'] + :func:`split` doesn't currently split a string on an empty pattern match. + For example: + + >>> re.split('x*', 'axbc') + ['a', 'bc'] + + Even though ``'x*'`` also matches 0 'x' before 'a', between 'b' and 'c', + and after 'c', currently these matches are ignored. The correct behavior + (i.e. splitting on empty matches too and returning ``['', 'a', 'b', 'c', + '']``) will be implemented in future versions of Python, but since this + is a backward incompatible change, a :exc:`FutureWarning` will be raised + in the meanwhile. + + Patterns that can only match empty strings currently never split the + string. Since this doesn't match the expected behavior, a + :exc:`ValueError` will be raised starting from Python 3.5:: + + >>> re.split("^$", "foo\n\nbar\n", flags=re.M) + Traceback (most recent call last): + File "", line 1, in + ... + ValueError: split() requires a non-empty pattern match. .. versionchanged:: 3.1 Added the optional flags argument. + .. versionchanged:: 3.5 + Splitting on a pattern that could match an empty string now raises + a warning. Patterns that can only match empty strings are now rejected. .. function:: findall(pattern, string, flags=0) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -482,6 +482,13 @@ simply define :meth:`~importlib.machinery.Loader.create_module` to return ``None`` (:issue:`23014`). +* :func:`re.split` always ignored empty pattern matches, so the ``'x*'`` + pattern worked the same as ``'x+'``, and the ``'\b'`` pattern never worked. + Now :func:`re.split` raises a warning if the pattern could match + an empty string. For compatibility use patterns that never match an empty + string (e.g. ``'x+'`` instead of ``'x*'``). Patterns that could only match + an empty string (such as ``'\b'``) now raise an error. + Changes in the C API -------------------- diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -414,8 +414,11 @@ # this contains min/max pattern width, and an optional literal # prefix or a character map lo, hi = pattern.getwidth() + if hi > MAXCODE: + hi = MAXCODE if lo == 0: - return # not worth it + code.extend([INFO, 4, 0, lo, hi]) + return # look for a literal prefix prefix = [] prefixappend = prefix.append @@ -495,10 +498,7 @@ else: emit(MAXCODE) prefix = prefix[:MAXCODE] - if hi < MAXCODE: - emit(hi) - else: - emit(0) + emit(min(hi, MAXCODE)) # add literal prefix if prefix: emit(len(prefix)) # length diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -251,28 +251,28 @@ for string in ":a:b::c", S(":a:b::c"): self.assertTypedEqual(re.split(":", string), ['', 'a', 'b', '', 'c']) - self.assertTypedEqual(re.split(":*", string), + self.assertTypedEqual(re.split(":+", string), ['', 'a', 'b', 'c']) - self.assertTypedEqual(re.split("(:*)", string), + self.assertTypedEqual(re.split("(:+)", string), ['', ':', 'a', ':', 'b', '::', 'c']) for string in (b":a:b::c", B(b":a:b::c"), bytearray(b":a:b::c"), memoryview(b":a:b::c")): self.assertTypedEqual(re.split(b":", string), [b'', b'a', b'b', b'', b'c']) - self.assertTypedEqual(re.split(b":*", string), + self.assertTypedEqual(re.split(b":+", string), [b'', b'a', b'b', b'c']) - self.assertTypedEqual(re.split(b"(:*)", string), + self.assertTypedEqual(re.split(b"(:+)", string), [b'', b':', b'a', b':', b'b', b'::', b'c']) for a, b, c in ("\xe0\xdf\xe7", "\u0430\u0431\u0432", "\U0001d49c\U0001d49e\U0001d4b5"): string = ":%s:%s::%s" % (a, b, c) self.assertEqual(re.split(":", string), ['', a, b, '', c]) - self.assertEqual(re.split(":*", string), ['', a, b, c]) - self.assertEqual(re.split("(:*)", string), + self.assertEqual(re.split(":+", string), ['', a, b, c]) + self.assertEqual(re.split("(:+)", string), ['', ':', a, ':', b, '::', c]) - self.assertEqual(re.split("(?::*)", ":a:b::c"), ['', 'a', 'b', 'c']) - self.assertEqual(re.split("(:)*", ":a:b::c"), + self.assertEqual(re.split("(?::+)", ":a:b::c"), ['', 'a', 'b', 'c']) + self.assertEqual(re.split("(:)+", ":a:b::c"), ['', ':', 'a', ':', 'b', ':', 'c']) self.assertEqual(re.split("([b:]+)", ":a:b::c"), ['', ':', 'a', ':b::', 'c']) @@ -282,13 +282,34 @@ self.assertEqual(re.split("(?:b)|(?::+)", ":a:b::c"), ['', 'a', '', '', 'c']) + for sep, expected in [ + (':*', ['', 'a', 'b', 'c']), + ('(?::*)', ['', 'a', 'b', 'c']), + ('(:*)', ['', ':', 'a', ':', 'b', '::', 'c']), + ('(:)*', ['', ':', 'a', ':', 'b', ':', 'c']), + ]: + with self.subTest(sep=sep), self.assertWarns(FutureWarning): + self.assertTypedEqual(re.split(sep, ':a:b::c'), expected) + + for sep, expected in [ + ('', [':a:b::c']), + (r'\b', [':a:b::c']), + (r'(?=:)', [':a:b::c']), + (r'(?<=:)', [':a:b::c']), + ]: + with self.subTest(sep=sep), self.assertRaises(ValueError): + self.assertTypedEqual(re.split(sep, ':a:b::c'), expected) + def test_qualified_re_split(self): self.assertEqual(re.split(":", ":a:b::c", maxsplit=2), ['', 'a', 'b::c']) self.assertEqual(re.split(':', 'a:b:c:d', maxsplit=2), ['a', 'b', 'c:d']) self.assertEqual(re.split("(:)", ":a:b::c", maxsplit=2), ['', ':', 'a', ':', 'b::c']) - self.assertEqual(re.split("(:*)", ":a:b::c", maxsplit=2), + self.assertEqual(re.split("(:+)", ":a:b::c", maxsplit=2), ['', ':', 'a', ':', 'b::c']) + with self.assertWarns(FutureWarning): + self.assertEqual(re.split("(:*)", ":a:b::c", maxsplit=2), + ['', ':', 'a', ':', 'b::c']) def test_re_findall(self): self.assertEqual(re.findall(":+", "abc"), []) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -232,6 +232,10 @@ Library ------- +- Issue #22818: Splitting on a pattern that could match an empty string now + raises a warning. Patterns that can only match empty strings are now + rejected. + - Issue #23099: Closing io.BytesIO with exported buffer is rejected now to prevent corrupting exported buffer. diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -863,6 +863,19 @@ if (!string) return NULL; + assert(self->codesize != 0); + if (self->code[0] != SRE_OP_INFO || self->code[3] == 0) { + if (self->code[0] == SRE_OP_INFO && self->code[4] == 0) { + PyErr_SetString(PyExc_ValueError, + "split() requires a non-empty pattern match."); + return NULL; + } + if (PyErr_WarnEx(PyExc_FutureWarning, + "split() requires a non-empty pattern match.", + 1) < 0) + return NULL; + } + string = state_init(&state, self, string, 0, PY_SSIZE_T_MAX); if (!string) return NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 10:31:13 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 09:31:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315381=3A_Optimize?= =?utf-8?q?d_io=2EBytesIO_to_make_less_allocations_and_copyings=2E?= Message-ID: <20150203093057.34390.35293@psf.io> https://hg.python.org/cpython/rev/2e29d54843a4 changeset: 94483:2e29d54843a4 user: Serhiy Storchaka date: Tue Feb 03 11:30:10 2015 +0200 summary: Issue #15381: Optimized io.BytesIO to make less allocations and copyings. files: Doc/whatsnew/3.5.rst | 3 + Lib/test/test_memoryio.py | 5 +- Misc/NEWS | 2 + Modules/_io/bytesio.c | 338 +++++++++++-------------- 4 files changed, 159 insertions(+), 189 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -362,6 +362,9 @@ The speed up can range from 3x to 15x. (:issue:`21486`, :issue:`21487`, :issue:`20826`) +* Many operations on :class:`io.BytesIO` are now 50% to 100% faster. + (Contributed by Serhiy Storchaka in :issue:`15381`.) + Build and C API Changes ======================= diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -718,12 +718,11 @@ @support.cpython_only def test_sizeof(self): - basesize = support.calcobjsize('P2nN2PnP') + basesize = support.calcobjsize('P2n2Pn') check = self.check_sizeof self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) check(io.BytesIO(), basesize ) - check(io.BytesIO(b'a'), basesize + 1 ) - check(io.BytesIO(b'a' * 1000), basesize + 1000) + check(io.BytesIO(b'a' * 1000), basesize + sys.getsizeof(b'a' * 1000)) # Various tests of copy-on-write behaviour for BytesIO. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -232,6 +232,8 @@ Library ------- +- Issue #15381: Optimized io.BytesIO to make less allocations and copyings. + - Issue #22818: Splitting on a pattern that could match an empty string now raises a warning. Patterns that can only match empty strings are now rejected. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -4,17 +4,12 @@ typedef struct { PyObject_HEAD - char *buf; + PyObject *buf; Py_ssize_t pos; Py_ssize_t string_size; - size_t buf_size; PyObject *dict; PyObject *weakreflist; Py_ssize_t exports; - /** If `initvalue' != NULL, `buf' is a read-only pointer into the PyBytes - * referenced by `initvalue'. It must be copied prior to mutation, and - * released during finalization */ - PyObject *initvalue; } bytesio; typedef struct { @@ -22,12 +17,18 @@ bytesio *source; } bytesiobuf; +/* The bytesio object can be in three states: + * Py_REFCNT(buf) == 1, exports == 0. + * Py_REFCNT(buf) > 1. exports == 0, string_size == PyBytes_GET_SIZE(buf), + first modification or export causes the internal buffer copying. + * exports > 0. Py_REFCNT(buf) == 1, any modifications are forbidden. +*/ -#define CHECK_CLOSED(self, ret) \ +#define CHECK_CLOSED(self) \ if ((self)->buf == NULL) { \ PyErr_SetString(PyExc_ValueError, \ "I/O operation on closed file."); \ - return ret; \ + return NULL; \ } #define CHECK_EXPORTS(self) \ @@ -37,47 +38,8 @@ return NULL; \ } -/* Ensure we have a buffer suitable for writing, in the case that an initvalue - * object was provided, and we're currently borrowing its buffer. `size' - * indicates the new buffer size allocated as part of unsharing, to avoid a - * redundant reallocation caused by any subsequent mutation. `truncate' - * indicates whether truncation should occur if `size` < self->string_size. - * - * Do nothing if the buffer wasn't shared. Returns 0 on success, or sets an - * exception and returns -1 on failure. Existing state is preserved on failure. - */ -static int -unshare(bytesio *self, size_t preferred_size, int truncate) -{ - if (self->initvalue) { - Py_ssize_t copy_size; - char *new_buf; +#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1) - if((! truncate) && preferred_size < (size_t)self->string_size) { - preferred_size = self->string_size; - } - - /* PyMem_Malloc() returns NULL if preferred_size is bigger - than PY_SSIZE_T_MAX */ - new_buf = (char *)PyMem_Malloc(preferred_size); - if (new_buf == NULL) { - PyErr_NoMemory(); - return -1; - } - - copy_size = self->string_size; - if ((size_t)copy_size > preferred_size) { - copy_size = preferred_size; - } - - memcpy(new_buf, self->buf, copy_size); - Py_CLEAR(self->initvalue); - self->buf = new_buf; - self->buf_size = preferred_size; - self->string_size = (Py_ssize_t) copy_size; - } - return 0; -} /* Internal routine to get a line from the buffer of a BytesIO object. Returns the length between the current position to the @@ -91,7 +53,7 @@ assert(self->buf != NULL); /* Move to the end of the line, up to the end of the string, s. */ - start = self->buf + self->pos; + start = PyBytes_AS_STRING(self->buf) + self->pos; maxlen = self->string_size - self->pos; if (len < 0 || len > maxlen) len = maxlen; @@ -109,6 +71,27 @@ return len; } +/* Internal routine for detaching the shared buffer of BytesIO objects. + The caller should ensure that the 'size' argument is non-negative and + not lesser than self->string_size. Returns 0 on success, -1 otherwise. */ +static int +unshare_buffer(bytesio *self, size_t size) +{ + PyObject *new_buf, *old_buf; + assert(SHARED_BUF(self)); + assert(self->exports == 0); + assert(size >= (size_t)self->string_size); + new_buf = PyBytes_FromStringAndSize(NULL, size); + if (new_buf == NULL) + return -1; + memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf), + self->string_size); + old_buf = self->buf; + self->buf = new_buf; + Py_DECREF(old_buf); + return 0; +} + /* Internal routine for changing the size of the buffer of BytesIO objects. The caller should ensure that the 'size' argument is non-negative. Returns 0 on success, -1 otherwise. */ @@ -117,8 +100,7 @@ { /* Here, unsigned types are used to avoid dealing with signed integer overflow, which is undefined in C. */ - size_t alloc = self->buf_size; - char *new_buf = NULL; + size_t alloc = PyBytes_GET_SIZE(self->buf); assert(self->buf != NULL); @@ -146,13 +128,15 @@ if (alloc > ((size_t)-1) / sizeof(char)) goto overflow; - new_buf = (char *)PyMem_Realloc(self->buf, alloc * sizeof(char)); - if (new_buf == NULL) { - PyErr_NoMemory(); - return -1; + + if (SHARED_BUF(self)) { + if (unshare_buffer(self, alloc) < 0) + return -1; } - self->buf_size = alloc; - self->buf = new_buf; + else { + if (_PyBytes_Resize(&self->buf, alloc) < 0) + return -1; + } return 0; @@ -167,19 +151,16 @@ static Py_ssize_t write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) { - size_t desired; - assert(self->buf != NULL); assert(self->pos >= 0); assert(len >= 0); - desired = (size_t)self->pos + len; - if (unshare(self, desired, 0) < 0) { - return -1; + if ((size_t)self->pos + len > (size_t)PyBytes_GET_SIZE(self->buf)) { + if (resize_buffer(self, (size_t)self->pos + len) < 0) + return -1; } - - if (desired > self->buf_size) { - if (resize_buffer(self, (size_t)self->pos + len) < 0) + else if (SHARED_BUF(self)) { + if (unshare_buffer(self, self->string_size) < 0) return -1; } @@ -192,13 +173,13 @@ | | <--to pad-->|<---to write---> | 0 buf position */ - memset(self->buf + self->string_size, '\0', + memset(PyBytes_AS_STRING(self->buf) + self->string_size, '\0', (self->pos - self->string_size) * sizeof(char)); } /* Copy the data to the internal buffer, overwriting some of the existing data if self->pos < self->string_size. */ - memcpy(self->buf + self->pos, bytes, len); + memcpy(PyBytes_AS_STRING(self->buf) + self->pos, bytes, len); self->pos += len; /* Set the new length of the internal string if it has changed. */ @@ -209,74 +190,6 @@ return len; } -/* Release or free any existing buffer, and place the BytesIO in the closed - * state. */ -static void -reset(bytesio *self) -{ - if (self->initvalue) { - Py_CLEAR(self->initvalue); - } else if (self->buf) { - PyMem_Free(self->buf); - } - self->buf = NULL; - self->string_size = 0; - self->pos = 0; -} - -/* Reinitialize with a new heap-allocated buffer of size `size`. Returns 0 on - * success, or sets an exception and returns -1 on failure. Existing state is - * preserved on failure. */ -static int -reinit_private(bytesio *self, Py_ssize_t size) -{ - char *tmp = (char *)PyMem_Malloc(size); - if (tmp == NULL) { - PyErr_NoMemory(); - return -1; - } - reset(self); - self->buf = tmp; - self->buf_size = size; - return 0; -} - -/* Internal version of BytesIO.__init__; resets the object to its initial - * (closed) state before repopulating it, optionally by sharing a PyBytes - * buffer provided by `initvalue'. Returns 0 on success, or sets an exception - * and returns -1 on failure. */ -static int -reinit(bytesio *self, PyObject *initvalue) -{ - CHECK_CLOSED(self, -1); - - if (initvalue == NULL || initvalue == Py_None) { - if (reinit_private(self, 0) < 0) { - return -1; - } - } else if (PyBytes_CheckExact(initvalue)) { - reset(self); - Py_INCREF(initvalue); - self->initvalue = initvalue; - self->buf = PyBytes_AS_STRING(initvalue); - self->buf_size = PyBytes_GET_SIZE(initvalue); - self->string_size = PyBytes_GET_SIZE(initvalue); - } else { - Py_buffer buf; - if (PyObject_GetBuffer(initvalue, &buf, PyBUF_CONTIG_RO) < 0) { - return -1; - } - if (reinit_private(self, buf.len) < 0) { - PyBuffer_Release(&buf); - return -1; - } - memcpy(self->buf, buf.buf, buf.len); - self->string_size = buf.len; - PyBuffer_Release(&buf); - } - return 0; -} - static PyObject * bytesio_get_closed(bytesio *self) { @@ -301,7 +214,7 @@ static PyObject * return_not_closed(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); Py_RETURN_TRUE; } @@ -311,7 +224,7 @@ static PyObject * bytesio_flush(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); Py_RETURN_NONE; } @@ -327,7 +240,7 @@ bytesiobuf *buf; PyObject *view; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); buf = (bytesiobuf *) type->tp_alloc(type, 0); if (buf == NULL) @@ -347,8 +260,23 @@ static PyObject * bytesio_getvalue(bytesio *self) { - CHECK_CLOSED(self, NULL); - return PyBytes_FromStringAndSize(self->buf, self->string_size); + CHECK_CLOSED(self); + if (self->string_size <= 1 || self->exports > 0) + return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf), + self->string_size); + + if (self->string_size != PyBytes_GET_SIZE(self->buf)) { + if (SHARED_BUF(self)) { + if (unshare_buffer(self, self->string_size) < 0) + return NULL; + } + else { + if (_PyBytes_Resize(&self->buf, self->string_size) < 0) + return NULL; + } + } + Py_INCREF(self->buf); + return self->buf; } PyDoc_STRVAR(isatty_doc, @@ -360,7 +288,7 @@ static PyObject * bytesio_isatty(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); Py_RETURN_FALSE; } @@ -370,10 +298,29 @@ static PyObject * bytesio_tell(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); return PyLong_FromSsize_t(self->pos); } +static PyObject * +read_bytes(bytesio *self, Py_ssize_t size) +{ + char *output; + + assert(self->buf != NULL); + if (size > 1 && + self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && + self->exports == 0) { + self->pos += size; + Py_INCREF(self->buf); + return self->buf; + } + + output = PyBytes_AS_STRING(self->buf) + self->pos; + self->pos += size; + return PyBytes_FromStringAndSize(output, size); +} + PyDoc_STRVAR(read_doc, "read([size]) -> read at most size bytes, returned as a string.\n" "\n" @@ -384,10 +331,9 @@ bytesio_read(bytesio *self, PyObject *args) { Py_ssize_t size, n; - char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "|O:read", &arg)) return NULL; @@ -415,11 +361,7 @@ size = 0; } - assert(self->buf != NULL); - output = self->buf + self->pos; - self->pos += size; - - return PyBytes_FromStringAndSize(output, size); + return read_bytes(self, size); } @@ -453,10 +395,9 @@ bytesio_readline(bytesio *self, PyObject *args) { Py_ssize_t size, n; - char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "|O:readline", &arg)) return NULL; @@ -478,9 +419,7 @@ n = scan_eol(self, size); - output = self->buf + self->pos; - self->pos += n; - return PyBytes_FromStringAndSize(output, n); + return read_bytes(self, n); } PyDoc_STRVAR(readlines_doc, @@ -498,7 +437,7 @@ char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "|O:readlines", &arg)) return NULL; @@ -523,7 +462,7 @@ if (!result) return NULL; - output = self->buf + self->pos; + output = PyBytes_AS_STRING(self->buf) + self->pos; while ((n = scan_eol(self, -1)) != 0) { self->pos += n; line = PyBytes_FromStringAndSize(output, n); @@ -558,7 +497,7 @@ Py_buffer buffer; Py_ssize_t len, n; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_Parse(arg, "w*", &buffer)) return NULL; @@ -572,7 +511,7 @@ len = 0; } - memcpy(buffer.buf, self->buf + self->pos, len); + memcpy(buffer.buf, PyBytes_AS_STRING(self->buf) + self->pos, len); assert(self->pos + len < PY_SSIZE_T_MAX); assert(len >= 0); self->pos += len; @@ -593,7 +532,7 @@ Py_ssize_t size; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); CHECK_EXPORTS(self); if (!PyArg_ParseTuple(args, "|O:truncate", &arg)) @@ -620,10 +559,6 @@ return NULL; } - if (unshare(self, size, 1) < 0) { - return NULL; - } - if (size < self->string_size) { self->string_size = size; if (resize_buffer(self, size) < 0) @@ -636,19 +571,16 @@ static PyObject * bytesio_iternext(bytesio *self) { - const char *next; Py_ssize_t n; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); n = scan_eol(self, -1); if (n == 0) return NULL; - next = self->buf + self->pos; - self->pos += n; - return PyBytes_FromStringAndSize(next, n); + return read_bytes(self, n); } PyDoc_STRVAR(seek_doc, @@ -666,7 +598,7 @@ Py_ssize_t pos; int mode = 0; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode)) return NULL; @@ -721,7 +653,7 @@ Py_buffer buf; PyObject *result = NULL; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); CHECK_EXPORTS(self); if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0) @@ -749,7 +681,7 @@ PyObject *it, *item; PyObject *ret; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); it = PyObject_GetIter(v); if (it == NULL) @@ -780,7 +712,7 @@ bytesio_close(bytesio *self) { CHECK_EXPORTS(self); - reset(self); + Py_CLEAR(self->buf); Py_RETURN_NONE; } @@ -828,11 +760,11 @@ static PyObject * bytesio_setstate(bytesio *self, PyObject *state) { + PyObject *result; PyObject *position_obj; PyObject *dict; Py_ssize_t pos; - CHECK_EXPORTS(self); assert(state != NULL); /* We allow the state tuple to be longer than 3, because we may need @@ -844,13 +776,18 @@ Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name); return NULL; } + CHECK_EXPORTS(self); + /* Reset the object to its default state. This is only needed to handle + the case of repeated calls to __setstate__. */ + self->string_size = 0; + self->pos = 0; - /* Reset the object to its default state and set the value of the internal - * buffer. If state[0] does not support the buffer protocol, reinit() will - * raise the appropriate TypeError. */ - if (reinit(self, PyTuple_GET_ITEM(state, 0)) < 0) { + /* Set the value of the internal buffer. If state[0] does not support the + buffer protocol, bytesio_write will raise the appropriate TypeError. */ + result = bytesio_write(self, PyTuple_GET_ITEM(state, 0)); + if (result == NULL) return NULL; - } + Py_DECREF(result); /* Set carefully the position value. Alternatively, we could use the seek method instead of modifying self->pos directly to better protect the @@ -905,9 +842,7 @@ "deallocated BytesIO object has exported buffers"); PyErr_Print(); } - - reset(self); - + Py_CLEAR(self->buf); Py_CLEAR(self->dict); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -927,7 +862,7 @@ /* tp_alloc initializes all the fields to zero. So we don't have to initialize them here. */ - self->buf = (char *)PyMem_Malloc(0); + self->buf = PyBytes_FromStringAndSize(NULL, 0); if (self->buf == NULL) { Py_DECREF(self); return PyErr_NoMemory(); @@ -946,7 +881,33 @@ &initvalue)) return -1; - return reinit(self, initvalue); + /* In case, __init__ is called multiple times. */ + self->string_size = 0; + self->pos = 0; + + if (self->exports > 0) { + PyErr_SetString(PyExc_BufferError, + "Existing exports of data: object cannot be re-sized"); + return -1; + } + if (initvalue && initvalue != Py_None) { + if (PyBytes_CheckExact(initvalue)) { + Py_INCREF(initvalue); + Py_XDECREF(self->buf); + self->buf = initvalue; + self->string_size = PyBytes_GET_SIZE(initvalue); + } + else { + PyObject *res; + res = bytesio_write(self, initvalue); + if (res == NULL) + return -1; + Py_DECREF(res); + self->pos = 0; + } + } + + return 0; } static PyObject * @@ -955,8 +916,8 @@ Py_ssize_t res; res = sizeof(bytesio); - if (self->buf) - res += self->buf_size; + if (self->buf && !SHARED_BUF(self)) + res += _PySys_GetSizeOf(self->buf); return PyLong_FromSsize_t(res); } @@ -1066,11 +1027,16 @@ { int ret; bytesio *b = (bytesio *) obj->source; + if (SHARED_BUF(b)) { + if (unshare_buffer(b, b->string_size) < 0) + return -1; + } if (view == NULL) { b->exports++; return 0; } - ret = PyBuffer_FillInfo(view, (PyObject*)obj, b->buf, b->string_size, + ret = PyBuffer_FillInfo(view, (PyObject*)obj, + PyBytes_AS_STRING(b->buf), b->string_size, 0, flags); if (ret >= 0) { b->exports++; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 10:55:27 2015 From: python-checkins at python.org (berker.peksag) Date: Tue, 03 Feb 2015 09:55:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzU4?= =?utf-8?q?=3A_Add_missing_BaseServer_entry_to_socketserver=2E=5F=5Fall=5F?= =?utf-8?b?Xy4=?= Message-ID: <20150203095525.39294.46495@psf.io> https://hg.python.org/cpython/rev/e614ff664877 changeset: 94484:e614ff664877 branch: 3.4 parent: 94480:e62d54128bd3 user: Berker Peksag date: Tue Feb 03 11:55:09 2015 +0200 summary: Issue #23358: Add missing BaseServer entry to socketserver.__all__. Patch by Martin Panter. files: Lib/socketserver.py | 8 ++++---- Lib/test/test_socketserver.py | 19 ++++++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Lib/socketserver.py b/Lib/socketserver.py --- a/Lib/socketserver.py +++ b/Lib/socketserver.py @@ -138,10 +138,10 @@ except ImportError: import dummy_threading as threading -__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", - "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler", - "StreamRequestHandler","DatagramRequestHandler", - "ThreadingMixIn", "ForkingMixIn"] +__all__ = ["BaseServer", "TCPServer", "UDPServer", "ForkingUDPServer", + "ForkingTCPServer", "ThreadingUDPServer", "ThreadingTCPServer", + "BaseRequestHandler", "StreamRequestHandler", + "DatagramRequestHandler", "ThreadingMixIn", "ForkingMixIn"] if hasattr(socket, "AF_UNIX"): __all__.extend(["UnixStreamServer","UnixDatagramServer", "ThreadingUnixStreamServer", diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -2,7 +2,6 @@ Test suite for socketserver. """ -import _imp as imp import contextlib import os import select @@ -313,12 +312,18 @@ socketserver.StreamRequestHandler) -def test_main(): - if imp.lock_held(): - # If the import lock is held, the threads will hang - raise unittest.SkipTest("can't run when import lock is held") +class MiscTestCase(unittest.TestCase): - test.support.run_unittest(SocketServerTest) + def test_all(self): + # objects defined in the module should be in __all__ + expected = [] + for name in dir(socketserver): + if not name.startswith('_'): + mod_object = getattr(socketserver, name) + if getattr(mod_object, '__module__', None) == 'socketserver': + expected.append(name) + self.assertCountEqual(socketserver.__all__, expected) + if __name__ == "__main__": - test_main() + unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 10:55:27 2015 From: python-checkins at python.org (berker.peksag) Date: Tue, 03 Feb 2015 09:55:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323358=3A_Add_missing_BaseServer_entry_to_socket?= =?utf-8?b?c2VydmVyLl9fYWxsX18u?= Message-ID: <20150203095525.106346.89159@psf.io> https://hg.python.org/cpython/rev/80d282505d21 changeset: 94485:80d282505d21 parent: 94483:2e29d54843a4 parent: 94484:e614ff664877 user: Berker Peksag date: Tue Feb 03 11:55:32 2015 +0200 summary: Issue #23358: Add missing BaseServer entry to socketserver.__all__. Patch by Martin Panter. files: Lib/socketserver.py | 8 ++++---- Lib/test/test_socketserver.py | 19 ++++++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Lib/socketserver.py b/Lib/socketserver.py --- a/Lib/socketserver.py +++ b/Lib/socketserver.py @@ -138,10 +138,10 @@ import dummy_threading as threading from time import monotonic as time -__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", - "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler", - "StreamRequestHandler","DatagramRequestHandler", - "ThreadingMixIn", "ForkingMixIn"] +__all__ = ["BaseServer", "TCPServer", "UDPServer", "ForkingUDPServer", + "ForkingTCPServer", "ThreadingUDPServer", "ThreadingTCPServer", + "BaseRequestHandler", "StreamRequestHandler", + "DatagramRequestHandler", "ThreadingMixIn", "ForkingMixIn"] if hasattr(socket, "AF_UNIX"): __all__.extend(["UnixStreamServer","UnixDatagramServer", "ThreadingUnixStreamServer", diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -2,7 +2,6 @@ Test suite for socketserver. """ -import _imp as imp import contextlib import os import select @@ -281,12 +280,18 @@ socketserver.StreamRequestHandler) -def test_main(): - if imp.lock_held(): - # If the import lock is held, the threads will hang - raise unittest.SkipTest("can't run when import lock is held") +class MiscTestCase(unittest.TestCase): - test.support.run_unittest(SocketServerTest) + def test_all(self): + # objects defined in the module should be in __all__ + expected = [] + for name in dir(socketserver): + if not name.startswith('_'): + mod_object = getattr(socketserver, name) + if getattr(mod_object, '__module__', None) == 'socketserver': + expected.append(name) + self.assertCountEqual(socketserver.__all__, expected) + if __name__ == "__main__": - test_main() + unittest.main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 11:22:04 2015 From: python-checkins at python.org (berker.peksag) Date: Tue, 03 Feb 2015 10:22:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2313128=3A_Print_re?= =?utf-8?q?sponse_headers_for_CONNECT_requests_when_debuglevel_=3E_0=2E?= Message-ID: <20150203102203.106325.68325@psf.io> https://hg.python.org/cpython/rev/dfbd07cdc031 changeset: 94486:dfbd07cdc031 user: Berker Peksag date: Tue Feb 03 12:22:11 2015 +0200 summary: Issue #13128: Print response headers for CONNECT requests when debuglevel > 0. Patch by Demian Brecht. files: Lib/http/client.py | 3 +++ Lib/test/test_httplib.py | 23 ++++++++++++++++++----- Misc/NEWS | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -776,6 +776,9 @@ if line in (b'\r\n', b'\n', b''): break + if self.debuglevel > 0: + print('header:', line.decode()) + def connect(self): """Connect to the host and port specified in __init__.""" self.sock = self._create_connection( diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1269,17 +1269,18 @@ 'HTTP/1.1 200 OK\r\n' # Reply to HEAD 'Content-Length: 42\r\n\r\n' ) - - def create_connection(address, timeout=None, source_address=None): - return FakeSocket(response_text, host=address[0], port=address[1]) - self.host = 'proxy.com' self.conn = client.HTTPConnection(self.host) - self.conn._create_connection = create_connection + self.conn._create_connection = self._create_connection(response_text) def tearDown(self): self.conn.close() + def _create_connection(self, response_text): + def create_connection(address, timeout=None, source_address=None): + return FakeSocket(response_text, host=address[0], port=address[1]) + return create_connection + def test_set_tunnel_host_port_headers(self): tunnel_host = 'destination.com' tunnel_port = 8888 @@ -1320,6 +1321,18 @@ self.assertIn(b'CONNECT destination.com', self.conn.sock.data) self.assertIn(b'Host: destination.com', self.conn.sock.data) + def test_tunnel_debuglog(self): + expected_header = 'X-Dummy: 1' + response_text = 'HTTP/1.0 200 OK\r\n{}\r\n\r\n'.format(expected_header) + + self.conn.set_debuglevel(1) + self.conn._create_connection = self._create_connection(response_text) + self.conn.set_tunnel('destination.com') + + with support.captured_stdout() as output: + self.conn.request('PUT', '/', '') + lines = output.getvalue().splitlines() + self.assertIn('header: {}'.format(expected_header), lines) @support.reap_threads diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -232,6 +232,9 @@ Library ------- +- Issue #13128: Print response headers for CONNECT requests when debuglevel + > 0. Patch by Demian Brecht. + - Issue #15381: Optimized io.BytesIO to make less allocations and copyings. - Issue #22818: Splitting on a pattern that could match an empty string now -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 13:58:47 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 12:58:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315381=3A_Try_to_f?= =?utf-8?q?ix_refcount_bug=2E_Empty_and_1-byte_buffers_are_always?= Message-ID: <20150203125839.39298.2829@psf.io> https://hg.python.org/cpython/rev/3fdbdf4d2ac7 changeset: 94487:3fdbdf4d2ac7 user: Serhiy Storchaka date: Tue Feb 03 14:57:49 2015 +0200 summary: Issue #15381: Try to fix refcount bug. Empty and 1-byte buffers are always shared. files: Modules/_io/bytesio.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -38,7 +38,8 @@ return NULL; \ } -#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1) +#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1 || \ + PyBytes_GET_SIZE((self)->buf) <= 1) /* Internal routine to get a line from the buffer of a BytesIO @@ -308,6 +309,7 @@ char *output; assert(self->buf != NULL); + assert(size <= self->string_size); if (size > 1 && self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && self->exports == 0) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 15:13:55 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 Feb 2015 14:13:55 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbywgVHVs?= =?utf-8?q?ip_issue_221=3A_Fix_doc_of_QueueEmpty_and_QueueFull?= Message-ID: <20150203141351.34400.63641@psf.io> https://hg.python.org/cpython/rev/fd445d2dd107 changeset: 94488:fd445d2dd107 branch: 3.4 parent: 94484:e614ff664877 user: Victor Stinner date: Tue Feb 03 15:09:24 2015 +0100 summary: asyncio, Tulip issue 221: Fix doc of QueueEmpty and QueueFull files: Doc/library/asyncio-sync.rst | 10 ++++------ Lib/asyncio/queues.py | 8 ++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -428,13 +428,11 @@ .. exception:: QueueEmpty - Exception raised when non-blocking :meth:`~Queue.get` (or - :meth:`~Queue.get_nowait`) is called - on a :class:`Queue` object which is empty. + Exception raised when the :meth:`~Queue.get_nowait` method is called on a + :class:`Queue` object which is empty. .. exception:: QueueFull - Exception raised when non-blocking :meth:`~Queue.put` (or - :meth:`~Queue.put_nowait`) is called - on a :class:`Queue` object which is full. + Exception raised when the :meth:`~Queue.put_nowait` method is called on a + :class:`Queue` object which is full. diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -13,12 +13,16 @@ class QueueEmpty(Exception): - 'Exception raised by Queue.get(block=0)/get_nowait().' + """Exception raised when Queue.get_nowait() is called on a Queue object + which is empty. + """ pass class QueueFull(Exception): - 'Exception raised by Queue.put(block=0)/put_nowait().' + """Exception raised when the Queue.put_nowait() method is called on a Queue + object which is full. + """ pass -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 15:13:55 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 03 Feb 2015 14:13:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio_doc=29?= Message-ID: <20150203141351.25855.56305@psf.io> https://hg.python.org/cpython/rev/7494f3972726 changeset: 94489:7494f3972726 parent: 94487:3fdbdf4d2ac7 parent: 94488:fd445d2dd107 user: Victor Stinner date: Tue Feb 03 15:12:13 2015 +0100 summary: Merge 3.4 (asyncio doc) files: Doc/library/asyncio-sync.rst | 10 ++++------ Lib/asyncio/queues.py | 8 ++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -428,13 +428,11 @@ .. exception:: QueueEmpty - Exception raised when non-blocking :meth:`~Queue.get` (or - :meth:`~Queue.get_nowait`) is called - on a :class:`Queue` object which is empty. + Exception raised when the :meth:`~Queue.get_nowait` method is called on a + :class:`Queue` object which is empty. .. exception:: QueueFull - Exception raised when non-blocking :meth:`~Queue.put` (or - :meth:`~Queue.put_nowait`) is called - on a :class:`Queue` object which is full. + Exception raised when the :meth:`~Queue.put_nowait` method is called on a + :class:`Queue` object which is full. diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -13,12 +13,16 @@ class QueueEmpty(Exception): - 'Exception raised by Queue.get(block=0)/get_nowait().' + """Exception raised when Queue.get_nowait() is called on a Queue object + which is empty. + """ pass class QueueFull(Exception): - 'Exception raised by Queue.put(block=0)/put_nowait().' + """Exception raised when the Queue.put_nowait() method is called on a Queue + object which is full. + """ pass -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 16:57:57 2015 From: python-checkins at python.org (stefan.krah) Date: Tue, 03 Feb 2015 15:57:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314203=3A_Remove_o?= =?utf-8?q?bsolete_support_for_view=3D=3DNULL_in_PyBuffer=5FFillInfo=28=29?= Message-ID: <20150203155754.39296.26507@psf.io> https://hg.python.org/cpython/rev/e8fe32d43c96 changeset: 94490:e8fe32d43c96 user: Stefan Krah date: Tue Feb 03 16:57:21 2015 +0100 summary: Issue #14203: Remove obsolete support for view==NULL in PyBuffer_FillInfo() and bytearray_getbuffer(). Both functions now raise BufferError in that case. files: Misc/NEWS | 4 +++ Modules/_testcapimodule.c | 34 +++++++++++++++++++++++++++ Objects/abstract.c | 7 ++++- Objects/bytearrayobject.c | 15 +++++------ 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1560,6 +1560,10 @@ C API ----- +- Issue #14203: Remove obsolete support for view==NULL in PyBuffer_FillInfo() + and bytearray_getbuffer(). Both functions now raise BufferError in that + case. + - Issue #22445: PyBuffer_IsContiguous() now implements precise contiguity tests, compatible with NumPy's NPY_RELAXED_STRIDES_CHECKING compilation flag. Previously the function reported false negatives for corner cases. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2518,6 +2518,39 @@ Py_RETURN_NONE; } + +static PyObject * +test_pep3118_obsolete_write_locks(PyObject* self, PyObject *noargs) +{ + PyObject *b; + char *dummy[1]; + int ret, match; + + ret = PyBuffer_FillInfo(NULL, NULL, dummy, 1, 0, PyBUF_SIMPLE); + match = PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_BufferError); + PyErr_Clear(); + if (ret != -1 || match == 0) + goto error; + + b = PyByteArray_FromStringAndSize("", 0); + if (b == NULL) { + return NULL; + } + + ret = PyObject_GetBuffer(b, NULL, PyBUF_SIMPLE); + Py_DECREF(b); + match = PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_BufferError); + PyErr_Clear(); + if (ret != -1 || match == 0) + goto error; + + Py_RETURN_NONE; + +error: + PyErr_SetString(TestError, + "test_pep3118_obsolete_write_locks: failure"); + return NULL; +} /* Test that the fatal error from not having a current thread doesn't cause an infinite loop. Run via Lib/test/test_capi.py */ @@ -3179,6 +3212,7 @@ {"test_unicode_compare_with_ascii", (PyCFunction)test_unicode_compare_with_ascii, METH_NOARGS}, {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, + {"test_pep3118_obsolete_write_locks", (PyCFunction)test_pep3118_obsolete_write_locks, METH_NOARGS}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, METH_VARARGS|METH_KEYWORDS}, diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -612,7 +612,12 @@ PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, int readonly, int flags) { - if (view == NULL) return 0; /* XXX why not -1? */ + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "PyBuffer_FillInfo: view==NULL argument is obsolete"); + return -1; + } + if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && (readonly == 1)) { PyErr_SetString(PyExc_BufferError, diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -60,18 +60,17 @@ static int bytearray_getbuffer(PyByteArrayObject *obj, Py_buffer *view, int flags) { - int ret; void *ptr; if (view == NULL) { - obj->ob_exports++; - return 0; + PyErr_SetString(PyExc_BufferError, + "bytearray_getbuffer: view==NULL argument is obsolete"); + return -1; } ptr = (void *) PyByteArray_AS_STRING(obj); - ret = PyBuffer_FillInfo(view, (PyObject*)obj, ptr, Py_SIZE(obj), 0, flags); - if (ret >= 0) { - obj->ob_exports++; - } - return ret; + /* cannot fail if view != NULL and readonly == 0 */ + (void)PyBuffer_FillInfo(view, (PyObject*)obj, ptr, Py_SIZE(obj), 0, flags); + obj->ob_exports++; + return 0; } static void -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 17:15:53 2015 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 03 Feb 2015 16:15:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_23359=3A__Reduce_siz?= =?utf-8?q?e_of_code_in_set=5Flookkey=2E_Only_do_linear_probes_when?= Message-ID: <20150203161548.96088.40866@psf.io> https://hg.python.org/cpython/rev/17cda5a92b6a changeset: 94491:17cda5a92b6a user: Raymond Hettinger date: Tue Feb 03 08:15:30 2015 -0800 summary: Issue 23359: Reduce size of code in set_lookkey. Only do linear probes when there is no wrap-around. Nice simplification contributed by Serhiy Storchaka :-) files: Objects/setobject.c | 33 --------------------------------- 1 files changed, 0 insertions(+), 33 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -115,33 +115,6 @@ if (entry->key == dummy && freeslot == NULL) freeslot = entry; } - } else { - for (j = 1 ; j <= LINEAR_PROBES ; j++) { - entry = &table[(i + j) & mask]; - if (entry->key == NULL) - goto found_null; - if (entry->hash == hash) { - PyObject *startkey = entry->key; - assert(startkey != dummy); - if (startkey == key) - return entry; - if (PyUnicode_CheckExact(startkey) - && PyUnicode_CheckExact(key) - && unicode_eq(startkey, key)) - return entry; - Py_INCREF(startkey); - cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); - Py_DECREF(startkey); - if (cmp < 0) - return NULL; - if (table != so->table || entry->key != startkey) - return set_lookkey(so, key, hash); - if (cmp > 0) - return entry; - } - if (entry->key == dummy && freeslot == NULL) - freeslot = entry; - } } perturb >>= PERTURB_SHIFT; @@ -183,12 +156,6 @@ if (entry->key == NULL) goto found_null; } - } else { - for (j = 1; j <= LINEAR_PROBES; j++) { - entry = &table[(i + j) & mask]; - if (entry->key == NULL) - goto found_null; - } } perturb >>= PERTURB_SHIFT; i = (i * 5 + 1 + perturb) & mask; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 17:53:35 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 03 Feb 2015 16:53:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315381=3A_Fixed_a_?= =?utf-8?q?bug_in_BytesIO=2Ewrite=28=29=2E?= Message-ID: <20150203165256.39276.88303@psf.io> https://hg.python.org/cpython/rev/ea33b61cac74 changeset: 94492:ea33b61cac74 user: Serhiy Storchaka date: Tue Feb 03 18:51:58 2015 +0200 summary: Issue #15381: Fixed a bug in BytesIO.write(). It was expected that string_size == PyBytes_GET_SIZE(buf) if the buffer is shared, but truncate() and __setstate__() can set string_size without unsharing the buffer. files: Modules/_io/bytesio.c | 19 ++++++++++--------- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -19,7 +19,7 @@ /* The bytesio object can be in three states: * Py_REFCNT(buf) == 1, exports == 0. - * Py_REFCNT(buf) > 1. exports == 0, string_size == PyBytes_GET_SIZE(buf), + * Py_REFCNT(buf) > 1. exports == 0, first modification or export causes the internal buffer copying. * exports > 0. Py_REFCNT(buf) == 1, any modifications are forbidden. */ @@ -38,8 +38,7 @@ return NULL; \ } -#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1 || \ - PyBytes_GET_SIZE((self)->buf) <= 1) +#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1) /* Internal routine to get a line from the buffer of a BytesIO @@ -152,16 +151,18 @@ static Py_ssize_t write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) { + size_t endpos; assert(self->buf != NULL); assert(self->pos >= 0); assert(len >= 0); - if ((size_t)self->pos + len > (size_t)PyBytes_GET_SIZE(self->buf)) { - if (resize_buffer(self, (size_t)self->pos + len) < 0) + endpos = (size_t)self->pos + len; + if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) { + if (resize_buffer(self, endpos) < 0) return -1; } else if (SHARED_BUF(self)) { - if (unshare_buffer(self, self->string_size) < 0) + if (unshare_buffer(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) return -1; } @@ -181,11 +182,11 @@ /* Copy the data to the internal buffer, overwriting some of the existing data if self->pos < self->string_size. */ memcpy(PyBytes_AS_STRING(self->buf) + self->pos, bytes, len); - self->pos += len; + self->pos = endpos; /* Set the new length of the internal string if it has changed. */ - if (self->string_size < self->pos) { - self->string_size = self->pos; + if ((size_t)self->string_size < endpos) { + self->string_size = endpos; } return len; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 21:43:53 2015 From: python-checkins at python.org (stefan.krah) Date: Tue, 03 Feb 2015 20:43:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314203=3A_Remove_o?= =?utf-8?q?bsolete_support_for_view=3D=3DNULL_in_bytesiobuf=5Fgetbuffer=28?= =?utf-8?q?=29?= Message-ID: <20150203204350.34384.84889@psf.io> https://hg.python.org/cpython/rev/0d5095a2422f changeset: 94493:0d5095a2422f user: Stefan Krah date: Tue Feb 03 21:43:23 2015 +0100 summary: Issue #14203: Remove obsolete support for view==NULL in bytesiobuf_getbuffer() and array_buffer_getbuf(). files: Lib/test/test_array.py | 5 +++++ Lib/test/test_bytes.py | 4 ++++ Misc/NEWS | 6 +++--- Modules/_io/bytesio.c | 21 +++++++++++---------- Modules/_testcapimodule.c | 22 ++++++++++++++++++++-- Modules/arraymodule.c | 7 +++++-- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1041,6 +1041,11 @@ a = array.array(self.typecode, "foo") a = array.array(self.typecode, array.array('u', 'foo')) + @support.cpython_only + def test_obsolete_write_lock(self): + from _testcapi import getbuffer_with_null_view + a = array.array('B', b"") + self.assertRaises(BufferError, getbuffer_with_null_view, a) class StringTest(BaseTest): diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1224,6 +1224,10 @@ self.assertRaises(BufferError, delslice) self.assertEqual(b, orig) + @test.support.cpython_only + def test_obsolete_write_lock(self): + from _testcapi import getbuffer_with_null_view + self.assertRaises(BufferError, getbuffer_with_null_view, bytearray()) class AssortedBytesTest(unittest.TestCase): # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1560,9 +1560,9 @@ C API ----- -- Issue #14203: Remove obsolete support for view==NULL in PyBuffer_FillInfo() - and bytearray_getbuffer(). Both functions now raise BufferError in that - case. +- Issue #14203: Remove obsolete support for view==NULL in PyBuffer_FillInfo(), + bytearray_getbuffer(), bytesiobuf_getbuffer() and array_buffer_getbuf(). + All functions now raise BufferError in that case. - Issue #22445: PyBuffer_IsContiguous() now implements precise contiguity tests, compatible with NumPy's NPY_RELAXED_STRIDES_CHECKING compilation diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1028,23 +1028,24 @@ static int bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags) { - int ret; bytesio *b = (bytesio *) obj->source; + + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "bytesiobuf_getbuffer: view==NULL argument is obsolete"); + return -1; + } if (SHARED_BUF(b)) { if (unshare_buffer(b, b->string_size) < 0) return -1; } - if (view == NULL) { - b->exports++; - return 0; - } - ret = PyBuffer_FillInfo(view, (PyObject*)obj, + + /* cannot fail if view != NULL and readonly == 0 */ + (void)PyBuffer_FillInfo(view, (PyObject*)obj, PyBytes_AS_STRING(b->buf), b->string_size, 0, flags); - if (ret >= 0) { - b->exports++; - } - return ret; + b->exports++; + return 0; } static void diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2518,21 +2518,26 @@ Py_RETURN_NONE; } - + +extern PyTypeObject _PyBytesIOBuffer_Type; + static PyObject * test_pep3118_obsolete_write_locks(PyObject* self, PyObject *noargs) { + PyTypeObject *type = &_PyBytesIOBuffer_Type; PyObject *b; char *dummy[1]; int ret, match; + /* PyBuffer_FillInfo() */ ret = PyBuffer_FillInfo(NULL, NULL, dummy, 1, 0, PyBUF_SIMPLE); match = PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_BufferError); PyErr_Clear(); if (ret != -1 || match == 0) goto error; - b = PyByteArray_FromStringAndSize("", 0); + /* bytesiobuf_getbuffer() */ + b = type->tp_alloc(type, 0); if (b == NULL) { return NULL; } @@ -2552,6 +2557,18 @@ return NULL; } +/* This tests functions that historically supported write locks. It is + wrong to call getbuffer() with view==NULL and a compliant getbufferproc + is entitled to segfault in that case. */ +static PyObject * +getbuffer_with_null_view(PyObject* self, PyObject *obj) +{ + if (PyObject_GetBuffer(obj, NULL, PyBUF_SIMPLE) < 0) + return NULL; + + Py_RETURN_NONE; +} + /* Test that the fatal error from not having a current thread doesn't cause an infinite loop. Run via Lib/test/test_capi.py */ static PyObject * @@ -3213,6 +3230,7 @@ {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, {"test_pep3118_obsolete_write_locks", (PyCFunction)test_pep3118_obsolete_write_locks, METH_NOARGS}, + {"getbuffer_with_null_view", getbuffer_with_null_view, METH_O}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, METH_VARARGS|METH_KEYWORDS}, diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2530,7 +2530,11 @@ static int array_buffer_getbuf(arrayobject *self, Py_buffer *view, int flags) { - if (view==NULL) goto finish; + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "array_buffer_getbuf: view==NULL argument is obsolete"); + return -1; + } view->buf = (void *)self->ob_item; view->obj = (PyObject*)self; @@ -2560,7 +2564,6 @@ #endif } - finish: self->ob_exports++; return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 3 22:27:50 2015 From: python-checkins at python.org (stefan.krah) Date: Tue, 03 Feb 2015 21:27:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314203=3A__Tempora?= =?utf-8?q?ry_fix_for_the_compile_failure_on_Windows=2E?= Message-ID: <20150203212749.96076.79334@psf.io> https://hg.python.org/cpython/rev/17a8c5f8ca48 changeset: 94494:17a8c5f8ca48 user: Stefan Krah date: Tue Feb 03 22:27:21 2015 +0100 summary: Issue #14203: Temporary fix for the compile failure on Windows. files: Modules/_testcapimodule.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2519,6 +2519,7 @@ Py_RETURN_NONE; } +#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__GNUC__) extern PyTypeObject _PyBytesIOBuffer_Type; static PyObject * @@ -2556,6 +2557,7 @@ "test_pep3118_obsolete_write_locks: failure"); return NULL; } +#endif /* This tests functions that historically supported write locks. It is wrong to call getbuffer() with view==NULL and a compliant getbufferproc @@ -3229,7 +3231,9 @@ {"test_unicode_compare_with_ascii", (PyCFunction)test_unicode_compare_with_ascii, METH_NOARGS}, {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, +#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__GNUC__) {"test_pep3118_obsolete_write_locks", (PyCFunction)test_pep3118_obsolete_write_locks, METH_NOARGS}, +#endif {"getbuffer_with_null_view", getbuffer_with_null_view, METH_O}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 07:09:38 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 04 Feb 2015 06:09:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWVzICMyMzM2?= =?utf-8?q?3=2C_=2323364=2C_=2323365=2C_=2323366=3A_Fixed_itertools_overfl?= =?utf-8?q?ow_tests=2E?= Message-ID: <20150204060935.25871.27595@psf.io> https://hg.python.org/cpython/rev/887526ebb013 changeset: 94495:887526ebb013 branch: 2.7 parent: 94466:83b75b016c77 user: Serhiy Storchaka date: Tue Feb 03 01:34:09 2015 +0200 summary: Issues #23363, #23364, #23365, #23366: Fixed itertools overflow tests. Used PyMem_New to check overflow. files: Lib/test/test_itertools.py | 12 +++++------- Modules/itertoolsmodule.c | 26 ++++++-------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -139,7 +139,7 @@ @test_support.bigaddrspacetest def test_combinations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations("AA", 2**29) @test_support.impl_detail("tuple reuse is specific to CPython") @@ -215,7 +215,7 @@ @test_support.bigaddrspacetest def test_combinations_with_replacement_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): combinations_with_replacement("AA", 2**30) @test_support.impl_detail("tuple reuse is specific to CPython") @@ -286,10 +286,8 @@ @test_support.bigaddrspacetest def test_permutations_overflow(self): - with self.assertRaises(OverflowError): + with self.assertRaises((OverflowError, MemoryError)): permutations("A", 2**30) - with self.assertRaises(OverflowError): - permutations("A", 2, 2**30) @test_support.impl_detail("tuple reuse is specific to CPython") def test_permutations_tuple_reuse(self): @@ -711,8 +709,8 @@ @test_support.bigaddrspacetest def test_product_overflow(self): - with self.assertRaises(OverflowError): - product(["a"]*(2**16), repeat=2**16) + with self.assertRaises((OverflowError, MemoryError)): + product(*(['ab']*2**5), repeat=2**25) @test_support.impl_detail("tuple reuse is specific to CPython") def test_product_tuple_reuse(self): diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1847,15 +1847,14 @@ nargs = 0; } else { nargs = PyTuple_GET_SIZE(args); - if (repeat > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - nargs > PY_SSIZE_T_MAX/(repeat * sizeof(Py_ssize_t))) { + if ((size_t)nargs > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)/repeat) { PyErr_SetString(PyExc_OverflowError, "repeat argument too large"); return NULL; } } npools = nargs * repeat; - indices = PyMem_Malloc(npools * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, npools); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2102,11 +2101,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2355,11 +2350,7 @@ goto error; } - if (r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "r is too big"); - goto error; - } - indices = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, r); if (indices == NULL) { PyErr_NoMemory(); goto error; @@ -2612,13 +2603,8 @@ goto error; } - if (n > PY_SSIZE_T_MAX/sizeof(Py_ssize_t) || - r > PY_SSIZE_T_MAX/sizeof(Py_ssize_t)) { - PyErr_SetString(PyExc_OverflowError, "parameters too large"); - goto error; - } - indices = PyMem_Malloc(n * sizeof(Py_ssize_t)); - cycles = PyMem_Malloc(r * sizeof(Py_ssize_t)); + indices = PyMem_New(Py_ssize_t, n); + cycles = PyMem_New(Py_ssize_t, r); if (indices == NULL || cycles == NULL) { PyErr_NoMemory(); goto error; -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Wed Feb 4 09:33:48 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 04 Feb 2015 09:33:48 +0100 Subject: [Python-checkins] Daily reference leaks (17a8c5f8ca48): sum=3 Message-ID: results for 17a8c5f8ca48 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogzoUP3t', '-x'] From python-checkins at python.org Wed Feb 4 10:04:50 2015 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 04 Feb 2015 09:04:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Skip_some_tests_that_require_a_subinterpreter_launched_w?= =?utf-8?q?ith_-E_or_-I_when_the?= Message-ID: <20150204090446.106325.46588@psf.io> https://hg.python.org/cpython/rev/0bd76ade1c7f changeset: 94497:0bd76ade1c7f parent: 94494:17a8c5f8ca48 parent: 94496:ef1d338bec8f user: Gregory P. Smith date: Wed Feb 04 01:04:31 2015 -0800 summary: Skip some tests that require a subinterpreter launched with -E or -I when the interpreter under test is being run in an environment that requires the use of environment variables such as PYTHONHOME in order to function at all. Adds a test.script_helper.interpreter_requires_environment() function to be used with @unittest.skipIf on stdlib test methods requiring this. files: Lib/test/script_helper.py | 35 ++++++++++++++++++ Lib/test/test_cmd_line.py | 4 +- Lib/test/test_script_helper.py | 41 ++++++++++++++++++++++ Lib/test/test_tracemalloc.py | 4 +- 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -15,6 +15,41 @@ from importlib.util import source_from_cache from test.support import make_legacy_pyc, strip_python_stderr, temp_dir + +# Cached result of the expensive test performed in the function below. +__cached_interp_requires_environment = None + +def interpreter_requires_environment(): + """ + Returns True if our sys.executable interpreter requires environment + variables in order to be able to run at all. + + This is designed to be used with @unittest.skipIf() to annotate tests + that need to use an assert_python*() function to launch an isolated + mode (-I) or no environment mode (-E) sub-interpreter process. + + A normal build & test does not run into this situation but it can happen + when trying to run the standard library test suite from an interpreter that + doesn't have an obvious home with Python's current home finding logic. + + Setting PYTHONHOME is one way to get most of the testsuite to run in that + situation. PYTHONPATH or PYTHONUSERSITE are other common envirnonment + variables that might impact whether or not the interpreter can start. + """ + global __cached_interp_requires_environment + if __cached_interp_requires_environment is None: + # Try running an interpreter with -E to see if it works or not. + try: + subprocess.check_call([sys.executable, '-E', + '-c', 'import sys; sys.exit(0)']) + except subprocess.CalledProcessError: + __cached_interp_requires_environment = True + else: + __cached_interp_requires_environment = False + + return __cached_interp_requires_environment + + # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): if '__isolated' in env_vars: diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -8,6 +8,7 @@ import sys import subprocess import tempfile +from test import script_helper from test.script_helper import (spawn_python, kill_python, assert_python_ok, assert_python_failure) @@ -439,7 +440,8 @@ self.assertEqual(err.splitlines().count(b'Unknown option: -a'), 1) self.assertEqual(b'', out) - + @unittest.skipIf(script_helper.interpreter_requires_environment(), + 'Cannot run -I tests when PYTHON env vars are required.') def test_isolatedmode(self): self.verify_valid_flag('-I') self.verify_valid_flag('-IEs') diff --git a/Lib/test/test_script_helper.py b/Lib/test/test_script_helper.py --- a/Lib/test/test_script_helper.py +++ b/Lib/test/test_script_helper.py @@ -1,7 +1,10 @@ """Unittests for test.script_helper. Who tests the test helper?""" +import subprocess +import sys from test import script_helper import unittest +from unittest import mock class TestScriptHelper(unittest.TestCase): @@ -31,5 +34,43 @@ msg='unexpected command line.') +class TestScriptHelperEnvironment(unittest.TestCase): + """Code coverage for interpreter_requires_environment().""" + + def setUp(self): + self.assertTrue( + hasattr(script_helper, '__cached_interp_requires_environment')) + # Reset the private cached state. + script_helper.__dict__['__cached_interp_requires_environment'] = None + + def tearDown(self): + # Reset the private cached state. + script_helper.__dict__['__cached_interp_requires_environment'] = None + + @mock.patch('subprocess.check_call') + def test_interpreter_requires_environment_true(self, mock_check_call): + mock_check_call.side_effect = subprocess.CalledProcessError('', '') + self.assertTrue(script_helper.interpreter_requires_environment()) + self.assertTrue(script_helper.interpreter_requires_environment()) + self.assertEqual(1, mock_check_call.call_count) + + @mock.patch('subprocess.check_call') + def test_interpreter_requires_environment_false(self, mock_check_call): + # The mocked subprocess.check_call fakes a no-error process. + script_helper.interpreter_requires_environment() + self.assertFalse(script_helper.interpreter_requires_environment()) + self.assertEqual(1, mock_check_call.call_count) + + @mock.patch('subprocess.check_call') + def test_interpreter_requires_environment_details(self, mock_check_call): + script_helper.interpreter_requires_environment() + self.assertFalse(script_helper.interpreter_requires_environment()) + self.assertFalse(script_helper.interpreter_requires_environment()) + self.assertEqual(1, mock_check_call.call_count) + check_call_command = mock_check_call.call_args[0][0] + self.assertEqual(sys.executable, check_call_command[0]) + self.assertIn('-E', check_call_command) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -5,7 +5,7 @@ import unittest from unittest.mock import patch from test.script_helper import assert_python_ok, assert_python_failure -from test import support +from test import script_helper, support try: import threading except ImportError: @@ -755,6 +755,8 @@ stdout = stdout.rstrip() self.assertEqual(stdout, b'False') + @unittest.skipIf(script_helper.interpreter_requires_environment(), + 'Cannot run -E tests when PYTHON env vars are required.') def test_env_var_ignored_with_E(self): """PYTHON* environment variables must be ignored when -E is present.""" code = 'import tracemalloc; print(tracemalloc.is_tracing())' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 10:04:50 2015 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 04 Feb 2015 09:04:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Skip_some_test?= =?utf-8?q?s_that_require_a_subinterpreter_launched_with_-E_or_-I_when_the?= Message-ID: <20150204090446.25871.12134@psf.io> https://hg.python.org/cpython/rev/ef1d338bec8f changeset: 94496:ef1d338bec8f branch: 3.4 parent: 94488:fd445d2dd107 user: Gregory P. Smith date: Wed Feb 04 00:59:40 2015 -0800 summary: Skip some tests that require a subinterpreter launched with -E or -I when the interpreter under test is being run in an environment that requires the use of environment variables such as PYTHONHOME in order to function at all. Adds a private test.script_helper._interpreter_requires_environment() function to be used with @unittest.skipIf on stdlib test methods requiring this. files: Lib/test/script_helper.py | 35 ++++++++++++++++++ Lib/test/test_cmd_line.py | 4 +- Lib/test/test_script_helper.py | 41 ++++++++++++++++++++++ Lib/test/test_tracemalloc.py | 4 +- 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -15,6 +15,41 @@ from importlib.util import source_from_cache from test.support import make_legacy_pyc, strip_python_stderr, temp_dir + +# Cached result of the expensive test performed in the function below. +__cached_interp_requires_environment = None + +def _interpreter_requires_environment(): + """ + Returns True if our sys.executable interpreter requires environment + variables in order to be able to run at all. + + This is designed to be used with @unittest.skipIf() to annotate tests + that need to use an assert_python*() function to launch an isolated + mode (-I) or no environment mode (-E) sub-interpreter process. + + A normal build & test does not run into this situation but it can happen + when trying to run the standard library test suite from an interpreter that + doesn't have an obvious home with Python's current home finding logic. + + Setting PYTHONHOME is one way to get most of the testsuite to run in that + situation. PYTHONPATH or PYTHONUSERSITE are other common envirnonment + variables that might impact whether or not the interpreter can start. + """ + global __cached_interp_requires_environment + if __cached_interp_requires_environment is None: + # Try running an interpreter with -E to see if it works or not. + try: + subprocess.check_call([sys.executable, '-E', + '-c', 'import sys; sys.exit(0)']) + except subprocess.CalledProcessError: + __cached_interp_requires_environment = True + else: + __cached_interp_requires_environment = False + + return __cached_interp_requires_environment + + # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): if '__isolated' in env_vars: diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -8,6 +8,7 @@ import sys import subprocess import tempfile +from test import script_helper from test.script_helper import (spawn_python, kill_python, assert_python_ok, assert_python_failure) @@ -439,7 +440,8 @@ self.assertEqual(err.splitlines().count(b'Unknown option: -a'), 1) self.assertEqual(b'', out) - + @unittest.skipIf(script_helper._interpreter_requires_environment(), + 'Cannot run -I tests when PYTHON env vars are required.') def test_isolatedmode(self): self.verify_valid_flag('-I') self.verify_valid_flag('-IEs') diff --git a/Lib/test/test_script_helper.py b/Lib/test/test_script_helper.py --- a/Lib/test/test_script_helper.py +++ b/Lib/test/test_script_helper.py @@ -1,7 +1,10 @@ """Unittests for test.script_helper. Who tests the test helper?""" +import subprocess +import sys from test import script_helper import unittest +from unittest import mock class TestScriptHelper(unittest.TestCase): @@ -31,5 +34,43 @@ msg='unexpected command line.') +class TestScriptHelperEnvironment(unittest.TestCase): + """Code coverage for _interpreter_requires_environment().""" + + def setUp(self): + self.assertTrue( + hasattr(script_helper, '__cached_interp_requires_environment')) + # Reset the private cached state. + script_helper.__dict__['__cached_interp_requires_environment'] = None + + def tearDown(self): + # Reset the private cached state. + script_helper.__dict__['__cached_interp_requires_environment'] = None + + @mock.patch('subprocess.check_call') + def test_interpreter_requires_environment_true(self, mock_check_call): + mock_check_call.side_effect = subprocess.CalledProcessError('', '') + self.assertTrue(script_helper._interpreter_requires_environment()) + self.assertTrue(script_helper._interpreter_requires_environment()) + self.assertEqual(1, mock_check_call.call_count) + + @mock.patch('subprocess.check_call') + def test_interpreter_requires_environment_false(self, mock_check_call): + # The mocked subprocess.check_call fakes a no-error process. + script_helper._interpreter_requires_environment() + self.assertFalse(script_helper._interpreter_requires_environment()) + self.assertEqual(1, mock_check_call.call_count) + + @mock.patch('subprocess.check_call') + def test_interpreter_requires_environment_details(self, mock_check_call): + script_helper._interpreter_requires_environment() + self.assertFalse(script_helper._interpreter_requires_environment()) + self.assertFalse(script_helper._interpreter_requires_environment()) + self.assertEqual(1, mock_check_call.call_count) + check_call_command = mock_check_call.call_args[0][0] + self.assertEqual(sys.executable, check_call_command[0]) + self.assertIn('-E', check_call_command) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -5,7 +5,7 @@ import unittest from unittest.mock import patch from test.script_helper import assert_python_ok, assert_python_failure -from test import support +from test import script_helper, support try: import threading except ImportError: @@ -755,6 +755,8 @@ stdout = stdout.rstrip() self.assertEqual(stdout, b'False') + @unittest.skipIf(script_helper._interpreter_requires_environment(), + 'Cannot run -E tests when PYTHON env vars are required.') def test_env_var_ignored_with_E(self): """PYTHON* environment variables must be ignored when -E is present.""" code = 'import tracemalloc; print(tracemalloc.is_tracing())' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 11:20:29 2015 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 04 Feb 2015 10:20:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Fixes_issue23390=3A_make_profile-opt_causes_-fprofile-ge?= =?utf-8?q?nerate_and_related_flags?= Message-ID: <20150204102019.34398.92598@psf.io> https://hg.python.org/cpython/rev/9c46707e5526 changeset: 94499:9c46707e5526 parent: 94497:0bd76ade1c7f parent: 94498:8957ff9776bd user: Gregory P. Smith date: Wed Feb 04 02:16:13 2015 -0800 summary: Fixes issue23390: make profile-opt causes -fprofile-generate and related flags to end up in distutils CFLAGS. files: Makefile.pre.in | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -488,14 +488,14 @@ $(MAKE) build_all_use_profile build_all_generate_profile: - $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-generate" LIBS="$(LIBS) -lgcov" + $(MAKE) all CFLAGS_NODIST="$(CFLAGS) -fprofile-generate" LDFLAGS="-fprofile-generate" LIBS="$(LIBS) -lgcov" run_profile_task: : # FIXME: can't run for a cross build $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) build_all_use_profile: - $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use -fprofile-correction" + $(MAKE) all CFLAGS_NODIST="$(CFLAGS) -fprofile-use -fprofile-correction" # Compile and run with gcov .PHONY=coverage coverage-lcov coverage-report -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 11:20:29 2015 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 04 Feb 2015 10:20:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fixes_issue233?= =?utf-8?q?90=3A_make_profile-opt_causes_-fprofile-generate_and_related_fl?= =?utf-8?q?ags?= Message-ID: <20150204102019.106264.95091@psf.io> https://hg.python.org/cpython/rev/8957ff9776bd changeset: 94498:8957ff9776bd branch: 3.4 parent: 94496:ef1d338bec8f user: Gregory P. Smith date: Wed Feb 04 02:11:56 2015 -0800 summary: Fixes issue23390: make profile-opt causes -fprofile-generate and related flags to end up in distutils CFLAGS. files: Makefile.pre.in | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -480,14 +480,14 @@ $(MAKE) build_all_use_profile build_all_generate_profile: - $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-generate" LIBS="$(LIBS) -lgcov" + $(MAKE) all CFLAGS_NODIST="$(CFLAGS) -fprofile-generate" LDFLAGS="-fprofile-generate" LIBS="$(LIBS) -lgcov" run_profile_task: : # FIXME: can't run for a cross build $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) build_all_use_profile: - $(MAKE) all CFLAGS="$(CFLAGS) -fprofile-use -fprofile-correction" + $(MAKE) all CFLAGS_NODIST="$(CFLAGS) -fprofile-use -fprofile-correction" # Compile and run with gcov .PHONY=coverage coverage-lcov coverage-report -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 14:54:22 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 Feb 2015 13:54:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogQmFz?= =?utf-8?q?eSelectorEventLoop_uses_directly_the_private_=5Fdebug_attribute?= Message-ID: <20150204135422.96094.76300@psf.io> https://hg.python.org/cpython/rev/c02cde905034 changeset: 94500:c02cde905034 branch: 3.4 parent: 94498:8957ff9776bd user: Victor Stinner date: Wed Feb 04 14:50:59 2015 +0100 summary: asyncio: BaseSelectorEventLoop uses directly the private _debug attribute Just try to be consistent: _debug was already used in some places, and always used in BaseProactorEventLoop. files: Lib/asyncio/selector_events.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -214,7 +214,7 @@ # It's now up to the protocol to handle the connection. except Exception as exc: - if self.get_debug(): + if self._debug: context = { 'message': ('Error on transport creation ' 'for incoming connection'), @@ -312,7 +312,7 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) self._sock_recv(fut, False, sock, n) @@ -350,7 +350,7 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) if data: @@ -393,7 +393,7 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) try: @@ -453,7 +453,7 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) self._sock_accept(fut, False, sock) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 14:54:22 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 Feb 2015 13:54:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogT25s?= =?utf-8?q?y_call_=5Fcheck=5Fresolved=5Faddress=28=29_in_debug_mode?= Message-ID: <20150204135422.96080.95954@psf.io> https://hg.python.org/cpython/rev/8b52ca4d11b8 changeset: 94501:8b52ca4d11b8 branch: 3.4 user: Victor Stinner date: Wed Feb 04 14:51:23 2015 +0100 summary: asyncio: Only call _check_resolved_address() in debug mode * _check_resolved_address() is implemented with getaddrinfo() which is slow * If available, use socket.inet_pton() instead of socket.getaddrinfo(), because it is much faster Microbenchmark (timeit) on Fedora 21 (Python 3.4, Linux 3.17, glibc 2.20) to validate the IPV4 address "127.0.0.1" or the IPv6 address "::1": * getaddrinfo() 10.4 usec per loop * inet_pton(): 0.285 usec per loop On glibc older than 2.14, getaddrinfo() always requests the list of all local IP addresses to the kernel (using a NETLINK socket). getaddrinfo() has other known issues, it's better to avoid it when it is possible. files: Lib/asyncio/base_events.py | 48 ++++++++++----- Lib/asyncio/proactor_events.py | 3 +- Lib/asyncio/selector_events.py | 3 +- Lib/test/test_asyncio/test_events.py | 4 + 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -75,7 +75,11 @@ def _check_resolved_address(sock, address): # Ensure that the address is already resolved to avoid the trap of hanging # the entire event loop when the address requires doing a DNS lookup. + # + # getaddrinfo() is slow (around 10 us per call): this function should only + # be called in debug mode family = sock.family + if family == socket.AF_INET: host, port = address elif family == socket.AF_INET6: @@ -83,22 +87,34 @@ else: return - type_mask = 0 - if hasattr(socket, 'SOCK_NONBLOCK'): - type_mask |= socket.SOCK_NONBLOCK - if hasattr(socket, 'SOCK_CLOEXEC'): - type_mask |= socket.SOCK_CLOEXEC - # Use getaddrinfo(flags=AI_NUMERICHOST) to ensure that the address is - # already resolved. - try: - socket.getaddrinfo(host, port, - family=family, - type=(sock.type & ~type_mask), - proto=sock.proto, - flags=socket.AI_NUMERICHOST) - except socket.gaierror as err: - raise ValueError("address must be resolved (IP address), got %r: %s" - % (address, err)) + # On Windows, socket.inet_pton() is only available since Python 3.4 + if hasattr(socket, 'inet_pton'): + # getaddrinfo() is slow and has known issue: prefer inet_pton() + # if available + try: + socket.inet_pton(family, host) + except OSError as exc: + raise ValueError("address must be resolved (IP address), " + "got host %r: %s" + % (host, exc)) + else: + # Use getaddrinfo(flags=AI_NUMERICHOST) to ensure that the address is + # already resolved. + type_mask = 0 + if hasattr(socket, 'SOCK_NONBLOCK'): + type_mask |= socket.SOCK_NONBLOCK + if hasattr(socket, 'SOCK_CLOEXEC'): + type_mask |= socket.SOCK_CLOEXEC + try: + socket.getaddrinfo(host, port, + family=family, + type=(sock.type & ~type_mask), + proto=sock.proto, + flags=socket.AI_NUMERICHOST) + except socket.gaierror as err: + raise ValueError("address must be resolved (IP address), " + "got host %r: %s" + % (host, err)) def _raise_stop_error(*args): raise _StopError diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -437,7 +437,8 @@ def sock_connect(self, sock, address): try: - base_events._check_resolved_address(sock, address) + if self._debug: + base_events._check_resolved_address(sock, address) except ValueError as err: fut = futures.Future(loop=self) fut.set_exception(err) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -397,7 +397,8 @@ raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) try: - base_events._check_resolved_address(sock, address) + if self._debug: + base_events._check_resolved_address(sock, address) except ValueError as err: fut.set_exception(err) else: diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1437,6 +1437,10 @@ 'selector': self.loop._selector.__class__.__name__}) def test_sock_connect_address(self): + # In debug mode, sock_connect() must ensure that the address is already + # resolved (call _check_resolved_address()) + self.loop.set_debug(True) + addresses = [(socket.AF_INET, ('www.python.org', 80))] if support.IPV6_ENABLED: addresses.extend(( -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 14:54:24 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 Feb 2015 13:54:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20150204135422.34410.20500@psf.io> https://hg.python.org/cpython/rev/cf4894e8f707 changeset: 94502:cf4894e8f707 parent: 94499:9c46707e5526 parent: 94501:8b52ca4d11b8 user: Victor Stinner date: Wed Feb 04 14:51:50 2015 +0100 summary: Merge 3.4 (asyncio) files: Lib/asyncio/base_events.py | 48 ++++++++++----- Lib/asyncio/proactor_events.py | 3 +- Lib/asyncio/selector_events.py | 13 ++-- Lib/test/test_asyncio/test_events.py | 4 + 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -75,7 +75,11 @@ def _check_resolved_address(sock, address): # Ensure that the address is already resolved to avoid the trap of hanging # the entire event loop when the address requires doing a DNS lookup. + # + # getaddrinfo() is slow (around 10 us per call): this function should only + # be called in debug mode family = sock.family + if family == socket.AF_INET: host, port = address elif family == socket.AF_INET6: @@ -83,22 +87,34 @@ else: return - type_mask = 0 - if hasattr(socket, 'SOCK_NONBLOCK'): - type_mask |= socket.SOCK_NONBLOCK - if hasattr(socket, 'SOCK_CLOEXEC'): - type_mask |= socket.SOCK_CLOEXEC - # Use getaddrinfo(flags=AI_NUMERICHOST) to ensure that the address is - # already resolved. - try: - socket.getaddrinfo(host, port, - family=family, - type=(sock.type & ~type_mask), - proto=sock.proto, - flags=socket.AI_NUMERICHOST) - except socket.gaierror as err: - raise ValueError("address must be resolved (IP address), got %r: %s" - % (address, err)) + # On Windows, socket.inet_pton() is only available since Python 3.4 + if hasattr(socket, 'inet_pton'): + # getaddrinfo() is slow and has known issue: prefer inet_pton() + # if available + try: + socket.inet_pton(family, host) + except OSError as exc: + raise ValueError("address must be resolved (IP address), " + "got host %r: %s" + % (host, exc)) + else: + # Use getaddrinfo(flags=AI_NUMERICHOST) to ensure that the address is + # already resolved. + type_mask = 0 + if hasattr(socket, 'SOCK_NONBLOCK'): + type_mask |= socket.SOCK_NONBLOCK + if hasattr(socket, 'SOCK_CLOEXEC'): + type_mask |= socket.SOCK_CLOEXEC + try: + socket.getaddrinfo(host, port, + family=family, + type=(sock.type & ~type_mask), + proto=sock.proto, + flags=socket.AI_NUMERICHOST) + except socket.gaierror as err: + raise ValueError("address must be resolved (IP address), " + "got host %r: %s" + % (host, err)) def _raise_stop_error(*args): raise _StopError diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -437,7 +437,8 @@ def sock_connect(self, sock, address): try: - base_events._check_resolved_address(sock, address) + if self._debug: + base_events._check_resolved_address(sock, address) except ValueError as err: fut = futures.Future(loop=self) fut.set_exception(err) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -214,7 +214,7 @@ # It's now up to the protocol to handle the connection. except Exception as exc: - if self.get_debug(): + if self._debug: context = { 'message': ('Error on transport creation ' 'for incoming connection'), @@ -312,7 +312,7 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) self._sock_recv(fut, False, sock, n) @@ -350,7 +350,7 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) if data: @@ -393,11 +393,12 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) try: - base_events._check_resolved_address(sock, address) + if self._debug: + base_events._check_resolved_address(sock, address) except ValueError as err: fut.set_exception(err) else: @@ -453,7 +454,7 @@ This method is a coroutine. """ - if self.get_debug() and sock.gettimeout() != 0: + if self._debug and sock.gettimeout() != 0: raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) self._sock_accept(fut, False, sock) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1437,6 +1437,10 @@ 'selector': self.loop._selector.__class__.__name__}) def test_sock_connect_address(self): + # In debug mode, sock_connect() must ensure that the address is already + # resolved (call _check_resolved_address()) + self.loop.set_debug(True) + addresses = [(socket.AF_INET, ('www.python.org', 80))] if support.IPV6_ENABLED: addresses.extend(( -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 16:15:14 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 Feb 2015 15:15:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_explain_how_to_display_ResourceWarning_in_the_debug_mode_secti?= =?utf-8?q?on?= Message-ID: <20150204151505.106346.33250@psf.io> https://hg.python.org/cpython/rev/8e6c1264e2fe changeset: 94503:8e6c1264e2fe branch: 3.4 parent: 94501:8b52ca4d11b8 user: Victor Stinner date: Wed Feb 04 16:14:33 2015 +0100 summary: asyncio doc: explain how to display ResourceWarning in the debug mode section files: Doc/library/asyncio-dev.rst | 39 +++++++++++++++--------- 1 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -14,16 +14,22 @@ Debug mode of asyncio --------------------- -To enable the debug mode globally, set the environment variable -:envvar:`PYTHONASYNCIODEBUG` to ``1``. To see debug traces, set the log level -of the :ref:`asyncio logger ` to :py:data:`logging.DEBUG`. The -simplest configuration is:: +The implementation of :mod:`asyncio` module has been written for performances. +To development with asyncio, it's required to enable the debug checks to ease +the development of asynchronous code. - import logging - # ... - logging.basicConfig(level=logging.DEBUG) +Setup an application to enable all debug checks: -Examples of effects of the debug mode: +* Enable the asyncio debug mode globally by setting the environment variable + :envvar:`PYTHONASYNCIODEBUG` to ``1`` +* Set the log level of the :ref:`asyncio logger ` to + :py:data:`logging.DEBUG`. For example, call + ``logging.basicConfig(level=logging.DEBUG)`` at startup. +* Configure the :mod:`warnings` module to display :exc:`ResourceWarning` + warnings. For example, use the ``-Wdefault`` command line option of Python to + display them. + +Examples debug checks: * Log :ref:`coroutines defined but never "yielded from" ` @@ -33,6 +39,8 @@ * Log callbacks taking more than 100 ms to be executed. The :attr:`BaseEventLoop.slow_callback_duration` attribute is the minimum duration in seconds of "slow" callbacks. +* :exc:`ResourceWarning` warnings are emitted when transports and event loops + are :ref:`not closed explicitly `. .. seealso:: @@ -372,14 +380,15 @@ :ref:`Detect coroutine objects never scheduled `. +.. _asyncio-close-transports: -Close transports ----------------- +Close transports and event loops +-------------------------------- When a transport is no more needed, call its ``close()`` method to release -resources. +resources. Event loops must also be closed explicitly. -If a transport (or an event loop) is not closed explicitly, a -:exc:`ResourceWarning` warning will be emitted in its destructor. The -:exc:`ResourceWarning` warnings are hidden by default: use the ``-Wd`` command -line option of Python to show them. +If a transport or an event loop is not closed explicitly, a +:exc:`ResourceWarning` warning will be emitted in its destructor. By default, +:exc:`ResourceWarning` warnings are ignored. The :ref:`Debug mode of asyncio +` section explains how to display them. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 16:15:14 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 04 Feb 2015 15:15:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio_doc=29?= Message-ID: <20150204151505.34396.83498@psf.io> https://hg.python.org/cpython/rev/f0665e8e497d changeset: 94504:f0665e8e497d parent: 94502:cf4894e8f707 parent: 94503:8e6c1264e2fe user: Victor Stinner date: Wed Feb 04 16:14:58 2015 +0100 summary: Merge 3.4 (asyncio doc) files: Doc/library/asyncio-dev.rst | 39 +++++++++++++++--------- 1 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -14,16 +14,22 @@ Debug mode of asyncio --------------------- -To enable the debug mode globally, set the environment variable -:envvar:`PYTHONASYNCIODEBUG` to ``1``. To see debug traces, set the log level -of the :ref:`asyncio logger ` to :py:data:`logging.DEBUG`. The -simplest configuration is:: +The implementation of :mod:`asyncio` module has been written for performances. +To development with asyncio, it's required to enable the debug checks to ease +the development of asynchronous code. - import logging - # ... - logging.basicConfig(level=logging.DEBUG) +Setup an application to enable all debug checks: -Examples of effects of the debug mode: +* Enable the asyncio debug mode globally by setting the environment variable + :envvar:`PYTHONASYNCIODEBUG` to ``1`` +* Set the log level of the :ref:`asyncio logger ` to + :py:data:`logging.DEBUG`. For example, call + ``logging.basicConfig(level=logging.DEBUG)`` at startup. +* Configure the :mod:`warnings` module to display :exc:`ResourceWarning` + warnings. For example, use the ``-Wdefault`` command line option of Python to + display them. + +Examples debug checks: * Log :ref:`coroutines defined but never "yielded from" ` @@ -33,6 +39,8 @@ * Log callbacks taking more than 100 ms to be executed. The :attr:`BaseEventLoop.slow_callback_duration` attribute is the minimum duration in seconds of "slow" callbacks. +* :exc:`ResourceWarning` warnings are emitted when transports and event loops + are :ref:`not closed explicitly `. .. seealso:: @@ -372,14 +380,15 @@ :ref:`Detect coroutine objects never scheduled `. +.. _asyncio-close-transports: -Close transports ----------------- +Close transports and event loops +-------------------------------- When a transport is no more needed, call its ``close()`` method to release -resources. +resources. Event loops must also be closed explicitly. -If a transport (or an event loop) is not closed explicitly, a -:exc:`ResourceWarning` warning will be emitted in its destructor. The -:exc:`ResourceWarning` warnings are hidden by default: use the ``-Wd`` command -line option of Python to show them. +If a transport or an event loop is not closed explicitly, a +:exc:`ResourceWarning` warning will be emitted in its destructor. By default, +:exc:`ResourceWarning` warnings are ignored. The :ref:`Debug mode of asyncio +` section explains how to display them. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 4 17:37:12 2015 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 04 Feb 2015 16:37:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_code_clean_up=2E?= Message-ID: <20150204163708.25845.65122@psf.io> https://hg.python.org/cpython/rev/017e7391ab58 changeset: 94505:017e7391ab58 user: Raymond Hettinger date: Wed Feb 04 08:37:02 2015 -0800 summary: Minor code clean up. files: Objects/setobject.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -89,7 +89,7 @@ freeslot = entry; if (i + LINEAR_PROBES <= mask) { - for (j = 1 ; j <= LINEAR_PROBES ; j++) { + for (j = 0 ; j < LINEAR_PROBES ; j++) { entry++; if (entry->key == NULL) goto found_null; @@ -151,7 +151,7 @@ if (entry->key == NULL) goto found_null; if (i + LINEAR_PROBES <= mask) { - for (j = 1; j <= LINEAR_PROBES; j++) { + for (j = 0; j < LINEAR_PROBES; j++) { entry++; if (entry->key == NULL) goto found_null; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 00:19:09 2015 From: python-checkins at python.org (chris.angelico) Date: Wed, 04 Feb 2015 23:19:09 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_485_from_Chris_Bar?= =?utf-8?q?ker=27s_edits?= Message-ID: <20150204231853.39274.76411@psf.io> https://hg.python.org/peps/rev/f77ab680d1e9 changeset: 5692:f77ab680d1e9 user: Chris Angelico date: Thu Feb 05 10:17:42 2015 +1100 summary: Update PEP 485 from Chris Barker's edits files: pep-0485.txt | 484 +++++++++++++++++++++++++++++++------- 1 files changed, 397 insertions(+), 87 deletions(-) diff --git a/pep-0485.txt b/pep-0485.txt --- a/pep-0485.txt +++ b/pep-0485.txt @@ -15,8 +15,10 @@ ======== This PEP proposes the addition of a function to the standard library -that determines whether one value is approximately equal or "close" -to another value. +that determines whether one value is approximately equal or "close" to +another value. It is also proposed that an assertion be added to the +``unittest.TestCase`` class to provide easy access for those using +unittest for testing. Rationale @@ -37,27 +39,35 @@ Existing Implementations ------------------------ -The standard library includes the -``unittest.TestCase.assertAlmostEqual`` method, but it: +The standard library includes the ``unittest.TestCase.assertAlmostEqual`` +method, but it: * Is buried in the unittest.TestCase class -* Is an assertion, so you can't use it as a general test (easily) +* Is an assertion, so you can't use it as a general test at the command + line, etc. (easily) -* Uses number of decimal digits or an absolute delta, which are - particular use cases that don't provide a general relative error. +* Is an absolute difference test. Often the measure of difference + requires, particularly for floating point numbers, a relative error, + i.e "Are these two values within x% of each-other?", rather than an + absolute error. Particularly when the magnatude of the values is + unknown a priori. -The numpy package has the ``allclose()`` and ``isclose()`` functions. +The numpy package has the ``allclose()`` and ``isclose()`` functions, +but they are only available with numpy. The statistics package tests include an implementation, used for its unit tests. One can also find discussion and sample implementations on Stack -Overflow, and other help sites. +Overflow and other help sites. -These existing implementations indicate that this is a common need, -and not trivial to write oneself, making it a candidate for the -standard library. +Many other non-python systems provide such a test, including the Boost C++ +library and the APL language (reference?). + +These existing implementations indicate that this is a common need and +not trivial to write oneself, making it a candidate for the standard +library. Proposed Implementation @@ -68,21 +78,22 @@ The new function will have the following signature:: - is_close_to(actual, expected, tol=1e-8, abs_tol=0.0) + is_close(a, b, rel_tolerance=1e-9, abs_tolerance=0.0) -``actual``: is the value that has been computed, measured, etc. +``a`` and ``b``: are the two values to be tested to relative closeness -``expected``: is the "known" value. +``rel_tolerance``: is the relative tolerance -- it is the amount of +error allowed, relative to the magnitude a and b. For example, to set +a tolerance of 5%, pass tol=0.05. The default tolerance is 1e-8, which +assures that the two values are the same within about 8 decimal +digits. -``tol``: is the relative tolerance -- it is the amount of error -allowed, relative to the magnitude of the expected value. - -``abs_tol``: is an minimum absolute tolerance level -- useful for +``abs_tolerance``: is an minimum absolute tolerance level -- useful for comparisons near zero. Modulo error checking, etc, the function will return the result of:: - abs(expected-actual) <= max(tol*expected, abs_tol) + abs(a-b) <= max( rel_tolerance * min(abs(a), abs(b), abs_tolerance ) Handling of non-finite numbers @@ -108,7 +119,7 @@ * ``int`` * ``Fraction`` - + * ``complex``: for complex, ``abs(z)`` will be used for scaling and comparison. @@ -116,35 +127,85 @@ Behavior near zero ------------------ -Relative comparison is problematic if either value is zero. In this -case, the difference is relative to zero, and thus will always be -smaller than the prescribed tolerance. To handle this case, an -optional parameter, ``abs_tol`` (default 0.0) can be used to set a -minimum tolerance to be used in the case of very small relative -tolerance. That is, the values will be considered close if:: +Relative comparison is problematic if either value is zero. By +definition, no value is small relative to zero. And computationally, +if either value is zero, the difference is the absolute value of the +other value, and the computed absolute tolerance will be rel_tolerance +times that value. rel-tolerance is always less than one, so the +difference will never be less than the tolerance. - abs(a-b) <= abs(tol*expected) or abs(a-b) <= abs_tol +However, while mathematically correct, there are many use cases where +a user will need to know if a computed value is "close" to zero. This +calls for an absolute tolerance test. If the user needs to call this +function inside a loop or comprehension, where some, but not all, of +the expected values may be zero, it is important that both a relative +tolerance and absolute tolerance can be tested for with a single +function with a single set of parameters. -If the user sets the rel_tol parameter to 0.0, then only the absolute -tolerance will effect the result, so this function provides an -absolute tolerance check as well. +There is a similar issue if the two values to be compared straddle zero: +if a is approximately equal to -b, then a and b will never be computed +as "close". + +To handle this case, an optional parameter, ``abs_tolerance`` can be +used to set a minimum tolerance used in the case of very small or zero +computed absolute tolerance. That is, the values will be always be +considered close if the difference between them is less than the +abs_tolerance + +The default absolute tolerance value is set to zero because there is +no value that is appropriate for the general case. It is impossible to +know an appropriate value without knowing the likely values expected +for a given use case. If all the values tested are on order of one, +then a value of about 1e-8 might be appropriate, but that would be far +too large if expected values are on order of 1e-12 or smaller. + +Any non-zero default might result in user's tests passing totally +inappropriately. If, on the other hand a test against zero fails the +first time with defaults, a user will be prompted to select an +appropriate value for the problem at hand in order to get the test to +pass. + +NOTE: that the author of this PEP has resolved to go back over many of +his tests that use the numpy ``all_close()`` function, which provides +a default abs_tolerance, and make sure that the default value is +appropriate. + +If the user sets the rel_tolerance parameter to 0.0, then only the +absolute tolerance will effect the result. While not the goal of the +function, it does allow it to be used as a purely absolute tolerance +check as well. + +unittest assertion +------------------- + +[need text here] + +implementation +-------------- A sample implementation is available (as of Jan 22, 2015) on gitHub: -https://github.com/PythonCHB/close_pep/blob/master/is_close_to.py +https://github.com/PythonCHB/close_pep/blob/master +This implementation has a flag that lets the user select which +relative tolerance test to apply -- this PEP does not suggest that +that be retained, but rather than the strong test be selected. Relative Difference =================== There are essentially two ways to think about how close two numbers -are to each-other: absolute difference: simply ``abs(a-b)``, and -relative difference: ``abs(a-b)/scale_factor`` [2]_. The absolute -difference is trivial enough that this proposal focuses on the -relative difference. +are to each-other: + +Absolute difference: simply ``abs(a-b)`` + +Relative difference: ``abs(a-b)/scale_factor`` [2]_. + +The absolute difference is trivial enough that this proposal focuses +on the relative difference. Usually, the scale factor is some function of the values under -consideration, for instance: +consideration, for instance: 1) The absolute value of one of the input values @@ -152,7 +213,106 @@ 3) The minimum absolute value of the two. -4) The arithmetic mean of the two +4) The absolute value of the arithmetic mean of the two + +These lead to the following possibilities for determining if two +values, a and b, are close to each other. + +1) ``abs(a-b) <= tol*abs(a)`` + +2) ``abs(a-b) <= tol * max( abs(a), abs(b) )`` + +3) ``abs(a-b) <= tol * min( abs(a), abs(b) )`` + +4) ``abs(a-b) <= tol * (a + b)/2`` + +NOTE: (2) and (3) can also be written as: + +2) ``(abs(a-b) <= tol*abs(a)) or (abs(a-b) <= tol*abs(a))`` + +3) ``(abs(a-b) <= tol*abs(a)) and (abs(a-b) <= tol*abs(a))`` + +(Boost refers to these as the "weak" and "strong" formulations [3]_) +These can be a tiny bit more computationally efficient, and thus are +used in the example code. + +Each of these formulations can lead to slightly different results. +However, if the tolerance value is small, the differences are quite +small. In fact, often less than available floating point precision. + +How much difference does it make? +--------------------------------- + +When selecting a method to determine closeness, one might want to know +how much of a difference it could make to use one test or the other +-- i.e. how many values are there (or what range of values) that will +pass one test, but not the other. + +The largest difference is between options (2) and (3) where the +allowable absolute difference is scaled by either the larger or +smaller of the values. + +Define ``delta`` to be the difference between the allowable absolute +tolerance defined by the larger value and that defined by the smaller +value. That is, the amount that the two input values need to be +different in order to get a different result from the two tests. +``tol`` is the relative tolerance value. + +Assume that ``a`` is the larger value and that both ``a`` and ``b`` +are positive, to make the analysis a bit easier. ``delta`` is +therefore:: + + delta = tol * (a-b) + + +or:: + + delta / tol = (a-b) + + +The largest absolute difference that would pass the test: ``(a-b)``, +equals the tolerance times the larger value:: + + (a-b) = tol * a + + +Substituting into the expression for delta:: + + delta / tol = tol * a + + +so:: + + delta = tol**2 * a + + +For example, for ``a = 10``, ``b = 9``, ``tol = 0.1`` (10%): + +maximum tolerance ``tol * a == 0.1 * 10 == 1.0`` + +minimum tolerance ``tol * b == 0.1 * 9.0 == 0.9`` + +delta = ``(1.0 - 0.9) * 0.1 = 0.1`` or ``tol**2 * a = 0.1**2 * 10 = .01`` + +The absolute difference between the maximum and minimum tolerance +tests in this case could be substantial. However, the primary use +case for the proposed function is testing the results of computations. +In that case a relative tolerance is likely to be selected of much +smaller magnitude. + +For example, a relative tolerance of ``1e-8`` is about half the +precision available in a python float. In that case, the difference +between the two tests is ``1e-8**2 * a`` or ``1e-16 * a``, which is +close to the limit of precision of a python float. If the relative +tolerance is set to the proposed default of 1e-9 (or smaller), the +difference between the two tests will be lost to the limits of +precision of floating point. That is, each of the four methods will +yield exactly the same results for all values of a and b. + +In addition, in common use, tolerances are defined to 1 significant +figure -- that is, 1e-8 is specifying about 8 decimal digits of +accuracy. So the difference between the various possible tests is well +below the precision to which the tolerance is specified. Symmetry @@ -161,46 +321,113 @@ A relative comparison can be either symmetric or non-symmetric. For a symmetric algorithm: -``is_close_to(a,b)`` is always equal to ``is_close_to(b,a)`` +``is_close_to(a,b)`` is always the same as ``is_close_to(b,a)`` -This is an appealing consistency -- it mirrors the symmetry of -equality, and is less likely to confuse people. However, often the -question at hand is: +If a relative closeness test uses only one of the values (such as (1) +above), then the result is asymmetric, i.e. is_close_to(a,b) is not +necessarily the same as is_close_to(b,a). -"Is this computed or measured value within some tolerance of a known -value?" +Which approach is most appropriate depends on what question is being +asked. If the question is: "are these two numbers close to each +other?", there is no obvious ordering, and a symmetric test is most +appropriate. -In this case, the user wants the relative tolerance to be specifically -scaled against the known value. It is also easier for the user to -reason about. +However, if the question is: "Is the computed value within x% of this +known value?", then it is appropriate to scale the tolerance to the +known value, and an asymmetric test is most appropriate. -This proposal uses this asymmetric test to allow this specific -definition of relative tolerance. +From the previous section, it is clear that either approach would +yield the same or similar results in the common use cases. In that +case, the goal of this proposal is to provide a function that is least +likely to produce surprising results. -Example: +The symmetric approach provide an appealing consistency -- it +mirrors the symmetry of equality, and is less likely to confuse +people. A symmetric test also relieves the user of the need to think +about the order in which to set the arguments. It was also pointed +out that there may be some cases where the order of evaluation may not +be well defined, for instance in the case of comparing a set of values +all against each other. -For the question: "Is the value of a within 10% of b?", Using b to -scale the percent error clearly defines the result. +There may be cases when a user does need to know that a value is +within a particular range of a known value. In that case, it is easy +enough to simply write the test directly:: -However, as this approach is not symmetric, a may be within 10% of b, -but b is not within 10% of a. Consider the case:: + if a-b <= tol*a: - a = 9.0 - b = 10.0 +(assuming a > b in this case). There is little need to provide a +function for this particular case. -The difference between a and b is 1.0. 10% of a is 0.9, so b is not -within 10% of a. But 10% of b is 1.0, so a is within 10% of b. +This proposal uses a symmetric test. -Casual users might reasonably expect that if a is close to b, then b -would also be close to a. However, in the common cases, the tolerance -is quite small and often poorly defined, i.e. 1e-8, defined to only -one significant figure, so the result will be very similar regardless -of the order of the values. And if the user does care about the -precise result, s/he can take care to always pass in the two -parameters in sorted order. +Which symmetric test? +--------------------- -This proposed implementation uses asymmetric criteria with the scaling -value clearly identified. +There are three symmetric tests considered: + +The case that uses the arithmetic mean of the two values requires that +the value be either added together before dividing by 2, which could +result in extra overflow to inf for very large numbers, or require +each value to be divided by two before being added together, which +could result in underflow to -inf for very small numbers. This effect +would only occur at the very limit of float values, but it was decided +there as no benefit to the method worth reducing the range of +functionality. + +This leaves the boost "weak" test (2)-- or using the smaller value to +scale the tolerance, or the Boost "strong" (3) test, which uses the +smaller of the values to scale the tolerance. For small tolerance, +they yield the same result, but this proposal uses the boost "strong" +test case: it is symmetric and provides a slightly stricter criteria +for tolerance. + + +Defaults +======== + +Default values are required for the relative and absolute tolerance. + +Relative Tolerance Default +-------------------------- + +The relative tolerance required for two values to be considered +"close" is entirely use-case dependent. Nevertheless, the relative +tolerance needs to be less than 1.0, and greater than 1e-16 +(approximate precision of a python float). The value of 1e-9 was +selected because it is the largest relative tolerance for which the +various possible methods will yield the same result, and it is also +about half of the precision available to a python float. In the +general case, a good numerical algorithm is not expected to lose more +than about half of available digits of accuracy, and if a much larger +tolerance is acceptable, the user should be considering the proper +value in that case. Thus 1-e9 is expected to "just work" for many +cases. + +Absolute tolerance default +-------------------------- + +The absolute tolerance value will be used primarily for comparing to +zero. The absolute tolerance required to determine if a value is +"close" to zero is entirely use-case dependent. There is also +essentially no bounds to the useful range -- expected values would +conceivably be anywhere within the limits of a python float. Thus a +default of 0.0 is selected. + +If, for a given use case, a user needs to compare to zero, the test +will be guaranteed to fail the first time, and the user can select an +appropriate value. + +It was suggested that comparing to zero is, in fact, a common use case +(evidence suggest that the numpy functions are often used with zero). +In this case, it would be desirable to have a "useful" default. Values +around 1-e8 were suggested, being about half of floating point +precision for values of around value 1. + +However, to quote The Zen: "In the face of ambiguity, refuse the +temptation to guess." Guessing that users will most often be concerned +with values close to 1.0 would lead to spurious passing tests when used +with smaller values -- this is potentially more damaging than +requiring the user to thoughtfully select an appropriate value. Expected Uses @@ -208,10 +435,23 @@ The primary expected use case is various forms of testing -- "are the results computed near what I expect as a result?" This sort of test -may or may not be part of a formal unit testing suite. +may or may not be part of a formal unit testing suite. Such testing +could be used one-off at the command line, in an iPython notebook, +part of doctests, or simple assets in an ``if __name__ == "__main__"`` +block. -The function might be used also to determine if a measured value is -within an expected value. +The proposed unitest.TestCase assertion would have course be used in +unit testing. + +It would also be an appropriate function to use for the termination +criteria for a simple iterative solution to an implicit function:: + + guess = something + while True: + new_guess = implicit_function(guess, *args) + if is_close(new_guess, guess): + break + guess = new_guess Inappropriate uses @@ -238,8 +478,8 @@ computing the difference, rounding to the given number of decimal places (default 7), and comparing to zero. -This method was not selected for this proposal, as the use of decimal -digits is a specific, not generally useful or flexible test. +This method is purely an absolute tolerance test, and does not address +the need for a relative tolerance test. numpy ``is_close()`` -------------------- @@ -262,13 +502,16 @@ In this approach, the absolute and relative tolerance are added together, rather than the ``or`` method used in this proposal. This is computationally more simple, and if relative tolerance is larger than -the absolute tolerance, then the addition will have no effect. But if -the absolute and relative tolerances are of similar magnitude, then +the absolute tolerance, then the addition will have no effect. However, +if the absolute and relative tolerances are of similar magnitude, then the allowed difference will be about twice as large as expected. -Also, if the value passed in are small compared to the absolute -tolerance, then the relative tolerance will be completely swamped, -perhaps unexpectedly. +This makes the function harder to understand, with no computational +advantage in this context. + +Even more critically, if the values passed in are small compared to +the absolute tolerance, then the relative tolerance will be +completely swamped, perhaps unexpectedly. This is why, in this proposal, the absolute tolerance defaults to zero -- the user will be required to choose a value appropriate for the @@ -279,25 +522,92 @@ ------------------------------- The Boost project ( [3]_ ) provides a floating point comparison -function. Is is a symetric approach, with both "weak" (larger of the +function. Is is a symmetric approach, with both "weak" (larger of the two relative errors) and "strong" (smaller of the two relative errors) -options. +options. This proposal uses the Boost "strong" approach. There is no +need to complicate the API by providing the option to select different +methods when the results will be similar in most cases, and the user +is unlikely to know which to select in any case. -It was decided that a method that clearly defined which value was used -to scale the relative error would be more appropriate for the standard -library. + +Alternate Proposals +------------------- + + +A Recipe +''''''''' + +The primary alternate proposal was to not provide a standard library +function at all, but rather, provide a recipe for users to refer to. +This would have the advantage that the recipe could provide and +explain the various options, and let the user select that which is +most appropriate. However, that would require anyone needing such a +test to, at the very least, copy the function into their code base, +and select the comparison method to use. + +In addition, adding the function to the standard library allows it to +be used in the ``unittest.TestCase.assertIsClose()`` method, providing +a substantial convenience to those using unittest. + + +``zero_tol`` +'''''''''''' + +One possibility was to provide a zero tolerance parameter, rather than +the absolute tolerance parameter. This would be an absolute tolerance +that would only be applied in the case of one of the arguments being +exactly zero. This would have the advantage of retaining the full +relative tolerance behavior for all non-zero values, while allowing +tests against zero to work. However, it would also result in the +potentially surprising result that a small value could be "close" to +zero, but not "close" to an even smaller value. e.g., 1e-10 is "close" +to zero, but not "close" to 1e-11. + + +No absolute tolerance +''''''''''''''''''''' + +Given the issues with comparing to zero, another possibility would +have been to only provide a relative tolerance, and let every +comparison to zero fail. In this case, the user would need to do a +simple absolute test: `abs(val) < zero_tol` in the case where the +comparison involved zero. + +However, this would not allow the same call to be used for a sequence +of values, such as in a loop or comprehension, or in the +``TestCase.assertClose()`` method. Making the function far less +useful. It is noted that the default abs_tolerance=0.0 achieves the +same effect if the default is not overidden. + +Other tests +'''''''''''' + +The other tests considered are all discussed in the Relative Error +section above. + References ========== -.. [1] Python-ideas list discussion thread - (https://mail.python.org/pipermail/python-ideas/2015-January/030947.html) +.. [1] Python-ideas list discussion threads -.. [2] Wikipedaia page on relative difference - (http://en.wikipedia.org/wiki/Relative_change_and_difference) + https://mail.python.org/pipermail/python-ideas/2015-January/030947.html + + https://mail.python.org/pipermail/python-ideas/2015-January/031124.html + + https://mail.python.org/pipermail/python-ideas/2015-January/031313.html + +.. [2] Wikipedia page on relative difference + + http://en.wikipedia.org/wiki/Relative_change_and_difference .. [3] Boost project floating-point comparison algorithms - (http://www.boost.org/doc/libs/1_35_0/libs/test/doc/components/test_tools/floating_point_comparison.html) + + http://www.boost.org/doc/libs/1_35_0/libs/test/doc/components/test_tools/floating_point_comparison.html + +.. Bruce Dawson's discussion of floating point. + + https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ Copyright -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Feb 5 02:16:52 2015 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 05 Feb 2015 01:16:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Make_the_stdli?= =?utf-8?q?b_test_suite_helper_test=2Escript=5Fhelper=2E=5Fassert=5Fpython?= =?utf-8?q?_no_longer?= Message-ID: <20150205011649.39278.82682@psf.io> https://hg.python.org/cpython/rev/8d388f6c2ac2 changeset: 94506:8d388f6c2ac2 branch: 3.4 parent: 94503:8e6c1264e2fe user: Gregory P. Smith date: Wed Feb 04 17:10:19 2015 -0800 summary: Make the stdlib test suite helper test.script_helper._assert_python no longer pass -I or -E to the child process by default when the environment is required for the child process interpreter to function properly. files: Lib/test/script_helper.py | 5 ++- Lib/test/test_script_helper.py | 33 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -52,16 +52,17 @@ # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): + env_required = _interpreter_requires_environment() if '__isolated' in env_vars: isolated = env_vars.pop('__isolated') else: - isolated = not env_vars + isolated = not env_vars and not env_required cmd_line = [sys.executable, '-X', 'faulthandler'] if isolated: # isolated mode: ignore Python environment variables, ignore user # site-packages, and don't add the current directory to sys.path cmd_line.append('-I') - elif not env_vars: + elif not env_vars and not env_required: # ignore Python environment variables cmd_line.append('-E') # Need to preserve the original environment, for in-place testing of diff --git a/Lib/test/test_script_helper.py b/Lib/test/test_script_helper.py --- a/Lib/test/test_script_helper.py +++ b/Lib/test/test_script_helper.py @@ -33,6 +33,39 @@ self.assertIn('import sys; sys.exit(0)', error_msg, msg='unexpected command line.') + @mock.patch('subprocess.Popen') + def test_assert_python_isolated_when_env_not_required(self, mock_popen): + with mock.patch.object(script_helper, + '_interpreter_requires_environment', + return_value=False) as mock_ire_func: + mock_popen.side_effect = RuntimeError('bail out of unittest') + try: + script_helper._assert_python(True, '-c', 'None') + except RuntimeError as err: + self.assertEqual('bail out of unittest', err.args[0]) + self.assertEqual(1, mock_popen.call_count) + self.assertEqual(1, mock_ire_func.call_count) + popen_command = mock_popen.call_args[0][0] + self.assertEqual(sys.executable, popen_command[0]) + self.assertIn('None', popen_command) + self.assertIn('-I', popen_command) + self.assertNotIn('-E', popen_command) # -I overrides this + + @mock.patch('subprocess.Popen') + def test_assert_python_not_isolated_when_env_is_required(self, mock_popen): + """Ensure that -I is not passed when the environment is required.""" + with mock.patch.object(script_helper, + '_interpreter_requires_environment', + return_value=True) as mock_ire_func: + mock_popen.side_effect = RuntimeError('bail out of unittest') + try: + script_helper._assert_python(True, '-c', 'None') + except RuntimeError as err: + self.assertEqual('bail out of unittest', err.args[0]) + popen_command = mock_popen.call_args[0][0] + self.assertNotIn('-I', popen_command) + self.assertNotIn('-E', popen_command) + class TestScriptHelperEnvironment(unittest.TestCase): """Code coverage for _interpreter_requires_environment().""" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 02:16:52 2015 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 05 Feb 2015 01:16:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Make_the_stdlib_test_suite_helper_test=2Escript=5Fhelper?= =?utf-8?q?=2E=5Fassert=5Fpython_no_longer?= Message-ID: <20150205011650.39292.28635@psf.io> https://hg.python.org/cpython/rev/7dce0cbea210 changeset: 94507:7dce0cbea210 parent: 94505:017e7391ab58 parent: 94506:8d388f6c2ac2 user: Gregory P. Smith date: Wed Feb 04 17:16:30 2015 -0800 summary: Make the stdlib test suite helper test.script_helper._assert_python no longer pass -I or -E to the child process by default when the environment is required for the child process interpreter to function properly. files: Lib/test/script_helper.py | 5 ++- Lib/test/test_script_helper.py | 33 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -52,16 +52,17 @@ # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): + env_required = interpreter_requires_environment() if '__isolated' in env_vars: isolated = env_vars.pop('__isolated') else: - isolated = not env_vars + isolated = not env_vars and not env_required cmd_line = [sys.executable, '-X', 'faulthandler'] if isolated: # isolated mode: ignore Python environment variables, ignore user # site-packages, and don't add the current directory to sys.path cmd_line.append('-I') - elif not env_vars: + elif not env_vars and not env_required: # ignore Python environment variables cmd_line.append('-E') # Need to preserve the original environment, for in-place testing of diff --git a/Lib/test/test_script_helper.py b/Lib/test/test_script_helper.py --- a/Lib/test/test_script_helper.py +++ b/Lib/test/test_script_helper.py @@ -33,6 +33,39 @@ self.assertIn('import sys; sys.exit(0)', error_msg, msg='unexpected command line.') + @mock.patch('subprocess.Popen') + def test_assert_python_isolated_when_env_not_required(self, mock_popen): + with mock.patch.object(script_helper, + 'interpreter_requires_environment', + return_value=False) as mock_ire_func: + mock_popen.side_effect = RuntimeError('bail out of unittest') + try: + script_helper._assert_python(True, '-c', 'None') + except RuntimeError as err: + self.assertEqual('bail out of unittest', err.args[0]) + self.assertEqual(1, mock_popen.call_count) + self.assertEqual(1, mock_ire_func.call_count) + popen_command = mock_popen.call_args[0][0] + self.assertEqual(sys.executable, popen_command[0]) + self.assertIn('None', popen_command) + self.assertIn('-I', popen_command) + self.assertNotIn('-E', popen_command) # -I overrides this + + @mock.patch('subprocess.Popen') + def test_assert_python_not_isolated_when_env_is_required(self, mock_popen): + """Ensure that -I is not passed when the environment is required.""" + with mock.patch.object(script_helper, + 'interpreter_requires_environment', + return_value=True) as mock_ire_func: + mock_popen.side_effect = RuntimeError('bail out of unittest') + try: + script_helper._assert_python(True, '-c', 'None') + except RuntimeError as err: + self.assertEqual('bail out of unittest', err.args[0]) + popen_command = mock_popen.call_args[0][0] + self.assertNotIn('-I', popen_command) + self.assertNotIn('-E', popen_command) + class TestScriptHelperEnvironment(unittest.TestCase): """Code coverage for interpreter_requires_environment().""" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 04:00:31 2015 From: python-checkins at python.org (donald.stufft) Date: Thu, 05 Feb 2015 03:00:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Update_pip_to_?= =?utf-8?b?Ni4wLjg=?= Message-ID: <20150205030024.34400.90033@psf.io> https://hg.python.org/cpython/rev/625798e94b14 changeset: 94508:625798e94b14 branch: 3.4 parent: 94506:8d388f6c2ac2 user: Donald Stufft date: Wed Feb 04 22:00:17 2015 -0500 summary: Update pip to 6.0.8 files: Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl | Bin 3 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ _SETUPTOOLS_VERSION = "12.0.5" -_PIP_VERSION = "6.0.7" +_PIP_VERSION = "6.0.8" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl deleted file mode 100644 index e01e8c4f44fbf99d9cb286f5a06b6689ff29d4d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..be9238d94c10081b4450aad01851f4c4eda1897c GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 04:01:10 2015 From: python-checkins at python.org (donald.stufft) Date: Thu, 05 Feb 2015 03:01:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_Update_pip_to_6=2E0=2E8?= Message-ID: <20150205030103.39294.57209@psf.io> https://hg.python.org/cpython/rev/a7ddddfe9e36 changeset: 94509:a7ddddfe9e36 parent: 94507:7dce0cbea210 parent: 94508:625798e94b14 user: Donald Stufft date: Wed Feb 04 22:00:56 2015 -0500 summary: Merge: Update pip to 6.0.8 files: Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl | Bin 3 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ _SETUPTOOLS_VERSION = "12.0.5" -_PIP_VERSION = "6.0.7" +_PIP_VERSION = "6.0.8" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl deleted file mode 100644 index e01e8c4f44fbf99d9cb286f5a06b6689ff29d4d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..be9238d94c10081b4450aad01851f4c4eda1897c GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 04:02:28 2015 From: python-checkins at python.org (donald.stufft) Date: Thu, 05 Feb 2015 03:02:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Update_pip_to_?= =?utf-8?b?Ni4wLjg=?= Message-ID: <20150205030217.39286.44606@psf.io> https://hg.python.org/cpython/rev/b658df02efa3 changeset: 94510:b658df02efa3 branch: 2.7 parent: 94495:887526ebb013 user: Donald Stufft date: Wed Feb 04 22:02:09 2015 -0500 summary: Update pip to 6.0.8 files: Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl | Bin 3 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -14,7 +14,7 @@ _SETUPTOOLS_VERSION = "12.0.5" -_PIP_VERSION = "6.0.7" +_PIP_VERSION = "6.0.8" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-6.0.7-py2.py3-none-any.whl deleted file mode 100644 index e01e8c4f44fbf99d9cb286f5a06b6689ff29d4d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-6.0.8-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..be9238d94c10081b4450aad01851f4c4eda1897c GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 04:07:09 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 05 Feb 2015 03:07:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_parenth?= =?utf-8?q?esis_from_print_statement_=28closes_=2323396=29?= Message-ID: <20150205030700.106285.25687@psf.io> https://hg.python.org/cpython/rev/2bb5fa752bfc changeset: 94511:2bb5fa752bfc branch: 2.7 user: Benjamin Peterson date: Wed Feb 04 22:06:55 2015 -0500 summary: remove parenthesis from print statement (closes #23396) files: Doc/tutorial/introduction.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -170,7 +170,7 @@ >>> print '"Isn\'t," she said.' "Isn't," she said. >>> s = 'First line.\nSecond line.' # \n means newline - >>> s # without print(), \n is included in the output + >>> s # without print, \n is included in the output 'First line.\nSecond line.' >>> print s # with print, \n produces a new line First line. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 07:25:47 2015 From: python-checkins at python.org (ned.deily) Date: Thu, 05 Feb 2015 06:25:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323345=3A_merge_from_3=2E4?= Message-ID: <20150205062539.96096.73252@psf.io> https://hg.python.org/cpython/rev/62b322b82f00 changeset: 94514:62b322b82f00 parent: 94509:a7ddddfe9e36 parent: 94513:52932cd7f003 user: Ned Deily date: Thu Feb 05 17:24:00 2015 +1100 summary: Issue #23345: merge from 3.4 files: Lib/test/test_ssl.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -306,7 +306,7 @@ self.assertGreaterEqual(fix, 0) self.assertLess(fix, 256) self.assertGreaterEqual(patch, 0) - self.assertLessEqual(patch, 26) + self.assertLessEqual(patch, 63) self.assertGreaterEqual(status, 0) self.assertLessEqual(status, 15) # Version string as returned by {Open,Libre}SSL, the format might change diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1727,6 +1727,9 @@ - Issue #23211: Workaround test_logging failure on some OS X 10.6 systems. +- Issue #23345: Prevent test_ssl failures with large OpenSSL patch level + values (like 0.9.8zc). + Tools/Demos ----------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 07:25:47 2015 From: python-checkins at python.org (ned.deily) Date: Thu, 05 Feb 2015 06:25:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzQ1?= =?utf-8?q?=3A_Prevent_test=5Fssl_failures_with_large_OpenSSL_patch_level?= Message-ID: <20150205062539.106389.62903@psf.io> https://hg.python.org/cpython/rev/52932cd7f003 changeset: 94513:52932cd7f003 branch: 3.4 parent: 94508:625798e94b14 user: Ned Deily date: Thu Feb 05 17:20:13 2015 +1100 summary: Issue #23345: Prevent test_ssl failures with large OpenSSL patch level values (like 0.9.8zc). files: Lib/test/test_ssl.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -292,7 +292,7 @@ self.assertGreaterEqual(fix, 0) self.assertLess(fix, 256) self.assertGreaterEqual(patch, 0) - self.assertLessEqual(patch, 26) + self.assertLessEqual(patch, 63) self.assertGreaterEqual(status, 0) self.assertLessEqual(status, 15) # Version string as returned by {Open,Libre}SSL, the format might change diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -340,6 +340,9 @@ - Issue #23211: Workaround test_logging failure on some OS X 10.6 systems. +- Issue #23345: Prevent test_ssl failures with large OpenSSL patch level + values (like 0.9.8zc). + Build ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 07:25:47 2015 From: python-checkins at python.org (ned.deily) Date: Thu, 05 Feb 2015 06:25:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzMzQ1?= =?utf-8?q?=3A_Prevent_test=5Fssl_failures_with_large_OpenSSL_patch_level?= Message-ID: <20150205062539.25841.70311@psf.io> https://hg.python.org/cpython/rev/49f07942fbd7 changeset: 94512:49f07942fbd7 branch: 2.7 user: Ned Deily date: Thu Feb 05 17:19:11 2015 +1100 summary: Issue #23345: Prevent test_ssl failures with large OpenSSL patch level values (like 0.9.8zc). files: Lib/test/test_ssl.py | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -275,7 +275,7 @@ self.assertGreaterEqual(fix, 0) self.assertLess(fix, 256) self.assertGreaterEqual(patch, 0) - self.assertLessEqual(patch, 26) + self.assertLessEqual(patch, 63) self.assertGreaterEqual(status, 0) self.assertLessEqual(status, 15) # Version string as returned by {Open,Libre}SSL, the format might change diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,9 @@ - Issue #18905: "pydoc -p 0" now outputs actually used port. Based on patch by Wieland Hoffmann. +- Issue #23345: Prevent test_ssl failures with large OpenSSL patch level + values (like 0.9.8zc). + Tests ----- -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Thu Feb 5 09:24:14 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 05 Feb 2015 09:24:14 +0100 Subject: [Python-checkins] Daily reference leaks (7dce0cbea210): sum=3 Message-ID: results for 7dce0cbea210 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogOdmBU0', '-x'] From python-checkins at python.org Thu Feb 5 11:47:34 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 05 Feb 2015 10:47:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20150205104720.34392.3245@psf.io> https://hg.python.org/cpython/rev/8ec13c088465 changeset: 94516:8ec13c088465 parent: 94514:62b322b82f00 parent: 94515:2e6972f1104d user: Victor Stinner date: Thu Feb 05 11:46:45 2015 +0100 summary: Merge 3.4 (asyncio) files: Lib/asyncio/base_events.py | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -188,7 +188,7 @@ self._internal_fds = 0 # Identifier of the thread running the event loop, or None if the # event loop is not running - self._owner = None + self._thread_id = None self._clock_resolution = time.get_clock_info('monotonic').resolution self._exception_handler = None self._debug = (not sys.flags.ignore_environment @@ -269,7 +269,7 @@ self._check_closed() if self.is_running(): raise RuntimeError('Event loop is running.') - self._owner = threading.get_ident() + self._thread_id = threading.get_ident() try: while True: try: @@ -277,7 +277,7 @@ except _StopError: break finally: - self._owner = None + self._thread_id = None def run_until_complete(self, future): """Run until the Future is done. @@ -362,7 +362,7 @@ def is_running(self): """Returns True if the event loop is running.""" - return (self._owner is not None) + return (self._thread_id is not None) def time(self): """Return the time according to the event loop's clock. @@ -449,10 +449,10 @@ Should only be called when (self._debug == True). The caller is responsible for checking this condition for performance reasons. """ - if self._owner is None: + if self._thread_id is None: return thread_id = threading.get_ident() - if thread_id != self._owner: + if thread_id != self._thread_id: raise RuntimeError( "Non-thread-safe operation invoked on an event loop other " "than the current one") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 11:47:34 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 05 Feb 2015 10:47:34 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogQmFz?= =?utf-8?q?eEventLoop=3A_rename_=5Fowner_to_=5Fthread=5Fid?= Message-ID: <20150205104720.25857.15593@psf.io> https://hg.python.org/cpython/rev/2e6972f1104d changeset: 94515:2e6972f1104d branch: 3.4 parent: 94513:52932cd7f003 user: Victor Stinner date: Thu Feb 05 11:45:33 2015 +0100 summary: asyncio: BaseEventLoop: rename _owner to _thread_id files: Lib/asyncio/base_events.py | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -188,7 +188,7 @@ self._internal_fds = 0 # Identifier of the thread running the event loop, or None if the # event loop is not running - self._owner = None + self._thread_id = None self._clock_resolution = time.get_clock_info('monotonic').resolution self._exception_handler = None self._debug = (not sys.flags.ignore_environment @@ -269,7 +269,7 @@ self._check_closed() if self.is_running(): raise RuntimeError('Event loop is running.') - self._owner = threading.get_ident() + self._thread_id = threading.get_ident() try: while True: try: @@ -277,7 +277,7 @@ except _StopError: break finally: - self._owner = None + self._thread_id = None def run_until_complete(self, future): """Run until the Future is done. @@ -362,7 +362,7 @@ def is_running(self): """Returns True if the event loop is running.""" - return (self._owner is not None) + return (self._thread_id is not None) def time(self): """Return the time according to the event loop's clock. @@ -449,10 +449,10 @@ Should only be called when (self._debug == True). The caller is responsible for checking this condition for performance reasons. """ - if self._owner is None: + if self._thread_id is None: return thread_id = threading.get_ident() - if thread_id != self._owner: + if thread_id != self._thread_id: raise RuntimeError( "Non-thread-safe operation invoked on an event loop other " "than the current one") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 14:19:44 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 05 Feb 2015 13:19:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4OTgy?= =?utf-8?q?=3A_Add_tests_for_CLI_of_the_calendar_module=2E?= Message-ID: <20150205131943.34410.49503@psf.io> https://hg.python.org/cpython/rev/50a5c262b2e6 changeset: 94519:50a5c262b2e6 branch: 2.7 parent: 94512:49f07942fbd7 user: Serhiy Storchaka date: Thu Feb 05 15:18:26 2015 +0200 summary: Issue #18982: Add tests for CLI of the calendar module. files: Lib/test/test_calendar.py | 135 +++++++++++++++++++++++++- Misc/NEWS | 2 + 2 files changed, 135 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -2,11 +2,22 @@ import unittest from test import test_support +from test.script_helper import assert_python_ok, assert_python_failure import locale import datetime +import os +result_2004_01_text = """\ + January 2004 +Mo Tu We Th Fr Sa Su + 1 2 3 4 + 5 6 7 8 9 10 11 +12 13 14 15 16 17 18 +19 20 21 22 23 24 25 +26 27 28 29 30 31 +""" -result_2004_text = """ +result_2004_text = """\ 2004 January February March @@ -44,7 +55,7 @@ 25 26 27 28 29 30 31 29 30 27 28 29 30 31 """ -result_2004_html = """ +result_2004_html = """\ @@ -460,6 +471,124 @@ self.assertEqual(calendar.leapdays(1997,2020), 5) +class CommandLineTestCase(unittest.TestCase): + def run_ok(self, *args): + return assert_python_ok('-m', 'calendar', *args)[1] + + def assertFailure(self, *args): + rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args) + self.assertIn(b'Usage:', stderr) + self.assertEqual(rc, 2) + + def test_help(self): + stdout = self.run_ok('-h') + self.assertIn(b'Usage:', stdout) + self.assertIn(b'calendar.py', stdout) + self.assertIn(b'--help', stdout) + + def test_illegal_arguments(self): + self.assertFailure('-z') + #self.assertFailure('spam') + #self.assertFailure('2004', 'spam') + self.assertFailure('-t', 'html', '2004', '1') + + def test_output_current_year(self): + stdout = self.run_ok() + year = datetime.datetime.now().year + self.assertIn((' %s' % year).encode(), stdout) + self.assertIn(b'January', stdout) + self.assertIn(b'Mo Tu We Th Fr Sa Su', stdout) + + def test_output_year(self): + stdout = self.run_ok('2004') + self.assertEqual(stdout.strip(), result_2004_text.strip()) + + def test_output_month(self): + stdout = self.run_ok('2004', '1') + self.assertEqual(stdout.strip(), result_2004_01_text.strip()) + + def test_option_encoding(self): + self.assertFailure('-e') + self.assertFailure('--encoding') + stdout = self.run_ok('--encoding', 'rot-13', '2004') + self.assertEqual(stdout.strip(), result_2004_text.encode('rot-13').strip()) + + def test_option_locale(self): + self.assertFailure('-L') + self.assertFailure('--locale') + self.assertFailure('-L', 'en') + lang, enc = locale.getdefaultlocale() + lang = lang or 'C' + enc = enc or 'UTF-8' + try: + oldlocale = locale.getlocale(locale.LC_TIME) + try: + locale.setlocale(locale.LC_TIME, (lang, enc)) + finally: + locale.setlocale(locale.LC_TIME, oldlocale) + except (locale.Error, ValueError): + self.skipTest('cannot set the system default locale') + stdout = self.run_ok('--locale', lang, '--encoding', enc, '2004') + self.assertIn('2004'.encode(enc), stdout) + + def test_option_width(self): + self.assertFailure('-w') + self.assertFailure('--width') + self.assertFailure('-w', 'spam') + stdout = self.run_ok('--width', '3', '2004') + self.assertIn(b'Mon Tue Wed Thu Fri Sat Sun', stdout) + + def test_option_lines(self): + self.assertFailure('-l') + self.assertFailure('--lines') + self.assertFailure('-l', 'spam') + stdout = self.run_ok('--lines', '2', '2004') + self.assertIn('December\n\nMo Tu We', stdout) + + def test_option_spacing(self): + self.assertFailure('-s') + self.assertFailure('--spacing') + self.assertFailure('-s', 'spam') + stdout = self.run_ok('--spacing', '8', '2004') + self.assertIn(b'Su Mo', stdout) + + def test_option_months(self): + self.assertFailure('-m') + self.assertFailure('--month') + self.assertFailure('-m', 'spam') + stdout = self.run_ok('--months', '1', '2004') + self.assertIn('\nMo Tu We Th Fr Sa Su\n', stdout) + + def test_option_type(self): + self.assertFailure('-t') + self.assertFailure('--type') + self.assertFailure('-t', 'spam') + stdout = self.run_ok('--type', 'text', '2004') + self.assertEqual(stdout.strip(), result_2004_text.strip()) + stdout = self.run_ok('--type', 'html', '2004') + self.assertEqual(stdout[:6], b'Calendar for 2004', stdout) + + def test_html_output_current_year(self): + stdout = self.run_ok('--type', 'html') + year = datetime.datetime.now().year + self.assertIn(('Calendar for %s' % year).encode(), + stdout) + self.assertIn(b'January', + stdout) + + def test_html_output_year_encoding(self): + stdout = self.run_ok('-t', 'html', '--encoding', 'ascii', '2004') + self.assertEqual(stdout.strip(), result_2004_html.strip()) + + def test_html_output_year_css(self): + self.assertFailure('-t', 'html', '-c') + self.assertFailure('-t', 'html', '--css') + stdout = self.run_ok('-t', 'html', '--css', 'custom.css', '2004') + self.assertIn(b'', stdout) + + def test_main(): test_support.run_unittest( OutputTestCase, @@ -468,8 +597,10 @@ SundayTestCase, MonthRangeTestCase, LeapdaysTestCase, + CommandLineTestCase, ) if __name__ == "__main__": test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,8 @@ Tests ----- +- Issue #18982: Add tests for CLI of the calendar module. + - Issue #19949: The test_xpickle test now tests compatibility with installed Python 2.7 and reports skipped tests. Based on patch by Zachary Ware. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 14:19:44 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 05 Feb 2015 13:19:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE4OTgy?= =?utf-8?q?=3A_Add_tests_for_CLI_of_the_calendar_module=2E?= Message-ID: <20150205131942.34388.33650@psf.io> https://hg.python.org/cpython/rev/28a9da0842aa changeset: 94517:28a9da0842aa branch: 3.4 parent: 94515:2e6972f1104d user: Serhiy Storchaka date: Thu Feb 05 15:14:35 2015 +0200 summary: Issue #18982: Add tests for CLI of the calendar module. files: Lib/test/test_calendar.py | 155 +++++++++++++++++++++---- Misc/NEWS | 2 + 2 files changed, 132 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -2,13 +2,14 @@ import unittest from test import support -from test.script_helper import assert_python_ok +from test.script_helper import assert_python_ok, assert_python_failure import time import locale import sys import datetime +import os -result_2004_01_text = """ +result_2004_01_text = """\ January 2004 Mo Tu We Th Fr Sa Su 1 2 3 4 @@ -18,7 +19,7 @@ 26 27 28 29 30 31 """ -result_2004_text = """ +result_2004_text = """\ 2004 January February March @@ -56,7 +57,7 @@ 25 26 27 28 29 30 31 29 30 27 28 29 30 31 """ -result_2004_html = """ +result_2004_html = """\ @@ -327,8 +328,8 @@ def check_htmlcalendar_encoding(self, req, res): cal = calendar.HTMLCalendar() self.assertEqual( - cal.formatyearpage(2004, encoding=req).strip(b' \t\n'), - (result_2004_html % {'e': res}).strip(' \t\n').encode(res) + cal.formatyearpage(2004, encoding=req), + (result_2004_html % {'e': res}).encode(res) ) def test_output(self): @@ -339,8 +340,8 @@ def test_output_textcalendar(self): self.assertEqual( - calendar.TextCalendar().formatyear(2004).strip(), - result_2004_text.strip() + calendar.TextCalendar().formatyear(2004), + result_2004_text ) def test_output_htmlcalendar_encoding_ascii(self): @@ -383,8 +384,8 @@ def test_formatmonth(self): self.assertEqual( - calendar.TextCalendar().formatmonth(2004, 1).strip(), - result_2004_01_text.strip() + calendar.TextCalendar().formatmonth(2004, 1), + result_2004_01_text ) def test_formatmonthname_with_year(self): @@ -692,23 +693,127 @@ self.assertEqual(calendar.leapdays(1997,2020), 5) -class ConsoleOutputTestCase(unittest.TestCase): - def test_outputs_bytes(self): - (return_code, stdout, stderr) = assert_python_ok('-m', 'calendar', '--type=html', '2010') +def conv(s): + return s.replace('\n', os.linesep).encode() + +class CommandLineTestCase(unittest.TestCase): + def run_ok(self, *args): + return assert_python_ok('-m', 'calendar', *args)[1] + + def assertFailure(self, *args): + rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args) + self.assertIn(b'Usage:', stderr) + self.assertEqual(rc, 2) + + def test_help(self): + stdout = self.run_ok('-h') + self.assertIn(b'Usage:', stdout) + self.assertIn(b'calendar.py', stdout) + self.assertIn(b'--help', stdout) + + def test_illegal_arguments(self): + self.assertFailure('-z') + #self.assertFailure('spam') + #self.assertFailure('2004', 'spam') + self.assertFailure('-t', 'html', '2004', '1') + + def test_output_current_year(self): + stdout = self.run_ok() + year = datetime.datetime.now().year + self.assertIn((' %s' % year).encode(), stdout) + self.assertIn(b'January', stdout) + self.assertIn(b'Mo Tu We Th Fr Sa Su', stdout) + + def test_output_year(self): + stdout = self.run_ok('2004') + self.assertEqual(stdout, conv(result_2004_text)) + + def test_output_month(self): + stdout = self.run_ok('2004', '1') + self.assertEqual(stdout, conv(result_2004_01_text)) + + def test_option_encoding(self): + self.assertFailure('-e') + self.assertFailure('--encoding') + stdout = self.run_ok('--encoding', 'utf-16-le', '2004') + self.assertEqual(stdout, result_2004_text.encode('utf-16-le')) + + def test_option_locale(self): + self.assertFailure('-L') + self.assertFailure('--locale') + self.assertFailure('-L', 'en') + lang, enc = locale.getdefaultlocale() + lang = lang or 'C' + enc = enc or 'UTF-8' + try: + oldlocale = locale.getlocale(locale.LC_TIME) + try: + locale.setlocale(locale.LC_TIME, (lang, enc)) + finally: + locale.setlocale(locale.LC_TIME, oldlocale) + except (locale.Error, ValueError): + self.skipTest('cannot set the system default locale') + stdout = self.run_ok('--locale', lang, '--encoding', enc, '2004') + self.assertIn('2004'.encode(enc), stdout) + + def test_option_width(self): + self.assertFailure('-w') + self.assertFailure('--width') + self.assertFailure('-w', 'spam') + stdout = self.run_ok('--width', '3', '2004') + self.assertIn(b'Mon Tue Wed Thu Fri Sat Sun', stdout) + + def test_option_lines(self): + self.assertFailure('-l') + self.assertFailure('--lines') + self.assertFailure('-l', 'spam') + stdout = self.run_ok('--lines', '2', '2004') + self.assertIn(conv('December\n\nMo Tu We'), stdout) + + def test_option_spacing(self): + self.assertFailure('-s') + self.assertFailure('--spacing') + self.assertFailure('-s', 'spam') + stdout = self.run_ok('--spacing', '8', '2004') + self.assertIn(b'Su Mo', stdout) + + def test_option_months(self): + self.assertFailure('-m') + self.assertFailure('--month') + self.assertFailure('-m', 'spam') + stdout = self.run_ok('--months', '1', '2004') + self.assertIn(conv('\nMo Tu We Th Fr Sa Su\n'), stdout) + + def test_option_type(self): + self.assertFailure('-t') + self.assertFailure('--type') + self.assertFailure('-t', 'spam') + stdout = self.run_ok('--type', 'text', '2004') + self.assertEqual(stdout, conv(result_2004_text)) + stdout = self.run_ok('--type', 'html', '2004') self.assertEqual(stdout[:6], b'Calendar for 2004', stdout) -def test_main(): - support.run_unittest( - OutputTestCase, - CalendarTestCase, - MondayTestCase, - SundayTestCase, - TimegmTestCase, - MonthRangeTestCase, - LeapdaysTestCase, - ConsoleOutputTestCase - ) + def test_html_output_current_year(self): + stdout = self.run_ok('--type', 'html') + year = datetime.datetime.now().year + self.assertIn(('Calendar for %s' % year).encode(), + stdout) + self.assertIn(b'January', + stdout) + + def test_html_output_year_encoding(self): + stdout = self.run_ok('-t', 'html', '--encoding', 'ascii', '2004') + self.assertEqual(stdout, + (result_2004_html % {'e': 'ascii'}).encode('ascii')) + + def test_html_output_year_css(self): + self.assertFailure('-t', 'html', '-c') + self.assertFailure('-t', 'html', '--css') + stdout = self.run_ok('-t', 'html', '--css', 'custom.css', '2004') + self.assertIn(b'', stdout) if __name__ == "__main__": - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -323,6 +323,8 @@ Tests ----- +- Issue #18982: Add tests for CLI of the calendar module. + - Issue #19548: Added some additional checks to test_codecs to ensure that statements in the updated documentation remain accurate. Patch by Martin Panter. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 14:19:44 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 05 Feb 2015 13:19:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318982=3A_Add_tests_for_CLI_of_the_calendar_modu?= =?utf-8?b?bGUu?= Message-ID: <20150205131943.96070.91480@psf.io> https://hg.python.org/cpython/rev/e057da873673 changeset: 94518:e057da873673 parent: 94516:8ec13c088465 parent: 94517:28a9da0842aa user: Serhiy Storchaka date: Thu Feb 05 15:17:49 2015 +0200 summary: Issue #18982: Add tests for CLI of the calendar module. files: Lib/test/test_calendar.py | 155 +++++++++++++++++++++---- Misc/NEWS | 2 + 2 files changed, 132 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -2,13 +2,14 @@ import unittest from test import support -from test.script_helper import assert_python_ok +from test.script_helper import assert_python_ok, assert_python_failure import time import locale import sys import datetime +import os -result_2004_01_text = """ +result_2004_01_text = """\ January 2004 Mo Tu We Th Fr Sa Su 1 2 3 4 @@ -18,7 +19,7 @@ 26 27 28 29 30 31 """ -result_2004_text = """ +result_2004_text = """\ 2004 January February March @@ -56,7 +57,7 @@ 25 26 27 28 29 30 31 29 30 27 28 29 30 31 """ -result_2004_html = """ +result_2004_html = """\ @@ -327,8 +328,8 @@ def check_htmlcalendar_encoding(self, req, res): cal = calendar.HTMLCalendar() self.assertEqual( - cal.formatyearpage(2004, encoding=req).strip(b' \t\n'), - (result_2004_html % {'e': res}).strip(' \t\n').encode(res) + cal.formatyearpage(2004, encoding=req), + (result_2004_html % {'e': res}).encode(res) ) def test_output(self): @@ -339,8 +340,8 @@ def test_output_textcalendar(self): self.assertEqual( - calendar.TextCalendar().formatyear(2004).strip(), - result_2004_text.strip() + calendar.TextCalendar().formatyear(2004), + result_2004_text ) def test_output_htmlcalendar_encoding_ascii(self): @@ -383,8 +384,8 @@ def test_formatmonth(self): self.assertEqual( - calendar.TextCalendar().formatmonth(2004, 1).strip(), - result_2004_01_text.strip() + calendar.TextCalendar().formatmonth(2004, 1), + result_2004_01_text ) def test_formatmonthname_with_year(self): @@ -692,23 +693,127 @@ self.assertEqual(calendar.leapdays(1997,2020), 5) -class ConsoleOutputTestCase(unittest.TestCase): - def test_outputs_bytes(self): - (return_code, stdout, stderr) = assert_python_ok('-m', 'calendar', '--type=html', '2010') +def conv(s): + return s.replace('\n', os.linesep).encode() + +class CommandLineTestCase(unittest.TestCase): + def run_ok(self, *args): + return assert_python_ok('-m', 'calendar', *args)[1] + + def assertFailure(self, *args): + rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args) + self.assertIn(b'Usage:', stderr) + self.assertEqual(rc, 2) + + def test_help(self): + stdout = self.run_ok('-h') + self.assertIn(b'Usage:', stdout) + self.assertIn(b'calendar.py', stdout) + self.assertIn(b'--help', stdout) + + def test_illegal_arguments(self): + self.assertFailure('-z') + #self.assertFailure('spam') + #self.assertFailure('2004', 'spam') + self.assertFailure('-t', 'html', '2004', '1') + + def test_output_current_year(self): + stdout = self.run_ok() + year = datetime.datetime.now().year + self.assertIn((' %s' % year).encode(), stdout) + self.assertIn(b'January', stdout) + self.assertIn(b'Mo Tu We Th Fr Sa Su', stdout) + + def test_output_year(self): + stdout = self.run_ok('2004') + self.assertEqual(stdout, conv(result_2004_text)) + + def test_output_month(self): + stdout = self.run_ok('2004', '1') + self.assertEqual(stdout, conv(result_2004_01_text)) + + def test_option_encoding(self): + self.assertFailure('-e') + self.assertFailure('--encoding') + stdout = self.run_ok('--encoding', 'utf-16-le', '2004') + self.assertEqual(stdout, result_2004_text.encode('utf-16-le')) + + def test_option_locale(self): + self.assertFailure('-L') + self.assertFailure('--locale') + self.assertFailure('-L', 'en') + lang, enc = locale.getdefaultlocale() + lang = lang or 'C' + enc = enc or 'UTF-8' + try: + oldlocale = locale.getlocale(locale.LC_TIME) + try: + locale.setlocale(locale.LC_TIME, (lang, enc)) + finally: + locale.setlocale(locale.LC_TIME, oldlocale) + except (locale.Error, ValueError): + self.skipTest('cannot set the system default locale') + stdout = self.run_ok('--locale', lang, '--encoding', enc, '2004') + self.assertIn('2004'.encode(enc), stdout) + + def test_option_width(self): + self.assertFailure('-w') + self.assertFailure('--width') + self.assertFailure('-w', 'spam') + stdout = self.run_ok('--width', '3', '2004') + self.assertIn(b'Mon Tue Wed Thu Fri Sat Sun', stdout) + + def test_option_lines(self): + self.assertFailure('-l') + self.assertFailure('--lines') + self.assertFailure('-l', 'spam') + stdout = self.run_ok('--lines', '2', '2004') + self.assertIn(conv('December\n\nMo Tu We'), stdout) + + def test_option_spacing(self): + self.assertFailure('-s') + self.assertFailure('--spacing') + self.assertFailure('-s', 'spam') + stdout = self.run_ok('--spacing', '8', '2004') + self.assertIn(b'Su Mo', stdout) + + def test_option_months(self): + self.assertFailure('-m') + self.assertFailure('--month') + self.assertFailure('-m', 'spam') + stdout = self.run_ok('--months', '1', '2004') + self.assertIn(conv('\nMo Tu We Th Fr Sa Su\n'), stdout) + + def test_option_type(self): + self.assertFailure('-t') + self.assertFailure('--type') + self.assertFailure('-t', 'spam') + stdout = self.run_ok('--type', 'text', '2004') + self.assertEqual(stdout, conv(result_2004_text)) + stdout = self.run_ok('--type', 'html', '2004') self.assertEqual(stdout[:6], b'Calendar for 2004', stdout) -def test_main(): - support.run_unittest( - OutputTestCase, - CalendarTestCase, - MondayTestCase, - SundayTestCase, - TimegmTestCase, - MonthRangeTestCase, - LeapdaysTestCase, - ConsoleOutputTestCase - ) + def test_html_output_current_year(self): + stdout = self.run_ok('--type', 'html') + year = datetime.datetime.now().year + self.assertIn(('Calendar for %s' % year).encode(), + stdout) + self.assertIn(b'January', + stdout) + + def test_html_output_year_encoding(self): + stdout = self.run_ok('-t', 'html', '--encoding', 'ascii', '2004') + self.assertEqual(stdout, + (result_2004_html % {'e': 'ascii'}).encode('ascii')) + + def test_html_output_year_css(self): + self.assertFailure('-t', 'html', '-c') + self.assertFailure('-t', 'html', '--css') + stdout = self.run_ok('-t', 'html', '--css', 'custom.css', '2004') + self.assertIn(b'', stdout) if __name__ == "__main__": - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1629,6 +1629,8 @@ Tests ----- +- Issue #18982: Add tests for CLI of the calendar module. + - Issue #19548: Added some additional checks to test_codecs to ensure that statements in the updated documentation remain accurate. Patch by Martin Panter. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 14:26:13 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 05 Feb 2015 13:26:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogdGVzdF9tdWx0aXBy?= =?utf-8?q?ocessing=3A_tolerate_a_delta_of_30_ms_because_of_bad_clock_reso?= =?utf-8?q?lution?= Message-ID: <20150205132607.106307.75854@psf.io> https://hg.python.org/cpython/rev/a436592e60ae changeset: 94520:a436592e60ae branch: 3.4 parent: 94517:28a9da0842aa user: Victor Stinner date: Thu Feb 05 14:25:05 2015 +0100 summary: test_multiprocessing: tolerate a delta of 30 ms because of bad clock resolution on Windows files: Lib/test/_test_multiprocessing.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -716,9 +716,11 @@ def test_timeout(self): q = multiprocessing.Queue() start = time.time() - self.assertRaises(pyqueue.Empty, q.get, True, 0.2) + self.assertRaises(pyqueue.Empty, q.get, True, 0.200) delta = time.time() - start - self.assertGreaterEqual(delta, 0.18) + # Tolerate a delta of 30 ms because of the bad clock resolution on + # Windows (usually 15.6 ms) + self.assertGreaterEqual(delta, 0.170) # # -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 14:26:14 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 05 Feb 2015 13:26:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E4=29_test=5Fmultiprocessing=3A_tolerate_a_d?= =?utf-8?q?elta_of_30_ms_because_of_bad?= Message-ID: <20150205132607.96084.46219@psf.io> https://hg.python.org/cpython/rev/494376ec13d9 changeset: 94521:494376ec13d9 parent: 94518:e057da873673 parent: 94520:a436592e60ae user: Victor Stinner date: Thu Feb 05 14:25:53 2015 +0100 summary: (Merge 3.4) test_multiprocessing: tolerate a delta of 30 ms because of bad clock resolution on Windows files: Lib/test/_test_multiprocessing.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -716,9 +716,11 @@ def test_timeout(self): q = multiprocessing.Queue() start = time.time() - self.assertRaises(pyqueue.Empty, q.get, True, 0.2) + self.assertRaises(pyqueue.Empty, q.get, True, 0.200) delta = time.time() - start - self.assertGreaterEqual(delta, 0.18) + # Tolerate a delta of 30 ms because of the bad clock resolution on + # Windows (usually 15.6 ms) + self.assertGreaterEqual(delta, 0.170) # # -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 5 17:04:41 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 05 Feb 2015 16:04:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4OTgy?= =?utf-8?q?=3A_Fixed_newlines_in_calendar_CLI_tests_on_Windows=2E?= Message-ID: <20150205160410.106379.90846@psf.io> https://hg.python.org/cpython/rev/f2991b52157e changeset: 94522:f2991b52157e branch: 2.7 parent: 94519:50a5c262b2e6 user: Serhiy Storchaka date: Thu Feb 05 18:03:27 2015 +0200 summary: Issue #18982: Fixed newlines in calendar CLI tests on Windows. files: Lib/test/test_calendar.py | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -471,6 +471,9 @@ self.assertEqual(calendar.leapdays(1997,2020), 5) +def conv(s): + return s.replace('\n', os.linesep) + class CommandLineTestCase(unittest.TestCase): def run_ok(self, *args): return assert_python_ok('-m', 'calendar', *args)[1] @@ -501,17 +504,17 @@ def test_output_year(self): stdout = self.run_ok('2004') - self.assertEqual(stdout.strip(), result_2004_text.strip()) + self.assertEqual(stdout.strip(), conv(result_2004_text).strip()) def test_output_month(self): stdout = self.run_ok('2004', '1') - self.assertEqual(stdout.strip(), result_2004_01_text.strip()) + self.assertEqual(stdout.strip(), conv(result_2004_01_text).strip()) def test_option_encoding(self): self.assertFailure('-e') self.assertFailure('--encoding') stdout = self.run_ok('--encoding', 'rot-13', '2004') - self.assertEqual(stdout.strip(), result_2004_text.encode('rot-13').strip()) + self.assertEqual(stdout.strip(), conv(result_2004_text.encode('rot-13')).strip()) def test_option_locale(self): self.assertFailure('-L') @@ -543,7 +546,7 @@ self.assertFailure('--lines') self.assertFailure('-l', 'spam') stdout = self.run_ok('--lines', '2', '2004') - self.assertIn('December\n\nMo Tu We', stdout) + self.assertIn(conv('December\n\nMo Tu We'), stdout) def test_option_spacing(self): self.assertFailure('-s') @@ -557,14 +560,14 @@ self.assertFailure('--month') self.assertFailure('-m', 'spam') stdout = self.run_ok('--months', '1', '2004') - self.assertIn('\nMo Tu We Th Fr Sa Su\n', stdout) + self.assertIn(conv('\nMo Tu We Th Fr Sa Su\n'), stdout) def test_option_type(self): self.assertFailure('-t') self.assertFailure('--type') self.assertFailure('-t', 'spam') stdout = self.run_ok('--type', 'text', '2004') - self.assertEqual(stdout.strip(), result_2004_text.strip()) + self.assertEqual(stdout.strip(), conv(result_2004_text).strip()) stdout = self.run_ok('--type', 'html', '2004') self.assertEqual(stdout[:6], b'Calendar for 2004', stdout) @@ -579,7 +582,7 @@ def test_html_output_year_encoding(self): stdout = self.run_ok('-t', 'html', '--encoding', 'ascii', '2004') - self.assertEqual(stdout.strip(), result_2004_html.strip()) + self.assertEqual(stdout.strip(), conv(result_2004_html).strip()) def test_html_output_year_css(self): self.assertFailure('-t', 'html', '-c') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 04:17:13 2015 From: python-checkins at python.org (ned.deily) Date: Fri, 06 Feb 2015 03:17:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323212=3A_merge_from_3=2E4?= Message-ID: <20150206031711.96082.49572@psf.io> https://hg.python.org/cpython/rev/aeba7274d68a changeset: 94525:aeba7274d68a parent: 94521:494376ec13d9 parent: 94524:1ddf68f118c7 user: Ned Deily date: Fri Feb 06 14:16:29 2015 +1100 summary: Issue #23212: merge from 3.4 files: Mac/BuildScript/build-installer.py | 6 +++--- Misc/NEWS | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.1k", - url="https://www.openssl.org/source/openssl-1.0.1k.tar.gz", - checksum='d4f002bd22a56881340105028842ae1f', + name="OpenSSL 1.0.1l", + url="https://www.openssl.org/source/openssl-1.0.1l.tar.gz", + checksum='cdb22925fc9bc97ccbf1e007661f2aa6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1555,7 +1555,7 @@ - Issue #21236: Build _msi.pyd with cabinet.lib instead of fci.lib -- Issue #17128: Use private version of OpenSSL for 2.7.9 OS X 10.5+ installer. +- Issue #17128: Use private version of OpenSSL for OS X 10.5+ installer. C API ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 04:17:14 2015 From: python-checkins at python.org (ned.deily) Date: Fri, 06 Feb 2015 03:17:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMjEy?= =?utf-8?q?=3A_Update_OS_X_installer_build_OpenSSL_to_1=2E0=2E1l=2E?= Message-ID: <20150206031711.39282.14642@psf.io> https://hg.python.org/cpython/rev/1ddf68f118c7 changeset: 94524:1ddf68f118c7 branch: 3.4 parent: 94520:a436592e60ae user: Ned Deily date: Fri Feb 06 14:13:30 2015 +1100 summary: Issue #23212: Update OS X installer build OpenSSL to 1.0.1l. (currently only used for builds with <= 10.5 deployment targets) files: Mac/BuildScript/build-installer.py | 6 +++--- Misc/NEWS | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.1k", - url="https://www.openssl.org/source/openssl-1.0.1k.tar.gz", - checksum='d4f002bd22a56881340105028842ae1f', + name="OpenSSL 1.0.1l", + url="https://www.openssl.org/source/openssl-1.0.1l.tar.gz", + checksum='cdb22925fc9bc97ccbf1e007661f2aa6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -361,7 +361,7 @@ - Issue #17219: Add library build dir for Python extension cross-builds. -- Issue #17128: Use private version of OpenSSL for 2.7.9 OS X 10.5+ installer. +- Issue #17128: Use private version of OpenSSL for 3.4.3 OS X 10.5+ installer. C API ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 04:17:13 2015 From: python-checkins at python.org (ned.deily) Date: Fri, 06 Feb 2015 03:17:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzMjEy?= =?utf-8?q?=3A_Update_OS_X_installer_build_OpenSSL_to_1=2E0=2E1l=2E?= Message-ID: <20150206031710.25861.31220@psf.io> https://hg.python.org/cpython/rev/7b74c65758ca changeset: 94523:7b74c65758ca branch: 2.7 user: Ned Deily date: Fri Feb 06 14:11:36 2015 +1100 summary: Issue #23212: Update OS X installer build OpenSSL to 1.0.1l. (currently only used for builds with <= 10.5 deployment targets) files: Mac/BuildScript/build-installer.py | 6 +++--- Misc/NEWS | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -237,9 +237,9 @@ result.extend([ dict( - name="OpenSSL 1.0.1k", - url="https://www.openssl.org/source/openssl-1.0.1k.tar.gz", - checksum='d4f002bd22a56881340105028842ae1f', + name="OpenSSL 1.0.1l", + url="https://www.openssl.org/source/openssl-1.0.1l.tar.gz", + checksum='cdb22925fc9bc97ccbf1e007661f2aa6', patches=[ "openssl_sdk_makedepend.patch", ], diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,7 +130,7 @@ - Issue #23032: Fix installer build failures on OS X 10.4 Tiger by disabling assembly code in the OpenSSL build. -- Issue #23212: Update 10.5 OS X installer build to use OpenSSL 1.0.1k. +- Issue #23212: Update 10.5 OS X installer build to use OpenSSL 1.0.1l. C API ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 04:31:01 2015 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 06 Feb 2015 03:31:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI3MzUp?= Message-ID: <20150206033056.25861.97131@psf.io> https://hg.python.org/cpython/rev/75fd0bd89eef changeset: 94527:75fd0bd89eef parent: 94525:aeba7274d68a parent: 94526:6384c0cd3b2d user: Benjamin Peterson date: Thu Feb 05 22:29:46 2015 -0500 summary: merge 3.4 (#22735) files: Lib/test/test_descr.py | 227 +++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + Objects/typeobject.c | 699 +++++++++++++++++----------- 4 files changed, 649 insertions(+), 281 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -5057,11 +5057,236 @@ self.assertLess(sys.getsizeof(vars(b)), sys.getsizeof({})) +class DebugHelperMeta(type): + """ + Sets default __doc__ and simplifies repr() output. + """ + def __new__(mcls, name, bases, attrs): + if attrs.get('__doc__') is None: + attrs['__doc__'] = name # helps when debugging with gdb + return type.__new__(mcls, name, bases, attrs) + def __repr__(cls): + return repr(cls.__name__) + + +class MroTest(unittest.TestCase): + """ + Regressions for some bugs revealed through + mcsl.mro() customization (typeobject.c: mro_internal()) and + cls.__bases__ assignment (typeobject.c: type_set_bases()). + """ + + def setUp(self): + self.step = 0 + self.ready = False + + def step_until(self, limit): + ret = (self.step < limit) + if ret: + self.step += 1 + return ret + + def test_incomplete_set_bases_on_self(self): + """ + type_set_bases must be aware that type->tp_mro can be NULL. + """ + class M(DebugHelperMeta): + def mro(cls): + if self.step_until(1): + assert cls.__mro__ is None + cls.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + + def test_reent_set_bases_on_base(self): + """ + Deep reentrancy must not over-decref old_mro. + """ + class M(DebugHelperMeta): + def mro(cls): + if cls.__mro__ is not None and cls.__name__ == 'B': + # 4-5 steps are usually enough to make it crash somewhere + if self.step_until(10): + A.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + class B(A): + pass + B.__bases__ += () + + def test_reent_set_bases_on_direct_base(self): + """ + Similar to test_reent_set_bases_on_base, but may crash differently. + """ + class M(DebugHelperMeta): + def mro(cls): + base = cls.__bases__[0] + if base is not object: + if self.step_until(5): + base.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + class B(A): + pass + class C(B): + pass + + def test_reent_set_bases_tp_base_cycle(self): + """ + type_set_bases must check for an inheritance cycle not only through + MRO of the type, which may be not yet updated in case of reentrance, + but also through tp_base chain, which is assigned before diving into + inner calls to mro(). + + Otherwise, the following snippet can loop forever: + do { + // ... + type = type->tp_base; + } while (type != NULL); + + Functions that rely on tp_base (like solid_base and PyType_IsSubtype) + would not be happy in that case, causing a stack overflow. + """ + class M(DebugHelperMeta): + def mro(cls): + if self.ready: + if cls.__name__ == 'B1': + B2.__bases__ = (B1,) + if cls.__name__ == 'B2': + B1.__bases__ = (B2,) + return type.mro(cls) + + class A(metaclass=M): + pass + class B1(A): + pass + class B2(A): + pass + + self.ready = True + with self.assertRaises(TypeError): + B1.__bases__ += () + + def test_tp_subclasses_cycle_in_update_slots(self): + """ + type_set_bases must check for reentrancy upon finishing its job + by updating tp_subclasses of old/new bases of the type. + Otherwise, an implicit inheritance cycle through tp_subclasses + can break functions that recurse on elements of that field + (like recurse_down_subclasses and mro_hierarchy) eventually + leading to a stack overflow. + """ + class M(DebugHelperMeta): + def mro(cls): + if self.ready and cls.__name__ == 'C': + self.ready = False + C.__bases__ = (B2,) + return type.mro(cls) + + class A(metaclass=M): + pass + class B1(A): + pass + class B2(A): + pass + class C(A): + pass + + self.ready = True + C.__bases__ = (B1,) + B1.__bases__ = (C,) + + self.assertEqual(C.__bases__, (B2,)) + self.assertEqual(B2.__subclasses__(), [C]) + self.assertEqual(B1.__subclasses__(), []) + + self.assertEqual(B1.__bases__, (C,)) + self.assertEqual(C.__subclasses__(), [B1]) + + def test_tp_subclasses_cycle_error_return_path(self): + """ + The same as test_tp_subclasses_cycle_in_update_slots, but tests + a code path executed on error (goto bail). + """ + class E(Exception): + pass + class M(DebugHelperMeta): + def mro(cls): + if self.ready and cls.__name__ == 'C': + if C.__bases__ == (B2,): + self.ready = False + else: + C.__bases__ = (B2,) + raise E + return type.mro(cls) + + class A(metaclass=M): + pass + class B1(A): + pass + class B2(A): + pass + class C(A): + pass + + self.ready = True + with self.assertRaises(E): + C.__bases__ = (B1,) + B1.__bases__ = (C,) + + self.assertEqual(C.__bases__, (B2,)) + self.assertEqual(C.__mro__, tuple(type.mro(C))) + + def test_incomplete_extend(self): + """ + Extending an unitialized type with type->tp_mro == NULL must + throw a reasonable TypeError exception, instead of failing + with PyErr_BadInternalCall. + """ + class M(DebugHelperMeta): + def mro(cls): + if cls.__mro__ is None and cls.__name__ != 'X': + with self.assertRaises(TypeError): + class X(cls): + pass + + return type.mro(cls) + + class A(metaclass=M): + pass + + def test_incomplete_super(self): + """ + Attrubute lookup on a super object must be aware that + its target type can be uninitialized (type->tp_mro == NULL). + """ + class M(DebugHelperMeta): + def mro(cls): + if cls.__mro__ is None: + with self.assertRaises(AttributeError): + super(cls, cls).xxx + + return type.mro(cls) + + class A(metaclass=M): + pass + + def test_main(): # Run all local test cases, with PTypesLongInitTest first. support.run_unittest(PTypesLongInitTest, OperatorsTest, ClassPropertiesAndMethods, DictProxyTests, - MiscTests, PicklingTests, SharedKeyTests) + MiscTests, PicklingTests, SharedKeyTests, + MroTest) if __name__ == "__main__": test_main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -16,6 +16,7 @@ Rajiv Abraham David Abrahams Marc Abramowitz +Eldar Abusalimov Ron Adam Anton Afanasyev Ali Afshar diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #22735: Fix many edge cases (including crashes) involving custom mro() + implementations. + - Issue #22896: Avoid using PyObject_AsCharBuffer(), PyObject_AsReadBuffer() and PyObject_AsWriteBuffer(). diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -564,9 +564,11 @@ } static PyTypeObject *best_base(PyObject *); -static int mro_internal(PyTypeObject *); +static int mro_internal(PyTypeObject *, PyObject **); +static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); static int add_subclass(PyTypeObject*, PyTypeObject*); +static int add_all_subclasses(PyTypeObject *type, PyObject *bases); static void remove_subclass(PyTypeObject *, PyTypeObject *); static void remove_all_subclasses(PyTypeObject *type, PyObject *bases); static void update_all_slots(PyTypeObject *); @@ -576,167 +578,194 @@ update_callback callback, void *data); static int recurse_down_subclasses(PyTypeObject *type, PyObject *name, update_callback callback, void *data); +static PyObject *type_subclasses(PyTypeObject *type, PyObject *ignored); static int -mro_subclasses(PyTypeObject *type, PyObject* temp) -{ - PyTypeObject *subclass; - PyObject *ref, *subclasses, *old_mro; +mro_hierarchy(PyTypeObject *type, PyObject *temp) +{ + int res; + PyObject *new_mro, *old_mro; + PyObject *tuple; + PyObject *subclasses; + Py_ssize_t i, n; + + res = mro_internal(type, &old_mro); + if (res <= 0) + /* error / reentrance */ + return res; + new_mro = type->tp_mro; + + if (old_mro != NULL) + tuple = PyTuple_Pack(3, type, new_mro, old_mro); + else + tuple = PyTuple_Pack(2, type, new_mro); + + if (tuple != NULL) + res = PyList_Append(temp, tuple); + else + res = -1; + Py_XDECREF(tuple); + + if (res < 0) { + type->tp_mro = old_mro; + Py_DECREF(new_mro); + return -1; + } + Py_XDECREF(old_mro); + + /* Obtain a copy of subclasses list to iterate over. + + Otherwise type->tp_subclasses might be altered + in the middle of the loop, for example, through a custom mro(), + by invoking type_set_bases on some subclass of the type + which in turn calls remove_subclass/add_subclass on this type. + + Finally, this makes things simple avoiding the need to deal + with dictionary iterators and weak references. + */ + subclasses = type_subclasses(type, NULL); + if (subclasses == NULL) + return -1; + n = PyList_GET_SIZE(subclasses); + for (i = 0; i < n; i++) { + PyTypeObject *subclass; + subclass = (PyTypeObject *)PyList_GET_ITEM(subclasses, i); + res = mro_hierarchy(subclass, temp); + if (res < 0) + break; + } + Py_DECREF(subclasses); + + return res; +} + +static int +type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) +{ + int res = 0; + PyObject *temp; + PyObject *old_bases; + PyTypeObject *new_base, *old_base; Py_ssize_t i; - subclasses = type->tp_subclasses; - if (subclasses == NULL) - return 0; - assert(PyDict_CheckExact(subclasses)); - i = 0; - - while (PyDict_Next(subclasses, &i, NULL, &ref)) { - assert(PyWeakref_CheckRef(ref)); - subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); - assert(subclass != NULL); - if ((PyObject *)subclass == Py_None) - continue; - assert(PyType_Check(subclass)); - old_mro = subclass->tp_mro; - if (mro_internal(subclass) < 0) { - subclass->tp_mro = old_mro; - return -1; - } - else { - PyObject* tuple; - tuple = PyTuple_Pack(2, subclass, old_mro); - Py_DECREF(old_mro); - if (!tuple) - return -1; - if (PyList_Append(temp, tuple) < 0) - return -1; - Py_DECREF(tuple); - } - if (mro_subclasses(subclass, temp) < 0) - return -1; - } - return 0; -} - -static int -type_set_bases(PyTypeObject *type, PyObject *value, void *context) -{ - Py_ssize_t i; - int r = 0; - PyObject *ob, *temp; - PyTypeObject *new_base, *old_base; - PyObject *old_bases, *old_mro; - - if (!check_set_special_type_attr(type, value, "__bases__")) + if (!check_set_special_type_attr(type, new_bases, "__bases__")) return -1; - if (!PyTuple_Check(value)) { + if (!PyTuple_Check(new_bases)) { PyErr_Format(PyExc_TypeError, "can only assign tuple to %s.__bases__, not %s", - type->tp_name, Py_TYPE(value)->tp_name); + type->tp_name, Py_TYPE(new_bases)->tp_name); return -1; } - if (PyTuple_GET_SIZE(value) == 0) { + if (PyTuple_GET_SIZE(new_bases) == 0) { PyErr_Format(PyExc_TypeError, "can only assign non-empty tuple to %s.__bases__, not ()", type->tp_name); return -1; } - for (i = 0; i < PyTuple_GET_SIZE(value); i++) { - ob = PyTuple_GET_ITEM(value, i); + for (i = 0; i < PyTuple_GET_SIZE(new_bases); i++) { + PyObject *ob; + PyTypeObject *base; + + ob = PyTuple_GET_ITEM(new_bases, i); if (!PyType_Check(ob)) { PyErr_Format(PyExc_TypeError, "%s.__bases__ must be tuple of classes, not '%s'", type->tp_name, Py_TYPE(ob)->tp_name); return -1; } - if (PyType_IsSubtype((PyTypeObject*)ob, type)) { + + base = (PyTypeObject*)ob; + if (PyType_IsSubtype(base, type) || + /* In case of reentering here again through a custom mro() + the above check is not enough since it relies on + base->tp_mro which would gonna be updated inside + mro_internal only upon returning from the mro(). + + However, base->tp_base has already been assigned (see + below), which in turn may cause an inheritance cycle + through tp_base chain. And this is definitely + not what you want to ever happen. */ + (base->tp_mro != NULL && type_is_subtype_base_chain(base, type))) { + PyErr_SetString(PyExc_TypeError, "a __bases__ item causes an inheritance cycle"); return -1; } } - new_base = best_base(value); - - if (!new_base) + new_base = best_base(new_bases); + if (new_base == NULL) return -1; if (!compatible_for_assignment(type->tp_base, new_base, "__bases__")) return -1; + Py_INCREF(new_bases); Py_INCREF(new_base); - Py_INCREF(value); old_bases = type->tp_bases; old_base = type->tp_base; - old_mro = type->tp_mro; - - type->tp_bases = value; + + type->tp_bases = new_bases; type->tp_base = new_base; - if (mro_internal(type) < 0) { + temp = PyList_New(0); + if (temp == NULL) goto bail; - } - - temp = PyList_New(0); - if (!temp) - goto bail; - - r = mro_subclasses(type, temp); - - if (r < 0) { - for (i = 0; i < PyList_Size(temp); i++) { - PyTypeObject* cls; - PyObject* mro; - PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), - "", 2, 2, &cls, &mro); - Py_INCREF(mro); - ob = cls->tp_mro; - cls->tp_mro = mro; - Py_DECREF(ob); - } - Py_DECREF(temp); - goto bail; - } - + if (mro_hierarchy(type, temp) < 0) + goto undo; Py_DECREF(temp); - /* any base that was in __bases__ but now isn't, we - need to remove |type| from its tp_subclasses. - conversely, any class now in __bases__ that wasn't - needs to have |type| added to its subclasses. */ - - /* for now, sod that: just remove from all old_bases, - add to all new_bases */ - - remove_all_subclasses(type, old_bases); - - for (i = PyTuple_GET_SIZE(value) - 1; i >= 0; i--) { - ob = PyTuple_GET_ITEM(value, i); - if (PyType_Check(ob)) { - if (add_subclass((PyTypeObject*)ob, type) < 0) - r = -1; - } - } - - update_all_slots(type); + /* Take no action in case if type->tp_bases has been replaced + through reentrance. */ + if (type->tp_bases == new_bases) { + /* any base that was in __bases__ but now isn't, we + need to remove |type| from its tp_subclasses. + conversely, any class now in __bases__ that wasn't + needs to have |type| added to its subclasses. */ + + /* for now, sod that: just remove from all old_bases, + add to all new_bases */ + remove_all_subclasses(type, old_bases); + res = add_all_subclasses(type, new_bases); + update_all_slots(type); + } Py_DECREF(old_bases); Py_DECREF(old_base); - Py_DECREF(old_mro); - - return r; + + return res; + + undo: + for (i = PyList_GET_SIZE(temp) - 1; i >= 0; i--) { + PyTypeObject *cls; + PyObject *new_mro, *old_mro = NULL; + + PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), + "", 2, 3, &cls, &new_mro, &old_mro); + /* Do not rollback if cls has a newer version of MRO. */ + if (cls->tp_mro == new_mro) { + Py_XINCREF(old_mro); + cls->tp_mro = old_mro; + Py_DECREF(new_mro); + } + } + Py_DECREF(temp); bail: - Py_DECREF(type->tp_bases); - Py_DECREF(type->tp_base); - if (type->tp_mro != old_mro) { - Py_DECREF(type->tp_mro); - } - - type->tp_bases = old_bases; - type->tp_base = old_base; - type->tp_mro = old_mro; + if (type->tp_bases == new_bases) { + assert(type->tp_base == new_base); + + type->tp_bases = old_bases; + type->tp_base = old_base; + + Py_DECREF(new_bases); + Py_DECREF(new_base); + } + else { + Py_DECREF(old_bases); + Py_DECREF(old_base); + } return -1; } @@ -1312,6 +1341,18 @@ /* type test with subclassing support */ +Py_LOCAL_INLINE(int) +type_is_subtype_base_chain(PyTypeObject *a, PyTypeObject *b) +{ + do { + if (a == b) + return 1; + a = a->tp_base; + } while (a != NULL); + + return (b == &PyBaseObject_Type); +} + int PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) { @@ -1330,15 +1371,9 @@ } return 0; } - else { + else /* a is not completely initilized yet; follow tp_base */ - do { - if (a == b) - return 1; - a = a->tp_base; - } while (a != NULL); - return b == &PyBaseObject_Type; - } + return type_is_subtype_base_chain(a, b); } /* Internal routines to do a method lookup in the type @@ -1605,10 +1640,11 @@ } static int -pmerge(PyObject *acc, PyObject* to_merge) { +pmerge(PyObject *acc, PyObject* to_merge) +{ + int res = 0; Py_ssize_t i, j, to_merge_size, empty_cnt; int *remain; - int ok; to_merge_size = PyList_GET_SIZE(to_merge); @@ -1646,15 +1682,13 @@ candidate = PyList_GET_ITEM(cur_list, remain[i]); for (j = 0; j < to_merge_size; j++) { PyObject *j_lst = PyList_GET_ITEM(to_merge, j); - if (tail_contains(j_lst, remain[j], candidate)) { + if (tail_contains(j_lst, remain[j], candidate)) goto skip; /* continue outer loop */ - } } - ok = PyList_Append(acc, candidate); - if (ok < 0) { - PyMem_FREE(remain); - return -1; - } + res = PyList_Append(acc, candidate); + if (res < 0) + goto out; + for (j = 0; j < to_merge_size; j++) { PyObject *j_lst = PyList_GET_ITEM(to_merge, j); if (remain[j] < PyList_GET_SIZE(j_lst) && @@ -1666,22 +1700,25 @@ skip: ; } - if (empty_cnt == to_merge_size) { - PyMem_FREE(remain); - return 0; - } - set_mro_error(to_merge, remain); + if (empty_cnt != to_merge_size) { + set_mro_error(to_merge, remain); + res = -1; + } + + out: PyMem_FREE(remain); - return -1; + + return res; } static PyObject * mro_implementation(PyTypeObject *type) { + PyObject *result = NULL; + PyObject *bases; + PyObject *to_merge, *bases_aslist; + int res; Py_ssize_t i, n; - int ok; - PyObject *bases, *result; - PyObject *to_merge, *bases_aslist; if (type->tp_dict == NULL) { if (PyType_Ready(type) < 0) @@ -1705,42 +1742,44 @@ return NULL; for (i = 0; i < n; i++) { - PyObject *base = PyTuple_GET_ITEM(bases, i); - PyObject *parentMRO; - parentMRO = PySequence_List(((PyTypeObject*)base)->tp_mro); - if (parentMRO == NULL) { - Py_DECREF(to_merge); - return NULL; + PyTypeObject *base; + PyObject *base_mro_aslist; + + base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i); + if (base->tp_mro == NULL) { + PyErr_Format(PyExc_TypeError, + "Cannot extend an incomplete type '%.100s'", + base->tp_name); + goto out; } - PyList_SET_ITEM(to_merge, i, parentMRO); + base_mro_aslist = PySequence_List(base->tp_mro); + if (base_mro_aslist == NULL) + goto out; + + PyList_SET_ITEM(to_merge, i, base_mro_aslist); } bases_aslist = PySequence_List(bases); - if (bases_aslist == NULL) { - Py_DECREF(to_merge); - return NULL; - } + if (bases_aslist == NULL) + goto out; /* This is just a basic sanity check. */ if (check_duplicates(bases_aslist) < 0) { - Py_DECREF(to_merge); Py_DECREF(bases_aslist); - return NULL; + goto out; } PyList_SET_ITEM(to_merge, n, bases_aslist); result = Py_BuildValue("[O]", (PyObject *)type); - if (result == NULL) { - Py_DECREF(to_merge); - return NULL; - } - - ok = pmerge(result, to_merge); + if (result == NULL) + goto out; + + res = pmerge(result, to_merge); + if (res < 0) + Py_CLEAR(result); + + out: Py_DECREF(to_merge); - if (ok < 0) { - Py_DECREF(result); - return NULL; - } return result; } @@ -1754,59 +1793,133 @@ } static int -mro_internal(PyTypeObject *type) -{ - PyObject *mro, *result, *tuple; - int checkit = 0; - - if (Py_TYPE(type) == &PyType_Type) { - result = mro_implementation(type); +mro_check(PyTypeObject *type, PyObject *mro) +{ + PyTypeObject *solid; + Py_ssize_t i, n; + + solid = solid_base(type); + + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyTypeObject *base; + PyObject *tmp; + + tmp = PyTuple_GET_ITEM(mro, i); + if (!PyType_Check(tmp)) { + PyErr_Format( + PyExc_TypeError, + "mro() returned a non-class ('%.500s')", + Py_TYPE(tmp)->tp_name); + return -1; + } + + base = (PyTypeObject*)tmp; + if (!PyType_IsSubtype(solid, solid_base(base))) { + PyErr_Format( + PyExc_TypeError, + "mro() returned base with unsuitable layout ('%.500s')", + base->tp_name); + return -1; + } + } + + return 0; +} + +/* Lookups an mcls.mro method, invokes it and checks the result (if needed, + in case of a custom mro() implementation). + + Keep in mind that during execution of this function type->tp_mro + can be replaced due to possible reentrance (for example, + through type_set_bases): + + - when looking up the mcls.mro attribute (it could be + a user-provided descriptor); + + - from inside a custom mro() itself; + + - through a finalizer of the return value of mro(). +*/ +static PyObject * +mro_invoke(PyTypeObject *type) +{ + PyObject *mro_result; + PyObject *new_mro; + int custom = (Py_TYPE(type) != &PyType_Type); + + if (custom) { + _Py_IDENTIFIER(mro); + PyObject *mro_meth = lookup_method((PyObject *)type, &PyId_mro); + if (mro_meth == NULL) + return NULL; + mro_result = PyObject_CallObject(mro_meth, NULL); + Py_DECREF(mro_meth); } else { - _Py_IDENTIFIER(mro); - checkit = 1; - mro = lookup_method((PyObject *)type, &PyId_mro); - if (mro == NULL) - return -1; - result = PyObject_CallObject(mro, NULL); - Py_DECREF(mro); - } - if (result == NULL) + mro_result = mro_implementation(type); + } + if (mro_result == NULL) + return NULL; + + new_mro = PySequence_Tuple(mro_result); + Py_DECREF(mro_result); + if (new_mro == NULL) + return NULL; + + if (custom && mro_check(type, new_mro) < 0) { + Py_DECREF(new_mro); + return NULL; + } + + return new_mro; +} + +/* Calculates and assigns a new MRO to type->tp_mro. + Return values and invariants: + + - Returns 1 if a new MRO value has been set to type->tp_mro due to + this call of mro_internal (no tricky reentrancy and no errors). + + In case if p_old_mro argument is not NULL, a previous value + of type->tp_mro is put there, and the ownership of this + reference is transferred to a caller. + Otherwise, the previous value (if any) is decref'ed. + + - Returns 0 in case when type->tp_mro gets changed because of + reentering here through a custom mro() (see a comment to mro_invoke). + + In this case, a refcount of an old type->tp_mro is adjusted + somewhere deeper in the call stack (by the innermost mro_internal + or its caller) and may become zero upon returning from here. + This also implies that the whole hierarchy of subclasses of the type + has seen the new value and updated their MRO accordingly. + + - Returns -1 in case of an error. +*/ +static int +mro_internal(PyTypeObject *type, PyObject **p_old_mro) +{ + PyObject *new_mro, *old_mro; + int reent; + + /* Keep a reference to be able to do a reentrancy check below. + Don't let old_mro be GC'ed and its address be reused for + another object, like (suddenly!) a new tp_mro. */ + old_mro = type->tp_mro; + Py_XINCREF(old_mro); + new_mro = mro_invoke(type); /* might cause reentrance */ + reent = (type->tp_mro != old_mro); + Py_XDECREF(old_mro); + if (new_mro == NULL) return -1; - tuple = PySequence_Tuple(result); - Py_DECREF(result); - if (tuple == NULL) - return -1; - if (checkit) { - Py_ssize_t i, len; - PyObject *cls; - PyTypeObject *solid; - - solid = solid_base(type); - - len = PyTuple_GET_SIZE(tuple); - - for (i = 0; i < len; i++) { - PyTypeObject *t; - cls = PyTuple_GET_ITEM(tuple, i); - if (!PyType_Check(cls)) { - PyErr_Format(PyExc_TypeError, - "mro() returned a non-class ('%.500s')", - Py_TYPE(cls)->tp_name); - Py_DECREF(tuple); - return -1; - } - t = (PyTypeObject*)cls; - if (!PyType_IsSubtype(solid, solid_base(t))) { - PyErr_Format(PyExc_TypeError, - "mro() returned base with unsuitable layout ('%.500s')", - t->tp_name); - Py_DECREF(tuple); - return -1; - } - } - } - type->tp_mro = tuple; + + if (reent) { + Py_DECREF(new_mro); + return 0; + } + + type->tp_mro = new_mro; type_mro_modified(type, type->tp_mro); /* corner case: the super class might have been hidden @@ -1815,7 +1928,12 @@ PyType_Modified(type); - return 0; + if (p_old_mro != NULL) + *p_old_mro = old_mro; /* transfer the ownership */ + else + Py_XDECREF(old_mro); + + return 1; } @@ -4675,9 +4793,8 @@ } /* Calculate method resolution order */ - if (mro_internal(type) < 0) { + if (mro_internal(type, NULL) < 0) goto error; - } /* Inherit special flags from dominant base */ if (type->tp_base != NULL) @@ -4826,6 +4943,24 @@ return result; } +static int +add_all_subclasses(PyTypeObject *type, PyObject *bases) +{ + int res = 0; + + if (bases) { + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(bases); i++) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (PyType_Check(base) && + add_subclass((PyTypeObject*)base, type) < 0) + res = -1; + } + } + + return res; +} + static void remove_subclass(PyTypeObject *base, PyTypeObject *type) { @@ -6797,70 +6932,74 @@ super_getattro(PyObject *self, PyObject *name) { superobject *su = (superobject *)self; - int skip = su->obj_type == NULL; - - if (!skip) { - /* We want __class__ to return the class of the super object - (i.e. super, or a subclass), not the class of su->obj. */ - skip = (PyUnicode_Check(name) && - PyUnicode_GET_LENGTH(name) == 9 && - _PyUnicode_CompareWithId(name, &PyId___class__) == 0); - } - - if (!skip) { - PyObject *mro, *res, *tmp, *dict; - PyTypeObject *starttype; + PyTypeObject *starttype; + PyObject *mro; + Py_ssize_t i, n; + + starttype = su->obj_type; + if (starttype == NULL) + goto skip; + + /* We want __class__ to return the class of the super object + (i.e. super, or a subclass), not the class of su->obj. */ + if (PyUnicode_Check(name) && + PyUnicode_GET_LENGTH(name) == 9 && + _PyUnicode_CompareWithId(name, &PyId___class__) == 0) + goto skip; + + mro = starttype->tp_mro; + if (mro == NULL) + goto skip; + + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + + /* No need to check the last one: it's gonna be skipped anyway. */ + for (i = 0; i+1 < n; i++) { + if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) + break; + } + i++; /* skip su->type (if any) */ + if (i >= n) + goto skip; + + /* keep a strong reference to mro because starttype->tp_mro can be + replaced during PyDict_GetItem(dict, name) */ + Py_INCREF(mro); + do { + PyObject *res, *tmp, *dict; descrgetfunc f; - Py_ssize_t i, n; - - starttype = su->obj_type; - mro = starttype->tp_mro; - - if (mro == NULL) - n = 0; - else { - assert(PyTuple_Check(mro)); - n = PyTuple_GET_SIZE(mro); + + tmp = PyTuple_GET_ITEM(mro, i); + assert(PyType_Check(tmp)); + + dict = ((PyTypeObject *)tmp)->tp_dict; + assert(dict != NULL && PyDict_Check(dict)); + + res = PyDict_GetItem(dict, name); + if (res != NULL) { + Py_INCREF(res); + + f = Py_TYPE(res)->tp_descr_get; + if (f != NULL) { + tmp = f(res, + /* Only pass 'obj' param if this is instance-mode super + (See SF ID #743627) */ + (su->obj == (PyObject *)starttype) ? NULL : su->obj, + (PyObject *)starttype); + Py_DECREF(res); + res = tmp; + } + + Py_DECREF(mro); + return res; } - for (i = 0; i < n; i++) { - if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) - break; - } + i++; - res = NULL; - /* keep a strong reference to mro because starttype->tp_mro can be - replaced during PyDict_GetItem(dict, name) */ - Py_INCREF(mro); - for (; i < n; i++) { - tmp = PyTuple_GET_ITEM(mro, i); - if (PyType_Check(tmp)) - dict = ((PyTypeObject *)tmp)->tp_dict; - else - continue; - res = PyDict_GetItem(dict, name); - if (res != NULL) { - Py_INCREF(res); - f = Py_TYPE(res)->tp_descr_get; - if (f != NULL) { - tmp = f(res, - /* Only pass 'obj' param if - this is instance-mode super - (See SF ID #743627) - */ - (su->obj == (PyObject *) - su->obj_type - ? (PyObject *)NULL - : su->obj), - (PyObject *)starttype); - Py_DECREF(res); - res = tmp; - } - Py_DECREF(mro); - return res; - } - } - Py_DECREF(mro); - } + } while (i < n); + Py_DECREF(mro); + + skip: return PyObject_GenericGetAttr(self, name); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 04:31:01 2015 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 06 Feb 2015 03:31:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_fix_many_custo?= =?utf-8?q?m_mro=28=29_edge_cases_and_improve_code_quality_=28=2322735=29?= Message-ID: <20150206033056.96084.82237@psf.io> https://hg.python.org/cpython/rev/6384c0cd3b2d changeset: 94526:6384c0cd3b2d branch: 3.4 parent: 94524:1ddf68f118c7 user: Benjamin Peterson date: Thu Feb 05 22:29:14 2015 -0500 summary: fix many custom mro() edge cases and improve code quality (#22735) Patch by Eldar Abusalimov. files: Lib/test/test_descr.py | 227 +++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + Objects/typeobject.c | 699 +++++++++++++++++----------- 4 files changed, 649 insertions(+), 281 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4996,11 +4996,236 @@ self.assertLess(sys.getsizeof(vars(b)), sys.getsizeof({})) +class DebugHelperMeta(type): + """ + Sets default __doc__ and simplifies repr() output. + """ + def __new__(mcls, name, bases, attrs): + if attrs.get('__doc__') is None: + attrs['__doc__'] = name # helps when debugging with gdb + return type.__new__(mcls, name, bases, attrs) + def __repr__(cls): + return repr(cls.__name__) + + +class MroTest(unittest.TestCase): + """ + Regressions for some bugs revealed through + mcsl.mro() customization (typeobject.c: mro_internal()) and + cls.__bases__ assignment (typeobject.c: type_set_bases()). + """ + + def setUp(self): + self.step = 0 + self.ready = False + + def step_until(self, limit): + ret = (self.step < limit) + if ret: + self.step += 1 + return ret + + def test_incomplete_set_bases_on_self(self): + """ + type_set_bases must be aware that type->tp_mro can be NULL. + """ + class M(DebugHelperMeta): + def mro(cls): + if self.step_until(1): + assert cls.__mro__ is None + cls.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + + def test_reent_set_bases_on_base(self): + """ + Deep reentrancy must not over-decref old_mro. + """ + class M(DebugHelperMeta): + def mro(cls): + if cls.__mro__ is not None and cls.__name__ == 'B': + # 4-5 steps are usually enough to make it crash somewhere + if self.step_until(10): + A.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + class B(A): + pass + B.__bases__ += () + + def test_reent_set_bases_on_direct_base(self): + """ + Similar to test_reent_set_bases_on_base, but may crash differently. + """ + class M(DebugHelperMeta): + def mro(cls): + base = cls.__bases__[0] + if base is not object: + if self.step_until(5): + base.__bases__ += () + + return type.mro(cls) + + class A(metaclass=M): + pass + class B(A): + pass + class C(B): + pass + + def test_reent_set_bases_tp_base_cycle(self): + """ + type_set_bases must check for an inheritance cycle not only through + MRO of the type, which may be not yet updated in case of reentrance, + but also through tp_base chain, which is assigned before diving into + inner calls to mro(). + + Otherwise, the following snippet can loop forever: + do { + // ... + type = type->tp_base; + } while (type != NULL); + + Functions that rely on tp_base (like solid_base and PyType_IsSubtype) + would not be happy in that case, causing a stack overflow. + """ + class M(DebugHelperMeta): + def mro(cls): + if self.ready: + if cls.__name__ == 'B1': + B2.__bases__ = (B1,) + if cls.__name__ == 'B2': + B1.__bases__ = (B2,) + return type.mro(cls) + + class A(metaclass=M): + pass + class B1(A): + pass + class B2(A): + pass + + self.ready = True + with self.assertRaises(TypeError): + B1.__bases__ += () + + def test_tp_subclasses_cycle_in_update_slots(self): + """ + type_set_bases must check for reentrancy upon finishing its job + by updating tp_subclasses of old/new bases of the type. + Otherwise, an implicit inheritance cycle through tp_subclasses + can break functions that recurse on elements of that field + (like recurse_down_subclasses and mro_hierarchy) eventually + leading to a stack overflow. + """ + class M(DebugHelperMeta): + def mro(cls): + if self.ready and cls.__name__ == 'C': + self.ready = False + C.__bases__ = (B2,) + return type.mro(cls) + + class A(metaclass=M): + pass + class B1(A): + pass + class B2(A): + pass + class C(A): + pass + + self.ready = True + C.__bases__ = (B1,) + B1.__bases__ = (C,) + + self.assertEqual(C.__bases__, (B2,)) + self.assertEqual(B2.__subclasses__(), [C]) + self.assertEqual(B1.__subclasses__(), []) + + self.assertEqual(B1.__bases__, (C,)) + self.assertEqual(C.__subclasses__(), [B1]) + + def test_tp_subclasses_cycle_error_return_path(self): + """ + The same as test_tp_subclasses_cycle_in_update_slots, but tests + a code path executed on error (goto bail). + """ + class E(Exception): + pass + class M(DebugHelperMeta): + def mro(cls): + if self.ready and cls.__name__ == 'C': + if C.__bases__ == (B2,): + self.ready = False + else: + C.__bases__ = (B2,) + raise E + return type.mro(cls) + + class A(metaclass=M): + pass + class B1(A): + pass + class B2(A): + pass + class C(A): + pass + + self.ready = True + with self.assertRaises(E): + C.__bases__ = (B1,) + B1.__bases__ = (C,) + + self.assertEqual(C.__bases__, (B2,)) + self.assertEqual(C.__mro__, tuple(type.mro(C))) + + def test_incomplete_extend(self): + """ + Extending an unitialized type with type->tp_mro == NULL must + throw a reasonable TypeError exception, instead of failing + with PyErr_BadInternalCall. + """ + class M(DebugHelperMeta): + def mro(cls): + if cls.__mro__ is None and cls.__name__ != 'X': + with self.assertRaises(TypeError): + class X(cls): + pass + + return type.mro(cls) + + class A(metaclass=M): + pass + + def test_incomplete_super(self): + """ + Attrubute lookup on a super object must be aware that + its target type can be uninitialized (type->tp_mro == NULL). + """ + class M(DebugHelperMeta): + def mro(cls): + if cls.__mro__ is None: + with self.assertRaises(AttributeError): + super(cls, cls).xxx + + return type.mro(cls) + + class A(metaclass=M): + pass + + def test_main(): # Run all local test cases, with PTypesLongInitTest first. support.run_unittest(PTypesLongInitTest, OperatorsTest, ClassPropertiesAndMethods, DictProxyTests, - MiscTests, PicklingTests, SharedKeyTests) + MiscTests, PicklingTests, SharedKeyTests, + MroTest) if __name__ == "__main__": test_main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -16,6 +16,7 @@ Rajiv Abraham David Abrahams Marc Abramowitz +Eldar Abusalimov Ron Adam Anton Afanasyev Ali Afshar diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,6 +11,9 @@ Core and Builtins ----------------- +- Issue #22735: Fix many edge cases (including crashes) involving custom mro() + implementations. + - Issue #22896: Avoid using PyObject_AsCharBuffer(), PyObject_AsReadBuffer() and PyObject_AsWriteBuffer(). diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -539,9 +539,11 @@ } static PyTypeObject *best_base(PyObject *); -static int mro_internal(PyTypeObject *); +static int mro_internal(PyTypeObject *, PyObject **); +static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); static int add_subclass(PyTypeObject*, PyTypeObject*); +static int add_all_subclasses(PyTypeObject *type, PyObject *bases); static void remove_subclass(PyTypeObject *, PyTypeObject *); static void remove_all_subclasses(PyTypeObject *type, PyObject *bases); static void update_all_slots(PyTypeObject *); @@ -551,167 +553,194 @@ update_callback callback, void *data); static int recurse_down_subclasses(PyTypeObject *type, PyObject *name, update_callback callback, void *data); +static PyObject *type_subclasses(PyTypeObject *type, PyObject *ignored); static int -mro_subclasses(PyTypeObject *type, PyObject* temp) -{ - PyTypeObject *subclass; - PyObject *ref, *subclasses, *old_mro; +mro_hierarchy(PyTypeObject *type, PyObject *temp) +{ + int res; + PyObject *new_mro, *old_mro; + PyObject *tuple; + PyObject *subclasses; + Py_ssize_t i, n; + + res = mro_internal(type, &old_mro); + if (res <= 0) + /* error / reentrance */ + return res; + new_mro = type->tp_mro; + + if (old_mro != NULL) + tuple = PyTuple_Pack(3, type, new_mro, old_mro); + else + tuple = PyTuple_Pack(2, type, new_mro); + + if (tuple != NULL) + res = PyList_Append(temp, tuple); + else + res = -1; + Py_XDECREF(tuple); + + if (res < 0) { + type->tp_mro = old_mro; + Py_DECREF(new_mro); + return -1; + } + Py_XDECREF(old_mro); + + /* Obtain a copy of subclasses list to iterate over. + + Otherwise type->tp_subclasses might be altered + in the middle of the loop, for example, through a custom mro(), + by invoking type_set_bases on some subclass of the type + which in turn calls remove_subclass/add_subclass on this type. + + Finally, this makes things simple avoiding the need to deal + with dictionary iterators and weak references. + */ + subclasses = type_subclasses(type, NULL); + if (subclasses == NULL) + return -1; + n = PyList_GET_SIZE(subclasses); + for (i = 0; i < n; i++) { + PyTypeObject *subclass; + subclass = (PyTypeObject *)PyList_GET_ITEM(subclasses, i); + res = mro_hierarchy(subclass, temp); + if (res < 0) + break; + } + Py_DECREF(subclasses); + + return res; +} + +static int +type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) +{ + int res = 0; + PyObject *temp; + PyObject *old_bases; + PyTypeObject *new_base, *old_base; Py_ssize_t i; - subclasses = type->tp_subclasses; - if (subclasses == NULL) - return 0; - assert(PyDict_CheckExact(subclasses)); - i = 0; - - while (PyDict_Next(subclasses, &i, NULL, &ref)) { - assert(PyWeakref_CheckRef(ref)); - subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); - assert(subclass != NULL); - if ((PyObject *)subclass == Py_None) - continue; - assert(PyType_Check(subclass)); - old_mro = subclass->tp_mro; - if (mro_internal(subclass) < 0) { - subclass->tp_mro = old_mro; - return -1; - } - else { - PyObject* tuple; - tuple = PyTuple_Pack(2, subclass, old_mro); - Py_DECREF(old_mro); - if (!tuple) - return -1; - if (PyList_Append(temp, tuple) < 0) - return -1; - Py_DECREF(tuple); - } - if (mro_subclasses(subclass, temp) < 0) - return -1; - } - return 0; -} - -static int -type_set_bases(PyTypeObject *type, PyObject *value, void *context) -{ - Py_ssize_t i; - int r = 0; - PyObject *ob, *temp; - PyTypeObject *new_base, *old_base; - PyObject *old_bases, *old_mro; - - if (!check_set_special_type_attr(type, value, "__bases__")) + if (!check_set_special_type_attr(type, new_bases, "__bases__")) return -1; - if (!PyTuple_Check(value)) { + if (!PyTuple_Check(new_bases)) { PyErr_Format(PyExc_TypeError, "can only assign tuple to %s.__bases__, not %s", - type->tp_name, Py_TYPE(value)->tp_name); + type->tp_name, Py_TYPE(new_bases)->tp_name); return -1; } - if (PyTuple_GET_SIZE(value) == 0) { + if (PyTuple_GET_SIZE(new_bases) == 0) { PyErr_Format(PyExc_TypeError, "can only assign non-empty tuple to %s.__bases__, not ()", type->tp_name); return -1; } - for (i = 0; i < PyTuple_GET_SIZE(value); i++) { - ob = PyTuple_GET_ITEM(value, i); + for (i = 0; i < PyTuple_GET_SIZE(new_bases); i++) { + PyObject *ob; + PyTypeObject *base; + + ob = PyTuple_GET_ITEM(new_bases, i); if (!PyType_Check(ob)) { PyErr_Format(PyExc_TypeError, "%s.__bases__ must be tuple of classes, not '%s'", type->tp_name, Py_TYPE(ob)->tp_name); return -1; } - if (PyType_IsSubtype((PyTypeObject*)ob, type)) { + + base = (PyTypeObject*)ob; + if (PyType_IsSubtype(base, type) || + /* In case of reentering here again through a custom mro() + the above check is not enough since it relies on + base->tp_mro which would gonna be updated inside + mro_internal only upon returning from the mro(). + + However, base->tp_base has already been assigned (see + below), which in turn may cause an inheritance cycle + through tp_base chain. And this is definitely + not what you want to ever happen. */ + (base->tp_mro != NULL && type_is_subtype_base_chain(base, type))) { + PyErr_SetString(PyExc_TypeError, "a __bases__ item causes an inheritance cycle"); return -1; } } - new_base = best_base(value); - - if (!new_base) + new_base = best_base(new_bases); + if (new_base == NULL) return -1; if (!compatible_for_assignment(type->tp_base, new_base, "__bases__")) return -1; + Py_INCREF(new_bases); Py_INCREF(new_base); - Py_INCREF(value); old_bases = type->tp_bases; old_base = type->tp_base; - old_mro = type->tp_mro; - - type->tp_bases = value; + + type->tp_bases = new_bases; type->tp_base = new_base; - if (mro_internal(type) < 0) { + temp = PyList_New(0); + if (temp == NULL) goto bail; - } - - temp = PyList_New(0); - if (!temp) - goto bail; - - r = mro_subclasses(type, temp); - - if (r < 0) { - for (i = 0; i < PyList_Size(temp); i++) { - PyTypeObject* cls; - PyObject* mro; - PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), - "", 2, 2, &cls, &mro); - Py_INCREF(mro); - ob = cls->tp_mro; - cls->tp_mro = mro; - Py_DECREF(ob); - } - Py_DECREF(temp); - goto bail; - } - + if (mro_hierarchy(type, temp) < 0) + goto undo; Py_DECREF(temp); - /* any base that was in __bases__ but now isn't, we - need to remove |type| from its tp_subclasses. - conversely, any class now in __bases__ that wasn't - needs to have |type| added to its subclasses. */ - - /* for now, sod that: just remove from all old_bases, - add to all new_bases */ - - remove_all_subclasses(type, old_bases); - - for (i = PyTuple_GET_SIZE(value) - 1; i >= 0; i--) { - ob = PyTuple_GET_ITEM(value, i); - if (PyType_Check(ob)) { - if (add_subclass((PyTypeObject*)ob, type) < 0) - r = -1; - } - } - - update_all_slots(type); + /* Take no action in case if type->tp_bases has been replaced + through reentrance. */ + if (type->tp_bases == new_bases) { + /* any base that was in __bases__ but now isn't, we + need to remove |type| from its tp_subclasses. + conversely, any class now in __bases__ that wasn't + needs to have |type| added to its subclasses. */ + + /* for now, sod that: just remove from all old_bases, + add to all new_bases */ + remove_all_subclasses(type, old_bases); + res = add_all_subclasses(type, new_bases); + update_all_slots(type); + } Py_DECREF(old_bases); Py_DECREF(old_base); - Py_DECREF(old_mro); - - return r; + + return res; + + undo: + for (i = PyList_GET_SIZE(temp) - 1; i >= 0; i--) { + PyTypeObject *cls; + PyObject *new_mro, *old_mro = NULL; + + PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), + "", 2, 3, &cls, &new_mro, &old_mro); + /* Do not rollback if cls has a newer version of MRO. */ + if (cls->tp_mro == new_mro) { + Py_XINCREF(old_mro); + cls->tp_mro = old_mro; + Py_DECREF(new_mro); + } + } + Py_DECREF(temp); bail: - Py_DECREF(type->tp_bases); - Py_DECREF(type->tp_base); - if (type->tp_mro != old_mro) { - Py_DECREF(type->tp_mro); - } - - type->tp_bases = old_bases; - type->tp_base = old_base; - type->tp_mro = old_mro; + if (type->tp_bases == new_bases) { + assert(type->tp_base == new_base); + + type->tp_bases = old_bases; + type->tp_base = old_base; + + Py_DECREF(new_bases); + Py_DECREF(new_base); + } + else { + Py_DECREF(old_bases); + Py_DECREF(old_base); + } return -1; } @@ -1284,6 +1313,18 @@ /* type test with subclassing support */ +Py_LOCAL_INLINE(int) +type_is_subtype_base_chain(PyTypeObject *a, PyTypeObject *b) +{ + do { + if (a == b) + return 1; + a = a->tp_base; + } while (a != NULL); + + return (b == &PyBaseObject_Type); +} + int PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) { @@ -1302,15 +1343,9 @@ } return 0; } - else { + else /* a is not completely initilized yet; follow tp_base */ - do { - if (a == b) - return 1; - a = a->tp_base; - } while (a != NULL); - return b == &PyBaseObject_Type; - } + return type_is_subtype_base_chain(a, b); } /* Internal routines to do a method lookup in the type @@ -1577,10 +1612,11 @@ } static int -pmerge(PyObject *acc, PyObject* to_merge) { +pmerge(PyObject *acc, PyObject* to_merge) +{ + int res = 0; Py_ssize_t i, j, to_merge_size, empty_cnt; int *remain; - int ok; to_merge_size = PyList_GET_SIZE(to_merge); @@ -1618,15 +1654,13 @@ candidate = PyList_GET_ITEM(cur_list, remain[i]); for (j = 0; j < to_merge_size; j++) { PyObject *j_lst = PyList_GET_ITEM(to_merge, j); - if (tail_contains(j_lst, remain[j], candidate)) { + if (tail_contains(j_lst, remain[j], candidate)) goto skip; /* continue outer loop */ - } } - ok = PyList_Append(acc, candidate); - if (ok < 0) { - PyMem_FREE(remain); - return -1; - } + res = PyList_Append(acc, candidate); + if (res < 0) + goto out; + for (j = 0; j < to_merge_size; j++) { PyObject *j_lst = PyList_GET_ITEM(to_merge, j); if (remain[j] < PyList_GET_SIZE(j_lst) && @@ -1638,22 +1672,25 @@ skip: ; } - if (empty_cnt == to_merge_size) { - PyMem_FREE(remain); - return 0; - } - set_mro_error(to_merge, remain); + if (empty_cnt != to_merge_size) { + set_mro_error(to_merge, remain); + res = -1; + } + + out: PyMem_FREE(remain); - return -1; + + return res; } static PyObject * mro_implementation(PyTypeObject *type) { + PyObject *result = NULL; + PyObject *bases; + PyObject *to_merge, *bases_aslist; + int res; Py_ssize_t i, n; - int ok; - PyObject *bases, *result; - PyObject *to_merge, *bases_aslist; if (type->tp_dict == NULL) { if (PyType_Ready(type) < 0) @@ -1677,42 +1714,44 @@ return NULL; for (i = 0; i < n; i++) { - PyObject *base = PyTuple_GET_ITEM(bases, i); - PyObject *parentMRO; - parentMRO = PySequence_List(((PyTypeObject*)base)->tp_mro); - if (parentMRO == NULL) { - Py_DECREF(to_merge); - return NULL; + PyTypeObject *base; + PyObject *base_mro_aslist; + + base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i); + if (base->tp_mro == NULL) { + PyErr_Format(PyExc_TypeError, + "Cannot extend an incomplete type '%.100s'", + base->tp_name); + goto out; } - PyList_SET_ITEM(to_merge, i, parentMRO); + base_mro_aslist = PySequence_List(base->tp_mro); + if (base_mro_aslist == NULL) + goto out; + + PyList_SET_ITEM(to_merge, i, base_mro_aslist); } bases_aslist = PySequence_List(bases); - if (bases_aslist == NULL) { - Py_DECREF(to_merge); - return NULL; - } + if (bases_aslist == NULL) + goto out; /* This is just a basic sanity check. */ if (check_duplicates(bases_aslist) < 0) { - Py_DECREF(to_merge); Py_DECREF(bases_aslist); - return NULL; + goto out; } PyList_SET_ITEM(to_merge, n, bases_aslist); result = Py_BuildValue("[O]", (PyObject *)type); - if (result == NULL) { - Py_DECREF(to_merge); - return NULL; - } - - ok = pmerge(result, to_merge); + if (result == NULL) + goto out; + + res = pmerge(result, to_merge); + if (res < 0) + Py_CLEAR(result); + + out: Py_DECREF(to_merge); - if (ok < 0) { - Py_DECREF(result); - return NULL; - } return result; } @@ -1726,59 +1765,133 @@ } static int -mro_internal(PyTypeObject *type) -{ - PyObject *mro, *result, *tuple; - int checkit = 0; - - if (Py_TYPE(type) == &PyType_Type) { - result = mro_implementation(type); +mro_check(PyTypeObject *type, PyObject *mro) +{ + PyTypeObject *solid; + Py_ssize_t i, n; + + solid = solid_base(type); + + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + PyTypeObject *base; + PyObject *tmp; + + tmp = PyTuple_GET_ITEM(mro, i); + if (!PyType_Check(tmp)) { + PyErr_Format( + PyExc_TypeError, + "mro() returned a non-class ('%.500s')", + Py_TYPE(tmp)->tp_name); + return -1; + } + + base = (PyTypeObject*)tmp; + if (!PyType_IsSubtype(solid, solid_base(base))) { + PyErr_Format( + PyExc_TypeError, + "mro() returned base with unsuitable layout ('%.500s')", + base->tp_name); + return -1; + } + } + + return 0; +} + +/* Lookups an mcls.mro method, invokes it and checks the result (if needed, + in case of a custom mro() implementation). + + Keep in mind that during execution of this function type->tp_mro + can be replaced due to possible reentrance (for example, + through type_set_bases): + + - when looking up the mcls.mro attribute (it could be + a user-provided descriptor); + + - from inside a custom mro() itself; + + - through a finalizer of the return value of mro(). +*/ +static PyObject * +mro_invoke(PyTypeObject *type) +{ + PyObject *mro_result; + PyObject *new_mro; + int custom = (Py_TYPE(type) != &PyType_Type); + + if (custom) { + _Py_IDENTIFIER(mro); + PyObject *mro_meth = lookup_method((PyObject *)type, &PyId_mro); + if (mro_meth == NULL) + return NULL; + mro_result = PyObject_CallObject(mro_meth, NULL); + Py_DECREF(mro_meth); } else { - _Py_IDENTIFIER(mro); - checkit = 1; - mro = lookup_method((PyObject *)type, &PyId_mro); - if (mro == NULL) - return -1; - result = PyObject_CallObject(mro, NULL); - Py_DECREF(mro); - } - if (result == NULL) + mro_result = mro_implementation(type); + } + if (mro_result == NULL) + return NULL; + + new_mro = PySequence_Tuple(mro_result); + Py_DECREF(mro_result); + if (new_mro == NULL) + return NULL; + + if (custom && mro_check(type, new_mro) < 0) { + Py_DECREF(new_mro); + return NULL; + } + + return new_mro; +} + +/* Calculates and assigns a new MRO to type->tp_mro. + Return values and invariants: + + - Returns 1 if a new MRO value has been set to type->tp_mro due to + this call of mro_internal (no tricky reentrancy and no errors). + + In case if p_old_mro argument is not NULL, a previous value + of type->tp_mro is put there, and the ownership of this + reference is transferred to a caller. + Otherwise, the previous value (if any) is decref'ed. + + - Returns 0 in case when type->tp_mro gets changed because of + reentering here through a custom mro() (see a comment to mro_invoke). + + In this case, a refcount of an old type->tp_mro is adjusted + somewhere deeper in the call stack (by the innermost mro_internal + or its caller) and may become zero upon returning from here. + This also implies that the whole hierarchy of subclasses of the type + has seen the new value and updated their MRO accordingly. + + - Returns -1 in case of an error. +*/ +static int +mro_internal(PyTypeObject *type, PyObject **p_old_mro) +{ + PyObject *new_mro, *old_mro; + int reent; + + /* Keep a reference to be able to do a reentrancy check below. + Don't let old_mro be GC'ed and its address be reused for + another object, like (suddenly!) a new tp_mro. */ + old_mro = type->tp_mro; + Py_XINCREF(old_mro); + new_mro = mro_invoke(type); /* might cause reentrance */ + reent = (type->tp_mro != old_mro); + Py_XDECREF(old_mro); + if (new_mro == NULL) return -1; - tuple = PySequence_Tuple(result); - Py_DECREF(result); - if (tuple == NULL) - return -1; - if (checkit) { - Py_ssize_t i, len; - PyObject *cls; - PyTypeObject *solid; - - solid = solid_base(type); - - len = PyTuple_GET_SIZE(tuple); - - for (i = 0; i < len; i++) { - PyTypeObject *t; - cls = PyTuple_GET_ITEM(tuple, i); - if (!PyType_Check(cls)) { - PyErr_Format(PyExc_TypeError, - "mro() returned a non-class ('%.500s')", - Py_TYPE(cls)->tp_name); - Py_DECREF(tuple); - return -1; - } - t = (PyTypeObject*)cls; - if (!PyType_IsSubtype(solid, solid_base(t))) { - PyErr_Format(PyExc_TypeError, - "mro() returned base with unsuitable layout ('%.500s')", - t->tp_name); - Py_DECREF(tuple); - return -1; - } - } - } - type->tp_mro = tuple; + + if (reent) { + Py_DECREF(new_mro); + return 0; + } + + type->tp_mro = new_mro; type_mro_modified(type, type->tp_mro); /* corner case: the super class might have been hidden @@ -1787,7 +1900,12 @@ PyType_Modified(type); - return 0; + if (p_old_mro != NULL) + *p_old_mro = old_mro; /* transfer the ownership */ + else + Py_XDECREF(old_mro); + + return 1; } @@ -4661,9 +4779,8 @@ } /* Calculate method resolution order */ - if (mro_internal(type) < 0) { + if (mro_internal(type, NULL) < 0) goto error; - } /* Inherit special flags from dominant base */ if (type->tp_base != NULL) @@ -4812,6 +4929,24 @@ return result; } +static int +add_all_subclasses(PyTypeObject *type, PyObject *bases) +{ + int res = 0; + + if (bases) { + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(bases); i++) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (PyType_Check(base) && + add_subclass((PyTypeObject*)base, type) < 0) + res = -1; + } + } + + return res; +} + static void remove_subclass(PyTypeObject *base, PyTypeObject *type) { @@ -6765,70 +6900,74 @@ super_getattro(PyObject *self, PyObject *name) { superobject *su = (superobject *)self; - int skip = su->obj_type == NULL; - - if (!skip) { - /* We want __class__ to return the class of the super object - (i.e. super, or a subclass), not the class of su->obj. */ - skip = (PyUnicode_Check(name) && - PyUnicode_GET_LENGTH(name) == 9 && - _PyUnicode_CompareWithId(name, &PyId___class__) == 0); - } - - if (!skip) { - PyObject *mro, *res, *tmp, *dict; - PyTypeObject *starttype; + PyTypeObject *starttype; + PyObject *mro; + Py_ssize_t i, n; + + starttype = su->obj_type; + if (starttype == NULL) + goto skip; + + /* We want __class__ to return the class of the super object + (i.e. super, or a subclass), not the class of su->obj. */ + if (PyUnicode_Check(name) && + PyUnicode_GET_LENGTH(name) == 9 && + _PyUnicode_CompareWithId(name, &PyId___class__) == 0) + goto skip; + + mro = starttype->tp_mro; + if (mro == NULL) + goto skip; + + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + + /* No need to check the last one: it's gonna be skipped anyway. */ + for (i = 0; i+1 < n; i++) { + if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) + break; + } + i++; /* skip su->type (if any) */ + if (i >= n) + goto skip; + + /* keep a strong reference to mro because starttype->tp_mro can be + replaced during PyDict_GetItem(dict, name) */ + Py_INCREF(mro); + do { + PyObject *res, *tmp, *dict; descrgetfunc f; - Py_ssize_t i, n; - - starttype = su->obj_type; - mro = starttype->tp_mro; - - if (mro == NULL) - n = 0; - else { - assert(PyTuple_Check(mro)); - n = PyTuple_GET_SIZE(mro); + + tmp = PyTuple_GET_ITEM(mro, i); + assert(PyType_Check(tmp)); + + dict = ((PyTypeObject *)tmp)->tp_dict; + assert(dict != NULL && PyDict_Check(dict)); + + res = PyDict_GetItem(dict, name); + if (res != NULL) { + Py_INCREF(res); + + f = Py_TYPE(res)->tp_descr_get; + if (f != NULL) { + tmp = f(res, + /* Only pass 'obj' param if this is instance-mode super + (See SF ID #743627) */ + (su->obj == (PyObject *)starttype) ? NULL : su->obj, + (PyObject *)starttype); + Py_DECREF(res); + res = tmp; + } + + Py_DECREF(mro); + return res; } - for (i = 0; i < n; i++) { - if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) - break; - } + i++; - res = NULL; - /* keep a strong reference to mro because starttype->tp_mro can be - replaced during PyDict_GetItem(dict, name) */ - Py_INCREF(mro); - for (; i < n; i++) { - tmp = PyTuple_GET_ITEM(mro, i); - if (PyType_Check(tmp)) - dict = ((PyTypeObject *)tmp)->tp_dict; - else - continue; - res = PyDict_GetItem(dict, name); - if (res != NULL) { - Py_INCREF(res); - f = Py_TYPE(res)->tp_descr_get; - if (f != NULL) { - tmp = f(res, - /* Only pass 'obj' param if - this is instance-mode super - (See SF ID #743627) - */ - (su->obj == (PyObject *) - su->obj_type - ? (PyObject *)NULL - : su->obj), - (PyObject *)starttype); - Py_DECREF(res); - res = tmp; - } - Py_DECREF(mro); - return res; - } - } - Py_DECREF(mro); - } + } while (i < n); + Py_DECREF(mro); + + skip: return PyObject_GenericGetAttr(self, name); } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 05:43:37 2015 From: python-checkins at python.org (ned.deily) Date: Fri, 06 Feb 2015 04:43:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_missing_?= =?utf-8?q?=3Aref=3A_for_idle_in_doc_build=2E?= Message-ID: <20150206044337.25859.1280@psf.io> https://hg.python.org/cpython/rev/b8078220a6b8 changeset: 94529:b8078220a6b8 branch: 3.4 parent: 94526:6384c0cd3b2d user: Ned Deily date: Fri Feb 06 15:42:06 2015 +1100 summary: Fix missing :ref: for idle in doc build. files: Doc/library/idle.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -1,13 +1,13 @@ .. _idle: +IDLE +==== + .. index:: single: IDLE single: Python Editor single: Integrated Development Environment -IDLE -==== - .. moduleauthor:: Guido van Rossum IDLE is the Python IDE built with the :mod:`tkinter` GUI toolkit. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 05:43:37 2015 From: python-checkins at python.org (ned.deily) Date: Fri, 06 Feb 2015 04:43:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_missing_?= =?utf-8?q?=3Aref=3A_for_idle_in_doc_build=2E?= Message-ID: <20150206044336.34402.21545@psf.io> https://hg.python.org/cpython/rev/b3df5bb1cd14 changeset: 94528:b3df5bb1cd14 branch: 2.7 parent: 94523:7b74c65758ca user: Ned Deily date: Fri Feb 06 15:41:27 2015 +1100 summary: Fix missing :ref: for idle in doc build. files: Doc/library/idle.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -1,13 +1,13 @@ .. _idle: +IDLE +==== + .. index:: single: IDLE single: Python Editor single: Integrated Development Environment -IDLE -==== - .. moduleauthor:: Guido van Rossum IDLE is the Python IDE built with the :mod:`tkinter` GUI toolkit. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 05:43:37 2015 From: python-checkins at python.org (ned.deily) Date: Fri, 06 Feb 2015 04:43:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Fix_missing_=3Aref=3A_for_idle_in_doc_build=2E?= Message-ID: <20150206044337.39290.67069@psf.io> https://hg.python.org/cpython/rev/f1a82e949fb8 changeset: 94530:f1a82e949fb8 parent: 94527:75fd0bd89eef parent: 94529:b8078220a6b8 user: Ned Deily date: Fri Feb 06 15:43:01 2015 +1100 summary: Fix missing :ref: for idle in doc build. files: Doc/library/idle.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -1,13 +1,13 @@ .. _idle: +IDLE +==== + .. index:: single: IDLE single: Python Editor single: Integrated Development Environment -IDLE -==== - .. moduleauthor:: Guido van Rossum IDLE is the Python IDE built with the :mod:`tkinter` GUI toolkit. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 07:12:43 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 06 Feb 2015 06:12:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323260=3A_Update_W?= =?utf-8?q?indows_installer?= Message-ID: <20150206061243.25855.57060@psf.io> https://hg.python.org/cpython/rev/e7dbef447157 changeset: 94531:e7dbef447157 user: Steve Dower date: Thu Feb 05 22:08:48 2015 -0800 summary: Issue #23260: Update Windows installer files: .gitignore | 1 + .hgignore | 1 + Doc/make.bat | 15 +- Doc/using/win_installer.png | Bin Doc/using/windows.rst | 505 +- Misc/NEWS | 2 + PC/launcher.c | 20 +- PCbuild/_freeze_importlib.vcxproj | 9 +- PCbuild/libeay.vcxproj | 6 +- PCbuild/pylauncher.vcxproj | 1 + PCbuild/pyproject.props | 15 + PCbuild/python.props | 8 +- PCbuild/pywlauncher.vcxproj | 1 + PCbuild/ssleay.vcxproj | 6 +- Tools/buildbot/buildmsi.bat | 20 +- Tools/msi/README.txt | 501 +- Tools/msi/build.bat | 46 + Tools/msi/buildrelease.bat | 131 + Tools/msi/bundle/Default.thm | 123 + Tools/msi/bundle/Default.wxl | 103 + Tools/msi/bundle/SideBar.png | Bin Tools/msi/bundle/bootstrap/LICENSE.txt | 25 + Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp | 2645 ++++++++++ Tools/msi/bundle/bootstrap/pch.cpp | 1 + Tools/msi/bundle/bootstrap/pch.h | 59 + Tools/msi/bundle/bootstrap/pythonba.cpp | 76 + Tools/msi/bundle/bootstrap/pythonba.def | 18 + Tools/msi/bundle/bootstrap/pythonba.sln | 22 + Tools/msi/bundle/bootstrap/pythonba.vcxproj | 69 + Tools/msi/bundle/bootstrap/resource.h | 25 + Tools/msi/bundle/bundle.ico | Bin Tools/msi/bundle/bundle.targets | 99 + Tools/msi/bundle/bundle.wxs | 80 + Tools/msi/bundle/full.wixproj | 21 + Tools/msi/bundle/packagegroups/core.wxs | 56 + Tools/msi/bundle/packagegroups/crt.wxs | 25 + Tools/msi/bundle/packagegroups/dev.wxs | 40 + Tools/msi/bundle/packagegroups/doc.wxs | 24 + Tools/msi/bundle/packagegroups/exe.wxs | 56 + Tools/msi/bundle/packagegroups/launcher.wxs | 23 + Tools/msi/bundle/packagegroups/lib.wxs | 56 + Tools/msi/bundle/packagegroups/postinstall.wxs | 62 + Tools/msi/bundle/packagegroups/tcltk.wxs | 62 + Tools/msi/bundle/packagegroups/test.wxs | 56 + Tools/msi/bundle/packagegroups/tools.wxs | 24 + Tools/msi/bundle/postinstall_en-US.wxl_template | 4 + Tools/msi/bundle/releaselocal.wixproj | 21 + Tools/msi/bundle/releaseweb.wixproj | 21 + Tools/msi/bundle/snapshot.wixproj | 21 + Tools/msi/common.wxs | 101 + Tools/msi/common_en-US.wxl_template | 17 + Tools/msi/core/core.props | 12 + Tools/msi/core/core.wixproj | 11 + Tools/msi/core/core.wxs | 25 + Tools/msi/core/core_d.wixproj | 11 + Tools/msi/core/core_en-US.wxl | 5 + Tools/msi/core/core_files.wxs | 31 + Tools/msi/core/core_pdb.wixproj | 11 + Tools/msi/crt/crt.wixproj | 20 + Tools/msi/crt/crt.wxs | 26 + Tools/msi/crt/crt_en-US.wxl | 5 + Tools/msi/crt/crt_files.12.0.wxs | 20 + Tools/msi/crt/crt_files.14.0.wxs | 40 + Tools/msi/crt/crtlicense.txt | 47 + Tools/msi/crtlicense.txt | 44 - Tools/msi/csv_to_wxs.py | 127 + Tools/msi/dev/dev.props | 42 + Tools/msi/dev/dev.wixproj | 11 + Tools/msi/dev/dev.wxs | 25 + Tools/msi/dev/dev_d.wixproj | 11 + Tools/msi/dev/dev_en-US.wxl | 5 + Tools/msi/dev/dev_files.wxs | 42 + Tools/msi/doc/doc.wixproj | 30 + Tools/msi/doc/doc.wxs | 26 + Tools/msi/doc/doc_en-US.wxl_template | 7 + Tools/msi/doc/doc_files.wxs | 12 + Tools/msi/doc/doc_no_files.wxs | 17 + Tools/msi/exe/crtlicense.txt | 44 + Tools/msi/exe/exe.props | 36 + Tools/msi/exe/exe.wixproj | 11 + Tools/msi/exe/exe.wxs | 40 + Tools/msi/exe/exe_d.wixproj | 11 + Tools/msi/exe/exe_en-US.wxl_template | 9 + Tools/msi/exe/exe_files.wxs | 68 + Tools/msi/exe/exe_pdb.wixproj | 11 + Tools/msi/get_wix.py | 49 + Tools/msi/launcher/launcher.props | 12 + Tools/msi/launcher/launcher.wixproj | 11 + Tools/msi/launcher/launcher.wxs | 38 + Tools/msi/launcher/launcher_en-US.wxl | 8 + Tools/msi/launcher/launcher_files.wxs | 35 + Tools/msi/launcher/launcher_pdb.wixproj | 11 + Tools/msi/launcher/launcher_reg.wxs | 32 + Tools/msi/lib/lib.props | 27 + Tools/msi/lib/lib.wixproj | 11 + Tools/msi/lib/lib.wxs | 28 + Tools/msi/lib/lib_d.wixproj | 11 + Tools/msi/lib/lib_en-US.wxl | 5 + Tools/msi/lib/lib_files.wxs | 72 + Tools/msi/lib/lib_pdb.wixproj | 11 + Tools/msi/msi.props | 161 + Tools/msi/msi.py | 1454 ----- Tools/msi/msi.targets | 62 + Tools/msi/msilib.py | 679 -- Tools/msi/msisupport.c | 93 - Tools/msi/msisupport.mak | 9 - Tools/msi/path/path.wixproj | 19 + Tools/msi/path/path.wxs | 35 + Tools/msi/path/path_en-US.wxl | 6 + Tools/msi/pip/pip.wixproj | 19 + Tools/msi/pip/pip.wxs | 41 + Tools/msi/pip/pip_en-US.wxl | 6 + Tools/msi/schema.py | 1007 --- Tools/msi/sequence.py | 126 - Tools/msi/tcltk/tcltk.props | 49 + Tools/msi/tcltk/tcltk.wixproj | 11 + Tools/msi/tcltk/tcltk.wxs | 53 + Tools/msi/tcltk/tcltk_d.wixproj | 11 + Tools/msi/tcltk/tcltk_en-US.wxl_template | 8 + Tools/msi/tcltk/tcltk_files.wxs | 35 + Tools/msi/tcltk/tcltk_pdb.wixproj | 11 + Tools/msi/test/test.props | 22 + Tools/msi/test/test.wixproj | 11 + Tools/msi/test/test.wxs | 27 + Tools/msi/test/test_d.wixproj | 11 + Tools/msi/test/test_en-US.wxl | 7 + Tools/msi/test/test_files.wxs | 65 + Tools/msi/test/test_pdb.wixproj | 11 + Tools/msi/tools/tools.wixproj | 42 + Tools/msi/tools/tools.wxs | 14 + Tools/msi/tools/tools_en-US.wxl | 5 + Tools/msi/tools/tools_files.wxs | 16 + Tools/msi/uisample.py | 1400 ----- Tools/msi/wix.props | 12 + 134 files changed, 7080 insertions(+), 5035 deletions(-) diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -82,5 +82,6 @@ coverage/ externals/ htmlcov/ +Tools/msi/obj Tools/ssl/amd64 Tools/ssl/win32 diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -90,5 +90,6 @@ *.gcno *.gcov coverage.info +Tools/msi/obj Tools/ssl/amd64 Tools/ssl/win32 diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -8,11 +8,15 @@ if "%SPHINXBUILD%" EQU "" set SPHINXBUILD=sphinx-build if "%PYTHON%" EQU "" set PYTHON=py -if DEFINED ProgramFiles(x86) set _PRGMFLS=%ProgramFiles(x86)% -if NOT DEFINED ProgramFiles(x86) set _PRGMFLS=%ProgramFiles% -if "%HTMLHELP%" EQU "" set HTMLHELP=%_PRGMFLS%\HTML Help Workshop\hhc.exe +if "%HTMLHELP%" EQU "" ( + where hhc 2>nul >"%TEMP%\hhc.loc" + if errorlevel 1 dir "..\externals\hhc.exe" /s/b > "%TEMP%\hhc.loc" + if errorlevel 1 echo Cannot find HHC on PATH or in externals & exit /B 1 + set /P HTMLHELP= < "%TEMP%\hhc.loc" + del "%TEMP%\hhc.loc" +) -if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/patchlevel.py`) do set DISTVERSION=%%v +if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/extensions/patchlevel.py`) do set DISTVERSION=%%v if "%BUILDDIR%" EQU "" set BUILDDIR=build @@ -36,7 +40,8 @@ echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ - goto end + popd + exit /B 1 ) rem Targets that do require sphinx-build and have their own label diff --git a/Doc/using/win_installer.png b/Doc/using/win_installer.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4696bb2a400eb1c7ab18b48e9eda9a004e08749f GIT binary patch [stripped] diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -7,6 +7,7 @@ ************************* .. sectionauthor:: Robert Lehmann +.. sectionauthor:: Steve Dower This document aims to give an overview of Windows-specific behaviour you should know about when using Python on Microsoft Windows. @@ -19,10 +20,172 @@ Installing Python ================= -Unlike most Unix systems and services, Windows does not require Python natively -and thus does not pre-install a version of Python. However, the CPython team +Unlike most Unix systems and services, Windows does not include a system +supported installation of Python. To make Python available, the CPython team has compiled Windows installers (MSI packages) with every `release -`_ for many years. +`_ for many years. These installers +are primarily intended to add a system-wide installation of Python, with the +core interpreter and library being shared by all application. Non-shared +layouts of the Python interpreter may also be created with the same installer, +however, the released installer is not intended for embedding in other +installers. + +Installation Steps +------------------ + +Four Python 3.5 installers are available for download - two each for the 32-bit +and 64-bit versions of the interpreter. The *web installer* is a small initial +download, and it will automatically download the required components as +necessary. The *offline installer* includes the components necessary for a +default installation and only requires an internet connection for optional +features. See :ref:`install-layout-option` for other ways to avoid downloading +during installation. + +After starting the installer, one of three options may be selected: + +.. image:: win_installer.png + +If you select "Install for All Users": + +* You may be required to provide administrative credentials or approval +* Python will be installed into your Program Files directory +* The :ref:`launcher` will be installed into your Windows directory +* The standard library, test suite, launcher and pip will be installed +* After installation, the standard library will be pre-compiled to bytecode +* If selected, the install directory will be added to :envvar:`PATH` + +If you select "Install Just for Me": + +* You will *not* need to be an administrator +* Python will be installed into your user directory +* The :ref:`launcher` will *also* be installed into your user directory +* The standard library, test suite, launcher and pip will be installed +* If selected, the install directory will be added to :envvar:`PATH` + +Selecting "Customize installation" will allow you to select the features to +install, the installation location and other options or post-install actions. +To install debugging symbols or binaries, you will need to use this option. + +.. _install-quiet-option: + +Installing Without UI +--------------------- + +All of the options available in the installer UI can also be specified from the +command line, allowing scripted installers to replicate an installation on many +machines without user interaction. These options may also be set without +suppressing the UI in order to change some of the defaults. + +To completely hide the installer UI and install Python silently, pass the +``/quiet`` (``/q``) option. To skip past the user interaction but still display +progress and errors, pass the ``/passive`` (``/p``) option. The ``/uninstall`` +option may be passed to immediately begin removing Python - no prompt will be +displayed. + +All other options are passed as ``name=value``, where the value is usually +``0`` to disable a feature, ``1`` to enable a feature, or a path. The full list +of available options is shown below. + ++---------------------------+--------------------------------------+--------------------------+ +| Name | Description | Default | ++===========================+======================================+==========================+ +| InstallAllUsers | Perform a system-wide installation. | 1 | ++---------------------------+--------------------------------------+--------------------------+ +| TargetDir | The installation directory | Selected based on | +| | | InstallAllUsers | ++---------------------------+--------------------------------------+--------------------------+ +| DefaultAllUsersTargetDir | The default installation directory | :file:`%ProgramFiles%\\\ | +| | for all-user installs | Python X.Y` or :file:`\ | +| | | %ProgramFiles(x86)%\\\ | +| | | Python X.Y` | ++---------------------------+--------------------------------------+--------------------------+ +| DefaultJustForMeTargetDir | The default install directory for | :file:`%LocalAppData%\\\ | +| | just-for-me installs | Programs\\PythonXY` or | +| | | :file:`%LocalAppData%\\\ | +| | | Programs\\PythonXY-32` | ++---------------------------+--------------------------------------+--------------------------+ +| DefaultCustomTargetDir | The default custom install directory | (empty) | +| | displayed in the UI | | ++---------------------------+--------------------------------------+--------------------------+ +| AssociateFiles | Create file associations if the | 1 | +| | launcher is also installed. | | ++---------------------------+--------------------------------------+--------------------------+ +| CompileAll | Compile all ``.py`` files to | 0 | +| | ``.pyc`` and ``.pyo``. | | ++---------------------------+--------------------------------------+--------------------------+ +| PrependPath | Add install and Scripts directories | 0 | +| | tho :envvar:`PATH` and ``.PY`` to | | +| | :envvar:`PATHEXT` | | ++---------------------------+--------------------------------------+--------------------------+ +| Include_doc | Install Python manual | 1 | ++---------------------------+--------------------------------------+--------------------------+ +| Include_debug | Install debug binaries | 0 | ++---------------------------+--------------------------------------+--------------------------+ +| Include_dev | Install developer headers and | 1 | +| | libraries | | ++---------------------------+--------------------------------------+--------------------------+ +| Include_exe | Install :file:`python.exe` and | 1 | +| | related files | | ++---------------------------+--------------------------------------+--------------------------+ +| Include_launcher | Install :ref:`launcher`. | 1 | ++---------------------------+--------------------------------------+--------------------------+ +| Include_lib | Install standard library and | 1 | +| | extension modules | | ++---------------------------+--------------------------------------+--------------------------+ +| Include_pip | Install bundled pip and setuptools | 1 | ++---------------------------+--------------------------------------+--------------------------+ +| Include_symbols | Install debugging symbols (`*`.pdb) | 0 | ++---------------------------+--------------------------------------+--------------------------+ +| Include_tcltk | Install Tcl/Tk support and IDLE | 1 | ++---------------------------+--------------------------------------+--------------------------+ +| Include_test | Install standard library test suite | 1 | ++---------------------------+--------------------------------------+--------------------------+ +| Include_tools | Install utility scripts | 1 | ++---------------------------+--------------------------------------+--------------------------+ +| SimpleInstall | Disable most install UI | 0 | ++---------------------------+--------------------------------------+--------------------------+ + +For example, to silently install a default, system-wide Python installation, +you could use the following command (from an elevated command prompt):: + + python-3.5.0.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0 + +To allow users to easily install a personal copy of Python without the test +suite, you could provide a shortcut with the following command:: + + python-3.5.0.exe /passive InstallAllUsers=0 Include_launcher=0 Include_test=0 SimpleInstall=1 + +(Note that omitting the launcher also omits file associations, and is only +recommended for per-user installs when there is also a system-wide installation +that included the launcher.) + +.. _install-layout-option: + +Installing Without Downloading +------------------------------ + +As some features of Python are not included in the initial installer download, +selecting those features may require an internet connection. To avoid this +need, all possible components may be downloaded on-demand to create a complete +*layout* that will no longer require an internet connection regardless of the +selected features. Note that this download may be bigger than required, but +where a large number of installations are going to be performed it is very +useful to have a locally cached copy. + +Execute the following command from Command Prompt to download all possible +required files. Remember to substitute ``python-3.5.0.exe`` for the actual +name of your installer, and to create layouts in their own directories to +avoid collisions between files with the same name. + +:: + + python-3.5.0.exe /layout [optional target directory] + +You may also specify the ``/quiet`` option to hide the progress display. + + +Other Platforms +--------------- With ongoing development of Python, some platforms that used to be supported earlier are no longer supported (due to the lack of users or developers). @@ -66,19 +229,31 @@ `ActivePython `_ Installer with multi-platform compatibility, documentation, PyWin32 -`Enthought Python Distribution `_ - Popular modules (such as PyWin32) with their respective documentation, tool - suite for building extensible Python applications +`Anaconda `_ + Popular scientific modules (such as numpy, scipy and pandas) and the + ``conda`` package manager. -Notice that these packages are likely to install *older* versions of Python. +`Canopy `_ + A "comprehensive Python analysis environment" with editors and other + development tools. + +`WinPython `_ + Windows-specific distribution with prebuilt scientific packages and + tools for building packages. + +Note that these packages may not include the latest versions of Python or +other libraries, and are not maintained or supported by the core Python team. Configuring Python ================== -In order to run Python flawlessly, you might have to change certain environment -settings in Windows. +To run Python conveniently from a command prompt, you might consider changing +some default environment variables in Windows. While the installer provides an +option to configure the PATH and PATHEXT variables for you, this is only +reliable for a single, system-wide installation. If you regularly use multiple +versions of Python, consider using the :ref:`launcher`. .. _setting-envvars: @@ -86,163 +261,86 @@ Excursus: Setting environment variables --------------------------------------- -Windows has a built-in dialog for changing environment variables (following -guide applies to XP classical view): Right-click the icon for your machine -(usually located on your Desktop and called "My Computer") and choose -:menuselection:`Properties` there. Then, open the :guilabel:`Advanced` tab -and click the :guilabel:`Environment Variables` button. +Windows allows environment variables to be configured permanently at both the +User level and the System level, or temporarily in a command prompt. -In short, your path is: +To temporarily set environment variables, open Command Prompt and use the +:command:`set` command:: - :menuselection:`My Computer - --> Properties - --> Advanced - --> Environment Variables` + C:\>set PATH=C:\Program Files\Python 3.5;%PATH% + C:\>set PYTHONPATH=%PYTHONPATH%;C:\My_python_lib + C:\>python +These changes will apply to any further commands executed in that console, and +will be inherited by any applications started from the console. + +Including the variable name within percent signs will expand to the existing +value, allowing you to add your new value at either the start or the end. +Modifying :envvar:`PATH` by adding the directory containing +:program:`python.exe` to the start is a common way to ensure the correct version +of Python is launched. + +To permanently modify the default environment variables, click Start and search +for 'edit environment variables', or open System properties, :guilabel:`Advanced +system settings` and click the :guilabel:`Environment Variables` button. In this dialog, you can add or modify User and System variables. To change System variables, you need non-restricted access to your machine (i.e. Administrator rights). -Another way of adding variables to your environment is using the :command:`set` -command:: +.. note:: - set PYTHONPATH=%PYTHONPATH%;C:\My_python_lib + Windows will concatenate User variables *after* System variables, which may + cause unexpected results when modifying :envvar:`PATH`. -To make this setting permanent, you could add the corresponding command line to -your :file:`autoexec.bat`. :program:`msconfig` is a graphical interface to this -file. - -Viewing environment variables can also be done more straight-forward: The -command prompt will expand strings wrapped into percent signs automatically:: - - echo %PATH% - -Consult :command:`set /?` for details on this behaviour. + The :envvar:`PYTHONPATH` variable is used by all versions of Python 2 and + Python 3, so you should not permanently configure this variable unless it + only includes code that is compatible all of your installed Python + versions. .. seealso:: - http://support.microsoft.com/kb/100843 + http://support.microsoft.com/kb/100843 Environment variables in Windows NT - http://support.microsoft.com/kb/310519 + http://technet.microsoft.com/en-us/library/cc754250.aspx + The SET command, for temporarily modifying environment variables + + http://technet.microsoft.com/en-us/library/cc755104.aspx + The SETX command, for permanently modifying environment variables + + http://support.microsoft.com/kb/310519 How To Manage Environment Variables in Windows XP - http://www.chem.gla.ac.uk/~louis/software/faq/q1.html + http://www.chem.gla.ac.uk/~louis/software/faq/q1.html Setting Environment variables, Louis J. Farrugia - .. _windows-path-mod: Finding the Python executable ----------------------------- -.. versionchanged:: 3.3 +.. versionchanged:: 3.5 Besides using the automatically created start menu entry for the Python -interpreter, you might want to start Python in the command prompt. As of -Python 3.3, the installer has an option to set that up for you. +interpreter, you might want to start Python in the command prompt. The +installer for Python 3.5 and later has an option to set that up for you. -At the "Customize Python 3.3" screen, an option called -"Add python.exe to search path" can be enabled to have the installer place -your installation into the :envvar:`%PATH%`. This allows you to type -:command:`python` to run the interpreter. Thus, you can also execute your +On the first page of the installer, an option labelled "Add Python 3.5 to +PATH" can be selected to have the installer add the install location into the +:envvar:`PATH`. The location of the :file:`Scripts\\` folder is also added. +This allows you to type :command:`python` to run the interpreter, and +:command:`pip` or . Thus, you can also execute your scripts with command line options, see :ref:`using-on-cmdline` documentation. If you don't enable this option at install time, you can always re-run the -installer to choose it. +installer, select Modify, and enable it. Alternatively, you can manually +modify the :envvar:`PATH` using the directions in :ref:`setting-envvars`. You +need to set your :envvar:`PATH` environment variable to include the directory +of your Python installation, delimited by a semicolon from other entries. An +example variable could look like this (assuming the first two entries already +existed):: -The alternative is manually modifying the :envvar:`%PATH%` using the -directions in :ref:`setting-envvars`. You need to set your :envvar:`%PATH%` -environment variable to include the directory of your Python distribution, -delimited by a semicolon from other entries. An example variable could look -like this (assuming the first two entries are Windows' default):: - - C:\WINDOWS\system32;C:\WINDOWS;C:\Python33 - - -Finding modules ---------------- - -Python usually stores its library (and thereby your site-packages folder) in the -installation directory. So, if you had installed Python to -:file:`C:\\Python\\`, the default library would reside in -:file:`C:\\Python\\Lib\\` and third-party modules should be stored in -:file:`C:\\Python\\Lib\\site-packages\\`. - -This is how :data:`sys.path` is populated on Windows: - -* An empty entry is added at the start, which corresponds to the current - directory. - -* If the environment variable :envvar:`PYTHONPATH` exists, as described in - :ref:`using-on-envvars`, its entries are added next. Note that on Windows, - paths in this variable must be separated by semicolons, to distinguish them - from the colon used in drive identifiers (``C:\`` etc.). - -* Additional "application paths" can be added in the registry as subkeys of - :samp:`\\SOFTWARE\\Python\\PythonCore\\{version}\\PythonPath` under both the - ``HKEY_CURRENT_USER`` and ``HKEY_LOCAL_MACHINE`` hives. Subkeys which have - semicolon-delimited path strings as their default value will cause each path - to be added to :data:`sys.path`. (Note that all known installers only use - HKLM, so HKCU is typically empty.) - -* If the environment variable :envvar:`PYTHONHOME` is set, it is assumed as - "Python Home". Otherwise, the path of the main Python executable is used to - locate a "landmark file" (``Lib\os.py``) to deduce the "Python Home". If a - Python home is found, the relevant sub-directories added to :data:`sys.path` - (``Lib``, ``plat-win``, etc) are based on that folder. Otherwise, the core - Python path is constructed from the PythonPath stored in the registry. - -* If the Python Home cannot be located, no :envvar:`PYTHONPATH` is specified in - the environment, and no registry entries can be found, a default path with - relative entries is used (e.g. ``.\Lib;.\plat-win``, etc). - -The end result of all this is: - -* When running :file:`python.exe`, or any other .exe in the main Python - directory (either an installed version, or directly from the PCbuild - directory), the core path is deduced, and the core paths in the registry are - ignored. Other "application paths" in the registry are always read. - -* When Python is hosted in another .exe (different directory, embedded via COM, - etc), the "Python Home" will not be deduced, so the core path from the - registry is used. Other "application paths" in the registry are always read. - -* If Python can't find its home and there is no registry (eg, frozen .exe, some - very strange installation setup) you get a path with some default, but - relative, paths. - - -Executing scripts ------------------ - -As of Python 3.3, Python includes a launcher which facilitates running Python -scripts. See :ref:`launcher` for more information. - -Executing scripts without the Python launcher ---------------------------------------------- - -Without the Python launcher installed, Python scripts (files with the extension -``.py``) will be executed by :program:`python.exe` by default. This executable -opens a terminal, which stays open even if the program uses a GUI. If you do -not want this to happen, use the extension ``.pyw`` which will cause the script -to be executed by :program:`pythonw.exe` by default (both executables are -located in the top-level of your Python installation directory). This -suppresses the terminal window on startup. - -You can also make all ``.py`` scripts execute with :program:`pythonw.exe`, -setting this through the usual facilities, for example (might require -administrative rights): - -#. Launch a command prompt. -#. Associate the correct file group with ``.py`` scripts:: - - assoc .py=Python.File - -#. Redirect all Python files to the new executable:: - - ftype Python.File=C:\Path\to\pythonw.exe "%1" %* - + C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Python 3.5 .. _launcher: @@ -251,21 +349,26 @@ .. versionadded:: 3.3 -The Python launcher for Windows is a utility which aids in the location and -execution of different Python versions. It allows scripts (or the +The Python launcher for Windows is a utility which aids in locating and +executing of different Python versions. It allows scripts (or the command-line) to indicate a preference for a specific Python version, and will locate and execute that version. +Unlike the :envvar:`PATH` variable, the launcher will correctly select the most +appropriate version of Python. It will prefer per-user installations over +system-wide ones, and orders by language version rather than using the most +recently installed version. + Getting started --------------- From the command-line ^^^^^^^^^^^^^^^^^^^^^ -You should ensure the launcher is on your PATH - depending on how it was -installed it may already be there, but check just in case it is not. - -From a command-prompt, execute the following command: +System-wide installations of Python 3.3 and later will put the launcher on your +:envvar:`PATH`. The launcher is compatible with all available versions of +Python, so it does not matter which version is installed. To check that the +launcher is available, execute the following command in Command Prompt: :: @@ -291,6 +394,16 @@ You should find the latest version of Python 3.x starts. +If you see the following error, you do not have the launcher installed: + +:: + + 'py' is not recognized as an internal or external command, + operable program or batch file. + +Per-user installations of Python do not add the launcher to :envvar:`PATH` +unless the option was selected on installation. + From a script ^^^^^^^^^^^^^ @@ -383,17 +496,16 @@ Customization via INI files ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Two .ini files will be searched by the launcher - ``py.ini`` in the - current user's "application data" directory (i.e. the directory returned - by calling the Windows function SHGetFolderPath with CSIDL_LOCAL_APPDATA) - and ``py.ini`` in the same directory as the launcher. The same .ini - files are used for both the 'console' version of the launcher (i.e. - py.exe) and for the 'windows' version (i.e. pyw.exe) +Two .ini files will be searched by the launcher - ``py.ini`` in the current +user's "application data" directory (i.e. the directory returned by calling the +Windows function SHGetFolderPath with CSIDL_LOCAL_APPDATA) and ``py.ini`` in the +same directory as the launcher. The same .ini files are used for both the +'console' version of the launcher (i.e. py.exe) and for the 'windows' version +(i.e. pyw.exe) - Customization specified in the "application directory" will have - precedence over the one next to the executable, so a user, who may not - have write access to the .ini file next to the launcher, can override - commands in that global .ini file) +Customization specified in the "application directory" will have precedence over +the one next to the executable, so a user, who may not have write access to the +.ini file next to the launcher, can override commands in that global .ini file) Customizing default Python versions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -488,6 +600,78 @@ target Python. + +Finding modules +=============== + +Python usually stores its library (and thereby your site-packages folder) in the +installation directory. So, if you had installed Python to +:file:`C:\\Python\\`, the default library would reside in +:file:`C:\\Python\\Lib\\` and third-party modules should be stored in +:file:`C:\\Python\\Lib\\site-packages\\`. + +This is how :data:`sys.path` is populated on Windows: + +* An empty entry is added at the start, which corresponds to the current + directory. + +* If the environment variable :envvar:`PYTHONPATH` exists, as described in + :ref:`using-on-envvars`, its entries are added next. Note that on Windows, + paths in this variable must be separated by semicolons, to distinguish them + from the colon used in drive identifiers (``C:\`` etc.). + +* Additional "application paths" can be added in the registry as subkeys of + :samp:`\\SOFTWARE\\Python\\PythonCore\\{version}\\PythonPath` under both the + ``HKEY_CURRENT_USER`` and ``HKEY_LOCAL_MACHINE`` hives. Subkeys which have + semicolon-delimited path strings as their default value will cause each path + to be added to :data:`sys.path`. (Note that all known installers only use + HKLM, so HKCU is typically empty.) + +* If the environment variable :envvar:`PYTHONHOME` is set, it is assumed as + "Python Home". Otherwise, the path of the main Python executable is used to + locate a "landmark file" (``Lib\os.py``) to deduce the "Python Home". If a + Python home is found, the relevant sub-directories added to :data:`sys.path` + (``Lib``, ``plat-win``, etc) are based on that folder. Otherwise, the core + Python path is constructed from the PythonPath stored in the registry. + +* If the Python Home cannot be located, no :envvar:`PYTHONPATH` is specified in + the environment, and no registry entries can be found, a default path with + relative entries is used (e.g. ``.\Lib;.\plat-win``, etc). + +The end result of all this is: + +* When running :file:`python.exe`, or any other .exe in the main Python + directory (either an installed version, or directly from the PCbuild + directory), the core path is deduced, and the core paths in the registry are + ignored. Other "application paths" in the registry are always read. + +* When Python is hosted in another .exe (different directory, embedded via COM, + etc), the "Python Home" will not be deduced, so the core path from the + registry is used. Other "application paths" in the registry are always read. + +* If Python can't find its home and there is no registry (eg, frozen .exe, some + very strange installation setup) you get a path with some default, but + relative, paths. + +For those who want to bundle Python into their application or distribution, the +following advice will prevent conflicts with other installations: + +* If you are loading :file:`python3.dll` or :file:`python35.dll` in your own + executable, explicitly call :c:func:`Py_SetPath` or (at least) + :c:func:`Py_SetProgramName` before :c:func:`Py_Initialize`. + +* Clear and/or overwrite :envvar:`PYTHONPATH` and set :envvar:`PYTHONHOME` + before launching :file:`python.exe` from your application. + +* If you cannot use the previous suggestions (for example, you are a + distribution that allows people to run :file:`python.exe` directly), ensure + that the landmark file (:file:`Lib\\os.py`) exists in your bundled library. + (Note that it will not be detected inside a ZIP file.) + +These will ensure that the files in a system-wide installation will not take +precedence over the copy of the standard library bundled with your application. +Otherwise, your users may experience problems using your application. + Additional modules ================== @@ -498,7 +682,6 @@ The Windows-specific standard modules are documented in :ref:`mswin-specific-services`. - PyWin32 ------- @@ -557,20 +740,8 @@ `_. The source tree contains a build solution and project files for Microsoft -Visual C++, which is the compiler used to build the official Python releases. -View the :file:`readme.txt` in their respective directories: - -+--------------------+--------------+-----------------------+ -| Directory | MSVC version | Visual Studio version | -+====================+==============+=======================+ -| :file:`PC/VS9.0/` | 9.0 | 2008 | -+--------------------+--------------+-----------------------+ -| :file:`PCbuild/` | 10.0 | 2010 | -+--------------------+--------------+-----------------------+ - -Note that any build directories within the :file:`PC` directory are not -necessarily fully supported. The :file:`PCbuild` directory contains the files -for the compiler used to build the official release. +Visual Studio 2015, which is the compiler used to build the official Python +releases. These files are in the :file:`PCbuild` directory. Check :file:`PCbuild/readme.txt` for general information on the build process. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1778,6 +1778,8 @@ Windows ------- +- Issue #23260: Update Windows installer + - The bundled version of Tcl/Tk has been updated to 8.6.3. The most visible result of this change is the addition of new native file dialogs when running on Windows Vista or newer. See Tcl/Tk's TIP 432 for more diff --git a/PC/launcher.c b/PC/launcher.c --- a/PC/launcher.c +++ b/PC/launcher.c @@ -157,14 +157,19 @@ static size_t num_installed_pythons = 0; -/* to hold SOFTWARE\Python\PythonCore\X.Y\InstallPath */ +/* + * To hold SOFTWARE\Python\PythonCore\X.Y...\InstallPath + * The version name can be longer than MAX_VERSION_SIZE, but will be + * truncated to just X.Y for comparisons. + */ #define IP_BASE_SIZE 40 -#define IP_SIZE (IP_BASE_SIZE + MAX_VERSION_SIZE) +#define IP_VERSION_SIZE 8 +#define IP_SIZE (IP_BASE_SIZE + IP_VERSION_SIZE) #define CORE_PATH L"SOFTWARE\\Python\\PythonCore" static wchar_t * location_checks[] = { L"\\", - L"\\PCBuild\\", + L"\\PCBuild\\win32\\", L"\\PCBuild\\amd64\\", NULL }; @@ -196,6 +201,7 @@ BOOL ok; DWORD type, data_size, attrs; INSTALLED_PYTHON * ip, * pip; + wchar_t ip_version[IP_VERSION_SIZE]; wchar_t ip_path[IP_SIZE]; wchar_t * check; wchar_t ** checkp; @@ -207,19 +213,21 @@ else { ip = &installed_pythons[num_installed_pythons]; for (i = 0; num_installed_pythons < MAX_INSTALLED_PYTHONS; i++) { - status = RegEnumKeyW(core_root, i, ip->version, MAX_VERSION_SIZE); + status = RegEnumKeyW(core_root, i, ip_version, IP_VERSION_SIZE); if (status != ERROR_SUCCESS) { if (status != ERROR_NO_MORE_ITEMS) { /* unexpected error */ winerror(status, message, MSGSIZE); debug(L"Can't enumerate registry key for version %ls: %ls\n", - ip->version, message); + ip_version, message); } break; } else { + wcsncpy_s(ip->version, MAX_VERSION_SIZE, ip_version, + MAX_VERSION_SIZE-1); _snwprintf_s(ip_path, IP_SIZE, _TRUNCATE, - L"%ls\\%ls\\InstallPath", CORE_PATH, ip->version); + L"%ls\\%ls\\InstallPath", CORE_PATH, ip_version); status = RegOpenKeyExW(root, ip_path, 0, flags, &ip_key); if (status != ERROR_SUCCESS) { winerror(status, message, MSGSIZE); diff --git a/PCbuild/_freeze_importlib.vcxproj b/PCbuild/_freeze_importlib.vcxproj --- a/PCbuild/_freeze_importlib.vcxproj +++ b/PCbuild/_freeze_importlib.vcxproj @@ -81,7 +81,7 @@ - + @@ -93,9 +93,10 @@ DestinationFiles="$(PySourcePath)Python\importlib.h" Condition="Exists('$(IntDir)importlib.g.h') and '$(_OldContent)' != '$(_NewContent)'" /> - + + diff --git a/PCbuild/libeay.vcxproj b/PCbuild/libeay.vcxproj --- a/PCbuild/libeay.vcxproj +++ b/PCbuild/libeay.vcxproj @@ -41,8 +41,12 @@ + + + StaticLibrary + + - diff --git a/PCbuild/pylauncher.vcxproj b/PCbuild/pylauncher.vcxproj --- a/PCbuild/pylauncher.vcxproj +++ b/PCbuild/pylauncher.vcxproj @@ -61,6 +61,7 @@ _CONSOLE;%(PreprocessorDefinitions) + MultiThreaded version.lib;%(AdditionalDependencies) diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -11,6 +11,9 @@ false false true + true + false + false @@ -138,4 +141,16 @@ Condition="Exists(%(FullPath))" Targets="CleanAll" /> + + + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot81)\bin\x86\signtool.exe + $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Kits\Installed Roots at KitsRoot)\bin\x86\signtool.exe + $(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A at InstallationFolder)\Bin\signtool.exe + <_SignCommand Condition="Exists($(SignToolPath))">"$(SignToolPath)" sign /q /n "$(SigningCertificate)" /t http://timestamp.verisign.com/scripts/timestamp.dll /d "Python $(PythonVersion)" + + + + + + \ No newline at end of file diff --git a/PCbuild/python.props b/PCbuild/python.props --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -1,7 +1,7 @@ - + - Win32 + Win32 Release - .cp$(MajorVersionNumber)$(MinorVersionNumber)-win32 + .cp$(MajorVersionNumber)$(MinorVersionNumber)-win32 .cp$(MajorVersionNumber)$(MinorVersionNumber)-win_amd64 $(MajorVersionNumber).$(MinorVersionNumber) - $(SysWinVer)-32 + $(SysWinVer)-32 diff --git a/PCbuild/pywlauncher.vcxproj b/PCbuild/pywlauncher.vcxproj --- a/PCbuild/pywlauncher.vcxproj +++ b/PCbuild/pywlauncher.vcxproj @@ -61,6 +61,7 @@ _WINDOWS;%(PreprocessorDefinitions) + MultiThreaded version.lib;%(AdditionalDependencies) diff --git a/PCbuild/ssleay.vcxproj b/PCbuild/ssleay.vcxproj --- a/PCbuild/ssleay.vcxproj +++ b/PCbuild/ssleay.vcxproj @@ -41,8 +41,12 @@ + + + StaticLibrary + + - diff --git a/Tools/buildbot/buildmsi.bat b/Tools/buildbot/buildmsi.bat --- a/Tools/buildbot/buildmsi.bat +++ b/Tools/buildbot/buildmsi.bat @@ -1,21 +1,9 @@ @rem Used by the buildbot "buildmsi" step. setlocal -set cwd=%CD% +pushd - at rem build release versions of things -call "%~dp0build.bat" -c Release + at rem build both snapshot MSIs +call "%~dp0..\msi\build.bat" -x86 -x64 - at rem build the documentation -call "%~dp0..\..\Doc\make.bat" htmlhelp - - at rem build the MSI file -call "%~dp0..\..\PCBuild\env.bat" x86 -cd "%~dp0..\..\PC" -nmake /f icons.mak -cd ..\Tools\msi -del *.msi -nmake /f msisupport.mak -%HOST_PYTHON% msi.py - -cd "%cwd%" +popd \ No newline at end of file diff --git a/Tools/msi/README.txt b/Tools/msi/README.txt --- a/Tools/msi/README.txt +++ b/Tools/msi/README.txt @@ -1,25 +1,488 @@ -Packaging Python as a Microsoft Installer Package (MSI) -======================================================= +Quick Build Info +================ -Using this library, Python can be packaged as a MS-Windows -MSI file. To generate an installer package, you need -a build tree. By default, the build tree root directory -is assumed to be in "../..". This location can be changed -by adding a file config.py; see the beginning of msi.py -for additional customization options. +For testing, the installer should be built with the Tools/msi/build.bat +script: -The packaging process assumes that binaries have been -generated according to the instructions in PCBuild/README.txt, -and that you have either Visual Studio or the Platform SDK -installed. In addition, you need the Python COM extensions, -either from PythonWin, or from ActivePython. + build.bat [-x86] [-x64] [--doc] -To invoke the script, open a cmd.exe window which has -cabarc.exe in its PATH (e.g. "Visual Studio .NET 2003 -Command Prompt"). Then invoke +For an official release, the installer should be built with the +Tools/msi/buildrelease.bat script and environment variables: - msi.py + set PYTHON= + set SPHINXBUILD= + set PATH=; + ;%PATH% -If everything succeeds, pythonX.Y.Z.msi is generated -in the current directory. + buildrelease.bat [-x86] [-x64] [-D] [-B] + [-o ] [-c ] +See the Building the Installer section for more information. + +Overview +======== + +Python is distributed on Windows as an installer that will configure the +user's system. This allows users to have a functioning copy of Python +without having to build it themselves. + +The main tasks of the installer are: + +* copy required files into the expected layout +* configure system settings so the installation can be located by + other programs +* add entry points for modifying, repairing and uninstalling Python +* make it easy to launch Python, its documentation, and IDLE + +Each of these is discussed in a later section of this document. + +Structure of the Installer +========================== + +The installer is structured as a 'layout', which consists of a number of +CAB and MSI files and a single EXE. + +The EXE is the main entry point into the installer. It contains the UI +and command-line logic, as well as the ability to locate and optionally +download other parts of the layout. + +Each MSI contains the logic required to install a component or feature +of Python. These MSIs should not be launched directly by users. MSIs can +be embedded into the EXE or automatically downloaded as needed. + +Each CAB contains the files making up a Python installation. CABs are +embedded into their associated MSI and are never seen by users. + +MSIs are only required when the related feature or component is being +installed. When components are not selected for installation, the +associated MSI is not downloaded. This allows the installer to offer +options to install debugging symbols and binaries without increasing +the initial download size by separating them into their own MSIs. + +Building the Installer +====================== + +For testing, the installer should be built with the Tools/msi/build.bat +script: + + build.bat [-x86] [-x64] [--doc] + +This script will build the required configurations of Python and +generate an installer layout in PCBuild/(win32|amd64)/en-us. + +Specify -x86 and/or -x64 to build for each platform. If neither is +specified, both platforms will be built. Currently, both the debug and +release versions of Python are required for the installer. + +Specify --doc to build the documentation (.chm) file. If the file is not +available, it will simply be excluded from the installer. Ensure +%PYTHON% and %SPHINXBUILD% are set when passing this option. You may +also set %HTMLHELP% to the Html Help Compiler (hhc.exe), or put HHC on +your PATH or in externals/. + +If WiX is not found on your system, it will be automatically downloaded +and extracted to the externals/ directory. + + +For an official release, the installer should be built with the +Tools/msi/buildrelease.bat script: + + set PYTHON= + set SPHINXBUILD= + set PATH=; + ;%PATH% + + buildrelease.bat [-x86] [-x64] [-D] [-B] + [-o ] [-c ] + +Specify -x86 and/or -x64 to build for each platform. If neither is +specified, both platforms will be built. Currently, both the debug and +release versions of Python are required for the installer. + +Specify -D to skip rebuilding the documentation. The documentation is +required for a release and the build will fail if it is not available. + +Specify -B to skip rebuilding Python. This is useful to only rebuild the +installer layout after a previous call to buildrelease.bat. + +Specify -o to set an output directory. The installer layouts will be +copied to platform-specific subdirectories of this path. + +Specify -c to choose a code-signing certificate to be used for all the +signable binaries in Python as well as each file making up the +installer. Official releases of Python must be signed. + +Ensure %PYTHON% and %SPHINXBUILD% are set when passing this option. You +may also set %HTMLHELP% to the Html Help Compiler (hhc.exe), or put HHC +on your PATH or in externals/. You will also need Mercurial (hg.exe) on +your PATH. + +If WiX is not found on your system, it will be automatically downloaded +and extracted to the externals/ directory. + +To manually build layouts of the installer, build one of the projects in +the bundle folder. + + msbuild bundle\snapshot.wixproj + msbuild bundle\releaseweb.wixproj + msbuild bundle\releaselocal.wixproj + msbuild bundle\full.wixproj + +snapshot.wixproj produces a test installer versioned based on the date. + +releaseweb.wixproj produces a release installer that does not embed any +of the layout. + +releaselocal.wixproj produces a release installer that embeds the files +required for a default installation. + +full.wixproj produces a test installer that embeds the entire layout. + +The following properties may be passed when building these projects. + + /p:BuildForRelease=(true|false) + When true, adds extra verification to ensure a complete installer is + produced. For example, binutils is required when building for a release + to generate MinGW-compatible libraries, and the build will be aborted if + this fails. Defaults to false. + + /p:ReleaseUri=(any URI) + Used to generate unique IDs for the installers to allow side-by-side + installation. Forks of Python can use the same installer infrastructure + by providing a unique URI for this property. It does not need to be an + active internet address. Defaults to $(ComputerName). + + Official releases use http://www.python.org/(architecture name) + + /p:DownloadUrlBase=(any URI) + Specifies the base of a URL where missing parts of the installer layout + can be downloaded from. The build version and architecture will be + appended to create the full address. If omitted, missing components will + not be automatically downloaded. + + /p:DownloadUrl=(any URI) + Specifies the full URL where missing parts of the installer layout can + be downloaded from. Should normally include '{2}', which will be + substituted for the filename. If omitted, missing components will not be + automatically downloaded. If specified, this value overrides + DownloadUrlBase. + + /p:SigningCertificate=(certificate name) + Specifies the certificate to sign the installer layout with. If omitted, + the layout will not be signed. + + /p:RebuildAll=(true|false) + When true, rebuilds all of the MSIs making up the layout. Defaults to + true. + +Modifying the Installer +======================= + +The code for the installer is divided into three main groups: packages, +the bundle and the bootstrap application. + +Packages +-------- + +Packages appear as subdirectories of Tools/msi (other than the bundle/ +directory). The project file is a .wixproj and the build output is a +single MSI. Packages are built with the WiX Toolset. Some project files +share source files and use preprocessor directives to enable particular +features. These are typically used to keep the sources close when the +files are related, but produce multiple independent packages. + +A package is the smallest element that may be independently installed or +uninstalled (as used in this installer). For example, the test suite has +its own package, as users can choose to add or remove it after the +initial installation. + +All the files installed by a single package should be related, though +some packages may not install any files. For example, the pip package +executes the ensurepip package, but does not add or remove any of its +own files. (It is represented as a package because of its +installed/uninstalled nature, as opposed to the "precompile standard +library" option, for example.) Dependencies between packages are handled +by the bundle, but packages should detect when dependencies are missing +and raise an error. + +Packages that include a lot of files may use an InstallFiles element in +the .wixproj file to generate sources. See lib/lib.wixproj for an +example, and msi.targets and csv_to_wxs.py for the implementation. This +element is also responsible for generating the code for cleaning up and +removing __pycache__ folders in any directory containing .py files. + +All packages are built with the Tools/msi/common.wxs file, and so any +directory or property in this file may be referenced. Of particular +interest: + + REGISTRYKEY (property) + The registry key for the current installation. + + InstallDirectory (directory) + The root install directory for the current installation. Subdirectories + are also specified in this file (DLLs, Lib, etc.) + + MenuDir (directory) + The Start Menu folder for the current installation. + + UpgradeTable (property) + Every package should reference this property to include upgrade + information. + +The .wxl_template file is specially handled by the build system for this +project to perform {{substitutions}} as defined in msi.targets. They +should be included in projects as items, where .wxl files +are normally included as items. + +Bundle +------ + +The bundle is compiled to the main EXE entry point that for most users +will represent the Python installer. It is built from Tools/msi/bundle +with packages references in Tools/msi/bundle/packagegroups. + +Build logic for the bundle is in bundle.targets, but should be invoked +through one of the .wixproj files as described in Building the +Installer. + +The UI is separated between Default.thm (UI layout), Default.wxl +(strings), bundle.wxs (properties) and the bootstrap application. +Bundle.wxs also contains the chain, which is the list of packages to +install and the order they should be installed in. These refer to named +package groups in bundle/packagegroups. + +Each package group specifies one or more packages to install. Most +packages require two separate entries to support both per-user and +all-users installations. Because these reuse the same package, it does +not increase the overall size of the package. + +Package groups refer to payload groups, which allow better control over +embedding and downloading files than the default settings. Whether files +are embedded and where they are downloaded from depends on settings +created by the project files. + +Package references can include install conditions that determine when to +install the package. When a package is a dependency for others, the +condition should be crafted to ensure it is installed. + +MSI packages are installed or uninstalled based on their current state +and the install condition. This makes them most suitable for features +that are clearly present or absent from the user's machine. + +EXE packages are executed based on a customisable condition that can be +omitted. This makes them suitable for pre- or post-install tasks that +need to run regardless of whether features have been added or removed. + +Bootstrap Application +--------------------- + +The bootstrap application is a C++ application that controls the UI and +installation. While it does not directly compile into the main EXE of +the installer, it forms the main active component. Most of the +installation functionality is provided by WiX, and so the bootstrap +application is predominantly responsible for the code behind the UI that +is defined in the Default.thm file. The bootstrap application code is in +bundle/bootstrap and is built automatically when building the bundle. + +Installation Layout +=================== + +There are two installation layouts for Python on Windows, with the only +differences being supporting files. A layout is selected implicitly +based on whether the install is for all users of the machine or just for +the user performing the installation. + +The default installation location when installing for all users is +"%ProgramFiles%\Python 3.X" for the 64-bit interpreter and +"%ProgramFiles(x86)%\Python 3.X" for the 32-bit interpreter. (Note that +the latter path is equivalent to "%ProgramFiles%\Python 3.X" when +running a 32-bit version of Windows.) This location requires +administrative privileges to install or later modify the installation. + +The default installation location when installing for the current user +is "%LocalAppData%\Programs\Python\Python3X" for the 64-bit interpreter +and "%LocalAppData%\Programs\Python\Python3X-32" for the 32-bit +interpreter. Only the current user can access this location. This +provides a suitable level of protection against malicious modification +of Python's files. + +Within this install directory is the following approximate layout: + +.\python[w].exe The core executable files +.\DLLs Stdlib extensions (*.pyd) and dependencies +.\Doc Documentation (*.chm) +.\include Development headers (*.h) +.\Lib Standard library +.\Lib\test Test suite +.\libs Development libraries (*.lib) +.\Scripts Launcher scripts (*.exe, *.py) +.\tcl Tcl dependencies (*.dll, *.tcl and others) +.\Tools Tool scripts (*.py) + +When installed for all users, the following files are installed to +either "%SystemRoot%\System32" or "%SystemRoot%\SysWOW64" as +appropriate. For the current user, they are installed in the Python +install directory. + +.\python3x.dll The core interpreter +.\python3.dll The stable ABI reference +.\appcrt140.dll Microsoft Visual C Runtime +.\desktopcrt140.dll Microsoft Visual C Runtime +.\vcruntime140.dll Microsoft Visual C Runtime + +When installed for all users, the following files are installed to +"%SystemRoot%" (typically "C:\Windows") to ensure they are always +available on PATH. (See Launching Python below.) For the current user, +they are installed in the Python install directory. + +.\py[w].exe PEP 397 launcher + +System Settings +=============== + +On installation, registry keys are created so that other applications +can locate and identify installations of Python. The locations of these +keys vary based on the install type. + +For 64-bit interpreters installed for all users, the root key is: + HKEY_LOCAL_MACHINE\Software\Python\PythonCore\3.X + +For 32-bit interpreters installed for all users on a 64-bit operating +system, the root key is: + HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\PythonCore\3.X-32 + +For 32-bit interpreters installed for all users on a 32-bit operating +system, the root key is: + HKEY_LOCAL_MACHINE\Software\Python\PythonCore\3.X-32 + +For 64-bit interpreters installed for the current user: + HKEY_CURRENT_USER\Software\Python\PythonCore\3.X + +For 32-bit interpreters installed for the current user: + HKEY_CURRENT_USER\Software\Python\PythonCore\3.X-32 + +When the core Python executables are installed, a key "InstallPath" is +created within the root key with its default value set to the +executable's install directory. Within this key, a key "InstallGroup" is +created with its default value set to the product name "Python 3.X". + +When the Python standard library is installed, a key "PythonPath" is +created within the root key with its default value set to the full path +to the Lib folder followed by the path to the DLLs folder, separated by +a semicolon. + +When the documentation is installed, a key "Help" is created within the +root key, with a subkey "Main Python Documentation" with its default +value set to the full path to the installed CHM file. + + +The py.exe launcher is installed as part of a regular Python install, +but using a separate mechanism that allows it to more easily span +versions of Python. As a result, it has different root keys for its +registry entries: + +When installed for all users on a 64-bit operating system, the +launcher's root key is: + HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\Launcher + +When installed for all users on a 32-bit operating system, the +launcher's root key is: + HKEY_LOCAL_MACHINE\Software\Python\Launcher + +When installed for the current user: + HKEY_CURRENT_USER\Software\Python\Launcher + +When the launcher is installed, a key "InstallPath" is created within +its root key with its default value set to the launcher's install +directory. File associations are also created for .py, .pyw, .pyc and +.pyo files. + +Launching Python +================ + +When a feature offering user entry points in the Start Menu is +installed, a folder "Python 3.X" is created. Every shortcut should be +created within this folder, and each shortcut should include the version +and platform to allow users to identify the shortcut in a search results +page. + +The core Python executables creates a shortcut "Python 3.X (32-bit)" or +"Python 3.X (64-bit)" depending on the interpreter. + +The documentation creates a shortcut "Python 3.X 32-bit Manuals" or +"Python 3.X 64-bit Manuals". The documentation is identical for all +platforms, but the shortcuts need to be separate to avoid uninstallation +conflicts. + +Installing IDLE creates a shortcut "IDLE (Python 3.X 32-bit)" or "IDLE +(Python 3.X 64-bit)" depending on the interpreter. + + +For users who often launch Python from a Command Prompt, an option is +provided to add the directory containing python.exe to the user or +system PATH variable. If the option is selected, the install directory +and the Scripts directory will be added at the start of the system PATH +for an all users install and the user PATH for a per-user install. + +When the user only has one version of Python installed, this will behave +as expected. However, because Windows searches the system PATH before +the user PATH, users cannot override a system-wide installation of +Python on their PATH. Further, because the installer can only prepend to +the path, later installations of Python will take precedence over +earlier installations, regardless of interpreter version. + +Because it is not possible to automatically create a sensible PATH +configuration, users are recommended to use the py.exe launcher and +manually modify their PATH variable to add Scripts directories in their +preferred order. System-wide installations of Python should consider not +modifying PATH, or using an alternative technology to modify their +users' PATH variables. + + +The py.exe launcher is recommended because it uses a consistent and +sensible search order for Python installations. User installations are +preferred over system-wide installs, and later versions are preferred +regardless of installation order (with the exception that py.exe +currently prefers 2.x versions over 3.x versions without the -3 command +line argument). + +For both 32-bit and 64-bit interpreters, the 32-bit version of the +launcher is installed. This ensures that the search order is always +consistent (as the 64-bit launcher is subtly different from the 32-bit +launcher) and also avoids the need to install it multiple times. Future +versions of Python will upgrade the launcher in-place, using Windows +Installer's upgrade functionality to avoid conflicts with earlier +installed versions. + +When installed, file associations are created for .py, .pyc and .pyo +files to launch with py.exe and .pyw files to launch with pyw.exe. This +makes Python files respect shebang lines by default and also avoids +conflicts between multiple Python installations. + + +Repair, Modify and Uninstall +============================ + +After installation, Python may be modified, repaired or uninstalled by +running the original EXE again or via the Programs and Features applet +(formerly known as Add or Remove Programs). + +Modifications allow features to be added or removed. The install +directory and kind (all users/single user) cannot be modified. Because +Windows Installer caches installation packages, removing features will +not require internet access unless the package cache has been corrupted +or deleted. Adding features that were not previously installed and are +not embedded or otherwise available will require internet access. + +Repairing will rerun the installation for all currently installed +features, restoring files and registry keys that have been modified or +removed. This operation generally will not redownload any files unless +the cached packages have been corrupted or deleted. + +Removing Python will clean up all the files and registry keys that were +created by the installer, as well as __pycache__ folders that are +explicitly handled by the installer. Python packages installed later +using a tool like pip will not be removed. Some components may be +installed by other installers (such as the MSVCRT) and these will not be +removed if another product has a dependency on them. + diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat new file mode 100644 --- /dev/null +++ b/Tools/msi/build.bat @@ -0,0 +1,46 @@ + at echo off +setlocal +set D=%~dp0 +set PCBUILD=%D%..\..\PCBuild\ + +set BUILDX86= +set BUILDX64= +set BUILDDOC= + +:CheckOpts +if '%1'=='-x86' (set BUILDX86=1) && shift && goto CheckOpts +if '%1'=='-x64' (set BUILDX64=1) && shift && goto CheckOpts +if '%1'=='--doc' (set BUILDDOC=1) && shift && goto CheckOpts + +if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) + +call "%PCBUILD%env.bat" x86 + +if defined BUILDX86 ( + call "%PCBUILD%build.bat" -d + if errorlevel 1 goto :eof + call "%PCBUILD%build.bat" + if errorlevel 1 goto :eof +) +if defined BUILDX64 ( + call "%PCBUILD%build.bat" -p x64 -d + if errorlevel 1 goto :eof + call "%PCBUILD%build.bat" -p x64 + if errorlevel 1 goto :eof +) + +if defined BUILDDOC ( + call "%PCBUILD%..\Doc\make.bat" htmlhelp + if errorlevel 1 goto :eof +) + +if defined BUILDX86 ( + "%PCBUILD%win32\python.exe" "%D%get_wix.py" + msbuild "%D%bundle\snapshot.wixproj" + if errorlevel 1 goto :eof +) +if defined BUILDX64 ( + "%PCBUILD%amd64\python.exe" "%D%get_wix.py" + msbuild "%D%bundle\snapshot.wixproj" /p:Platform=x64 + if errorlevel 1 goto :eof +) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat new file mode 100644 --- /dev/null +++ b/Tools/msi/buildrelease.bat @@ -0,0 +1,131 @@ + at setlocal + at echo off + +rem This script is intended for building official releases of Python. +rem To use it to build alternative releases, you should clone this file +rem and modify the following three URIs. +rem +rem The first two will ensure that your release can be installed +rem alongside an official Python release, while the second specifies +rem the URL that will be used to download installation files. The +rem files available from this URL *will* conflict with your installer. +rem Trust me, you don't want them, even if it seems like a good idea. + +set RELEASE_URI_X86=http://www.python.org/win32 +set RELEASE_URI_X64=http://www.python.org/amd64 +set DOWNLOAD_URL_BASE=https://www.python.org/ftp/python +set DOWNLOAD_URL= + +set D=%~dp0 +set PCBUILD=%D%..\..\PCBuild\ + +set BUILDX86= +set BUILDX64= +set TARGET=Rebuild + + +:CheckOpts +if "%1" EQU "-c" (set CERTNAME=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "-o" (set OUTDIR=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "-D" (set SKIPDOC=1) && shift && goto CheckOpts +if "%1" EQU "-B" (set SKIPBUILD=1) && shift && goto CheckOpts +if "%1" EQU "--download" (set DOWNLOAD_URL=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "-b" (set TARGET=Build) && shift && goto CheckOpts +if '%1' EQU '-x86' (set BUILDX86=1) && shift && goto CheckOpts +if '%1' EQU '-x64' (set BUILDX64=1) && shift && goto CheckOpts + +if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) + +:builddoc +if "%SKIPBUILD%" EQU "1" goto skipdoc +if "%SKIPDOC%" EQU "1" goto skipdoc + +call "%D%..\..\doc\make.bat" htmlhelp +if errorlevel 1 goto :eof +:skipdoc + +where dlltool 2>nul >"%TEMP%\dlltool.loc" +if errorlevel 1 dir "%D%..\..\externals\dlltool.exe" /s/b > "%TEMP%\dlltool.loc" +if errorlevel 1 echo Cannot find binutils on PATH or in externals & exit /B 1 +set /P DLLTOOL= < "%TEMP%\dlltool.loc" +set PATH=%PATH%;%DLLTOOL:~,-12% +set DLLTOOL= +del "%TEMP%\dlltool.loc" + + +if defined BUILDX86 ( + call :build x86 + if errorlevel 1 exit /B +) + +if defined BUILDX64 ( + call :build x64 + if errorlevel 1 exit /B +) + +exit /B 0 + +:build + at setlocal + at echo off + +if "%1" EQU "x86" ( + call "%PCBUILD%env.bat" x86 + set BUILD=%PCBUILD%win32\ + set BUILD_PLAT=Win32 + set OUTDIR_PLAT=win32 + set OBJDIR_PLAT=x86 + set RELEASE_URI=%RELEASE_URI_X86% +) ELSE ( + call "%PCBUILD%env.bat" x86_amd64 + set BUILD=%PCBUILD%amd64\ + set BUILD_PLAT=x64 + set OUTDIR_PLAT=amd64 + set OBJDIR_PLAT=x64 + set RELEASE_URI=%RELEASE_URI_X64% +) + +echo on +if exist "%BUILD%en-us" ( + echo Deleting %BUILD%en-us + rmdir /q/s "%BUILD%en-us" + if errorlevel 1 exit /B +) + +echo on +if exist "%D%obj\Release_%OBJDIR_PLAT%" ( + echo Deleting "%D%obj\Release_%OBJDIR_PLAT%" + rmdir /q/s "%D%obj\Release_%OBJDIR_PLAT%" + if errorlevel 1 exit /B +) + +if not "%CERTNAME%" EQU "" ( + set CERTOPTS="/p:SigningCertificate=%CERTNAME%" +) else ( + set CERTOPTS= +) + +if not "%SKIPBUILD%" EQU "1" ( + call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -d -t %TARGET% %CERTOPTS% + if errorlevel 1 exit /B + call "%PCBUILD%build.bat" -p %BUILD_PLAT% -t %TARGET% %CERTOPTS% + if errorlevel 1 exit /B + @rem build.bat turns echo back on, so we disable it again + @echo off +) + +"%BUILD%python.exe" "%D%get_wix.py" + +set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI% +msbuild "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true +if errorlevel 1 exit /B +msbuild "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false +if errorlevel 1 exit /B + +if not "%OUTDIR%" EQU "" ( + mkdir "%OUTDIR%\%OUTDIR_PLAT%" + copy /Y "%BUILD%en-us\*.cab" "%OUTDIR%\%OUTDIR_PLAT%" + copy /Y "%BUILD%en-us\*.exe" "%OUTDIR%\%OUTDIR_PLAT%" + copy /Y "%BUILD%en-us\*.msi" "%OUTDIR%\%OUTDIR_PLAT%" +) + diff --git a/Tools/msi/bundle/Default.thm b/Tools/msi/bundle/Default.thm new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/Default.thm @@ -0,0 +1,123 @@ + + + #(loc.Caption) + Segoe UI + Segoe UI + Segoe UI + Segoe UI + Segoe UI + Segoe UI + + + #(loc.HelpHeader) + + + #(loc.HelpText) + + + + #(loc.InstallHeader) + + + #(loc.InstallMessage) + + + + + + #(loc.ShortPrependPathLabel) + + + + + #(loc.InstallHeader) + + + + + + + + #(loc.Custom1Header) + + + #(loc.Include_docLabel) + #(loc.Include_docHelpLabel) + + #(loc.Include_pipLabel) + #(loc.Include_pipHelpLabel) + + #(loc.Include_tcltkLabel) + #(loc.Include_tcltkHelpLabel) + + #(loc.Include_testLabel) + #(loc.Include_testHelpLabel) + + #(loc.Include_launcherLabel) + #(loc.Include_launcherHelpLabel) + + + + + + + #(loc.Custom2Header) + + + #(loc.AssociateFilesLabel) + #(loc.PrependPathLabel) + #(loc.InstallAllUsersLabel) + #(loc.PrecompileLabel) + #(loc.Include_symbolsLabel) + #(loc.Include_debugLabel) + + #(loc.CustomLocationLabel) + + + #(loc.CustomLocationHelpLabel) + + + + + + + #(loc.ProgressHeader) + + + #(loc.ProgressLabel) + #(loc.OverallProgressPackageText) + + + + + #(loc.ModifyHeader) + + + + + + + + + + #(loc.SuccessHeader) + + + + + #(loc.SuccessRestartText) + + + + + + #(loc.FailureHeader) + + + #(loc.FailureHyperlinkLogText) + Failure Message + #(loc.FailureRestartText) + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/Default.wxl b/Tools/msi/bundle/Default.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/Default.wxl @@ -0,0 +1,103 @@ +? + + [WixBundleName] Setup + [WixBundleName] + Installing + Setup + Updating + Modify + Repairing + Repair + Removing + Uninstall + + &Cancel + &Close + Install [WixBundleName] + Select to location to install Python, or choose Customize to enable or disable features. + Version [WixBundleVersion] + Are you sure you want to cancel? + Previous version + Setup Help + /uninstall + Uninstalls Python without prompting for confirmation. + +/layout [\[]directory[\]] + Downloads all components for offline installation. + +/passive + Displays progress without requiring user interaction. + +/quiet + Performs the requested action without displaying any UI. + +/log [\[]filename[\]] + Logs to a specific file. By default, log files are created in %TEMP%. + [WixBundleName] <a href="#">license terms</a>. + I &agree to the license terms and conditions + Install for &All Users + [DefaultAllUsersTargetDir] + Install &Just for Me + [DefaultJustForMeTargetDir] + C&ustomize installation + Choose location and features + &Install + Uses setting preselected by your administrator + Optional Features + Advanced Options + Customize install location + If not installing as administrator, you will require write permissions for this location. + &Install + &Next + &Back + B&rowse + &Documentation + Installs the Python documentation file. + &pip + Installs pip, which can download and install other Python packages. + tcl/tk and &IDLE + Installs tkinter and the IDLE development environment. + Python &test suite + Installs the standard library test suite. + py &launcher + Installs the global 'py' launcher to make it easier to start Python. + + Associate &files with Python (requires the py launcher) + Add Python to &environment variables + Add &Python [ShortVersion] to PATH + Install as &Administrator + &Precompile standard library + Install debugging &symbols + Install debu&g binaries + + [ActionLikeInstallation] Progress + [ActionLikeInstalling]: + Initializing... + Modify Setup + &Modify + Add or remove individual features. + &Repair + Ensure all current features are correctly installed. + &Uninstall + Remove the entire [WixBundleName] installation. + [ActionLikeInstallation] was successful + &Launch + You may need to restart your computer to finish updating files. + &Restart + Special thanks to Mark Hammond, without whose years of freely shared Windows expertise, Python for Windows would still be Python for DOS. + +New to Python? Start with the <a href="https://docs.python.org/[ShortVersion]/tutorial/index.html">online tutorial</a> and <a href="https://docs.python.org/[ShortVersion]/index.html">documentation</a>. + +See <a href="https://docs.python.org/[ShortVersion]/whatsnew/[ShortVersion].html">what's new</a> in this release. + Thank you for using [WixBundleName]. + Thank you for using [WixBundleName]. + +Feel free to email <a href="mailto:python-list at python.org">python-list at python.org</a> if you continue to encounter issues. + Thank you for using [WixBundleName]. + +Feel free to email <a href="mailto:python-list at python.org">python-list at python.org</a> if you encountered problems. + Setup failed + One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>. + You must restart your computer to complete the rollback of the software. + &Restart + diff --git a/Tools/msi/bundle/SideBar.png b/Tools/msi/bundle/SideBar.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9c18fff33a6ea50e3514ea938c5e5bfe4c5fe4c6 GIT binary patch [stripped] diff --git a/Tools/msi/bundle/bootstrap/LICENSE.txt b/Tools/msi/bundle/bootstrap/LICENSE.txt new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/LICENSE.txt @@ -0,0 +1,25 @@ +This license applies to the bootstrapper application that is embedded within the installer. It has no impact on the licensing for the rest of the installer or Python itself, as no code covered by this license exists in any other part of the product. + +--- + +Microsoft Reciprocal License (MS-RL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + A "contribution" is the original software, or any additions or changes to the software. + A "contributor" is any person that distributes its contribution under this license. + "Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + (A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose. + (B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + (C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + (D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -0,0 +1,2645 @@ +//------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2004, Outercurve Foundation. +// This software is released under Microsoft Reciprocal License (MS-RL). +// The license and further copyright text can be found in the file +// LICENSE.TXT at the root directory of the distribution. +// +//------------------------------------------------------------------------------------------------- + + +#include "pch.h" + +static const LPCWSTR WIXBUNDLE_VARIABLE_ELEVATED = L"WixBundleElevated"; + +static const LPCWSTR PYBA_WINDOW_CLASS = L"PythonBA"; +static const LPCWSTR PYBA_VARIABLE_LAUNCH_TARGET_PATH = L"LaunchTarget"; +static const LPCWSTR PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID = L"LaunchTargetElevatedId"; +static const LPCWSTR PYBA_VARIABLE_LAUNCH_ARGUMENTS = L"LaunchArguments"; +static const LPCWSTR PYBA_VARIABLE_LAUNCH_HIDDEN = L"LaunchHidden"; +static const DWORD PYBA_ACQUIRE_PERCENTAGE = 30; +static const LPCWSTR PYBA_VARIABLE_BUNDLE_FILE_VERSION = L"WixBundleFileVersion"; + +enum PYBA_STATE { + PYBA_STATE_INITIALIZING, + PYBA_STATE_INITIALIZED, + PYBA_STATE_HELP, + PYBA_STATE_DETECTING, + PYBA_STATE_DETECTED, + PYBA_STATE_PLANNING, + PYBA_STATE_PLANNED, + PYBA_STATE_APPLYING, + PYBA_STATE_CACHING, + PYBA_STATE_CACHED, + PYBA_STATE_EXECUTING, + PYBA_STATE_EXECUTED, + PYBA_STATE_APPLIED, + PYBA_STATE_FAILED, +}; + +static const int WM_PYBA_SHOW_HELP = WM_APP + 100; +static const int WM_PYBA_DETECT_PACKAGES = WM_APP + 101; +static const int WM_PYBA_PLAN_PACKAGES = WM_APP + 102; +static const int WM_PYBA_APPLY_PACKAGES = WM_APP + 103; +static const int WM_PYBA_CHANGE_STATE = WM_APP + 104; +static const int WM_PYBA_SHOW_FAILURE = WM_APP + 105; + +// This enum must be kept in the same order as the PAGE_NAMES array. +enum PAGE { + PAGE_LOADING, + PAGE_HELP, + PAGE_INSTALL, + PAGE_SIMPLE_INSTALL, + PAGE_CUSTOM1, + PAGE_CUSTOM2, + PAGE_MODIFY, + PAGE_PROGRESS, + PAGE_PROGRESS_PASSIVE, + PAGE_SUCCESS, + PAGE_FAILURE, + COUNT_PAGE, +}; + +// This array must be kept in the same order as the PAGE enum. +static LPCWSTR PAGE_NAMES[] = { + L"Loading", + L"Help", + L"Install", + L"SimpleInstall", + L"Custom1", + L"Custom2", + L"Modify", + L"Progress", + L"ProgressPassive", + L"Success", + L"Failure", +}; + +enum CONTROL_ID { + // Non-paged controls + ID_CLOSE_BUTTON = THEME_FIRST_ASSIGN_CONTROL_ID, + ID_MINIMIZE_BUTTON, + + // Welcome page + ID_INSTALL_ALL_USERS_BUTTON, + ID_INSTALL_JUST_FOR_ME_BUTTON, + ID_INSTALL_CUSTOM_BUTTON, + ID_INSTALL_SIMPLE_BUTTON, + ID_INSTALL_CANCEL_BUTTON, + + // Customize Page + ID_TARGETDIR_EDITBOX, + ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, + ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX, + ID_CUSTOM_BROWSE_BUTTON, + ID_CUSTOM_INSTALL_BUTTON, + ID_CUSTOM_NEXT_BUTTON, + ID_CUSTOM1_BACK_BUTTON, + ID_CUSTOM2_BACK_BUTTON, + ID_CUSTOM1_CANCEL_BUTTON, + ID_CUSTOM2_CANCEL_BUTTON, + + // Modify page + ID_MODIFY_BUTTON, + ID_REPAIR_BUTTON, + ID_UNINSTALL_BUTTON, + ID_MODIFY_CANCEL_BUTTON, + + // Progress page + ID_CACHE_PROGRESS_PACKAGE_TEXT, + ID_CACHE_PROGRESS_BAR, + ID_CACHE_PROGRESS_TEXT, + + ID_EXECUTE_PROGRESS_PACKAGE_TEXT, + ID_EXECUTE_PROGRESS_BAR, + ID_EXECUTE_PROGRESS_TEXT, + ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, + + ID_OVERALL_PROGRESS_PACKAGE_TEXT, + ID_OVERALL_PROGRESS_BAR, + ID_OVERALL_CALCULATED_PROGRESS_BAR, + ID_OVERALL_PROGRESS_TEXT, + + ID_PROGRESS_CANCEL_BUTTON, + + // Success page + ID_LAUNCH_BUTTON, + ID_SUCCESS_TEXT, + ID_SUCCESS_RESTART_TEXT, + ID_SUCCESS_RESTART_BUTTON, + ID_SUCCESS_CANCEL_BUTTON, + + // Failure page + ID_FAILURE_LOGFILE_LINK, + ID_FAILURE_MESSAGE_TEXT, + ID_FAILURE_RESTART_TEXT, + ID_FAILURE_RESTART_BUTTON, + ID_FAILURE_CANCEL_BUTTON +}; + +static THEME_ASSIGN_CONTROL_ID CONTROL_ID_NAMES[] = { + { ID_CLOSE_BUTTON, L"CloseButton" }, + { ID_MINIMIZE_BUTTON, L"MinimizeButton" }, + + { ID_INSTALL_ALL_USERS_BUTTON, L"InstallAllUsersButton" }, + { ID_INSTALL_JUST_FOR_ME_BUTTON, L"InstallJustForMeButton" }, + { ID_INSTALL_CUSTOM_BUTTON, L"InstallCustomButton" }, + { ID_INSTALL_SIMPLE_BUTTON, L"InstallSimpleButton" }, + { ID_INSTALL_CANCEL_BUTTON, L"InstallCancelButton" }, + + { ID_TARGETDIR_EDITBOX, L"TargetDir" }, + { ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, L"AssociateFiles" }, + { ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX, L"InstallAllUsers" }, + { ID_CUSTOM_BROWSE_BUTTON, L"CustomBrowseButton" }, + { ID_CUSTOM_INSTALL_BUTTON, L"CustomInstallButton" }, + { ID_CUSTOM_NEXT_BUTTON, L"CustomNextButton" }, + { ID_CUSTOM1_BACK_BUTTON, L"Custom1BackButton" }, + { ID_CUSTOM2_BACK_BUTTON, L"Custom2BackButton" }, + { ID_CUSTOM1_CANCEL_BUTTON, L"Custom1CancelButton" }, + { ID_CUSTOM2_CANCEL_BUTTON, L"Custom2CancelButton" }, + + { ID_MODIFY_BUTTON, L"ModifyButton" }, + { ID_REPAIR_BUTTON, L"RepairButton" }, + { ID_UNINSTALL_BUTTON, L"UninstallButton" }, + { ID_MODIFY_CANCEL_BUTTON, L"ModifyCancelButton" }, + + { ID_CACHE_PROGRESS_PACKAGE_TEXT, L"CacheProgressPackageText" }, + { ID_CACHE_PROGRESS_BAR, L"CacheProgressbar" }, + { ID_CACHE_PROGRESS_TEXT, L"CacheProgressText" }, + { ID_EXECUTE_PROGRESS_PACKAGE_TEXT, L"ExecuteProgressPackageText" }, + { ID_EXECUTE_PROGRESS_BAR, L"ExecuteProgressbar" }, + { ID_EXECUTE_PROGRESS_TEXT, L"ExecuteProgressText" }, + { ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L"ExecuteProgressActionDataText" }, + { ID_OVERALL_PROGRESS_PACKAGE_TEXT, L"OverallProgressPackageText" }, + { ID_OVERALL_PROGRESS_BAR, L"OverallProgressbar" }, + { ID_OVERALL_CALCULATED_PROGRESS_BAR, L"OverallCalculatedProgressbar" }, + { ID_OVERALL_PROGRESS_TEXT, L"OverallProgressText" }, + { ID_PROGRESS_CANCEL_BUTTON, L"ProgressCancelButton" }, + + { ID_LAUNCH_BUTTON, L"LaunchButton" }, + { ID_SUCCESS_TEXT, L"SuccessText" }, + { ID_SUCCESS_RESTART_TEXT, L"SuccessRestartText" }, + { ID_SUCCESS_RESTART_BUTTON, L"SuccessRestartButton" }, + { ID_SUCCESS_CANCEL_BUTTON, L"SuccessCancelButton" }, + + { ID_FAILURE_LOGFILE_LINK, L"FailureLogFileLink" }, + { ID_FAILURE_MESSAGE_TEXT, L"FailureMessageText" }, + { ID_FAILURE_RESTART_TEXT, L"FailureRestartText" }, + { ID_FAILURE_RESTART_BUTTON, L"FailureRestartButton" }, + { ID_FAILURE_CANCEL_BUTTON, L"FailureCancelButton" }, +}; + +class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication { + void ShowPage(DWORD newPageId) { + // Process each control for special handling in the new page. + ProcessPageControls(ThemeGetPage(_theme, newPageId)); + + // Enable disable controls per-page. + if (_pageIds[PAGE_INSTALL] == newPageId || _pageIds[PAGE_SIMPLE_INSTALL] == newPageId) { + InstallPage_Show(); + } else if (_pageIds[PAGE_CUSTOM1] == newPageId) { + Custom1Page_Show(); + } else if (_pageIds[PAGE_CUSTOM2] == newPageId) { + Custom2Page_Show(); + } else if (_pageIds[PAGE_MODIFY] == newPageId) { + ModifyPage_Show(); + } else if (_pageIds[PAGE_SUCCESS] == newPageId) { + SuccessPage_Show(); + } else if (_pageIds[PAGE_FAILURE] == newPageId) { + FailurePage_Show(); + } + + // Prevent repainting while switching page to avoid ugly flickering + _suppressPaint = TRUE; + ThemeShowPage(_theme, newPageId, SW_SHOW); + ThemeShowPage(_theme, _visiblePageId, SW_HIDE); + _suppressPaint = FALSE; + InvalidateRect(_theme->hwndParent, nullptr, TRUE); + _visiblePageId = newPageId; + + // On the install page set the focus to the install button or + // the next enabled control if install is disabled + if (_pageIds[PAGE_INSTALL] == newPageId) { + ThemeSetFocus(_theme, ID_INSTALL_ALL_USERS_BUTTON); + } else if (_pageIds[PAGE_SIMPLE_INSTALL] == newPageId) { + ThemeSetFocus(_theme, ID_INSTALL_SIMPLE_BUTTON); + } + } + + // + // Handles control clicks + // + void OnCommand(CONTROL_ID id) { + LPWSTR defaultDir = nullptr; + LPWSTR targetDir = nullptr; + LONGLONG elevated; + BOOL checked; + WCHAR wzPath[MAX_PATH] = { }; + BROWSEINFOW browseInfo = { }; + PIDLIST_ABSOLUTE pidl = nullptr; + HRESULT hr = S_OK; + + switch(id) { + case ID_CLOSE_BUTTON: + OnClickCloseButton(); + break; + + // Install commands + case ID_INSTALL_SIMPLE_BUTTON: + hr = BalGetStringVariable(L"TargetDir", &targetDir); + if (FAILED(hr) || !targetDir || !*targetDir) { + LONGLONG installAll; + if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) { + hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir); + BalExitOnFailure(hr, "Failed to get the default all users install directory"); + } else { + hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir); + BalExitOnFailure(hr, "Failed to get the default per-user install directory"); + } + + if (!defaultDir || !*defaultDir) { + BalLogError(E_INVALIDARG, "Default install directory is blank"); + } + + hr = BalFormatString(defaultDir, &targetDir); + BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); + + hr = _engine->SetVariableString(L"TargetDir", targetDir); + ReleaseStr(targetDir); + BalExitOnFailure(hr, "Failed to set install target directory"); + } else { + ReleaseStr(targetDir); + } + + OnPlan(BOOTSTRAPPER_ACTION_INSTALL); + break; + + case ID_INSTALL_ALL_USERS_BUTTON: + SavePageSettings(); + + hr = _engine->SetVariableNumeric(L"InstallAllUsers", 1); + ExitOnFailure(hr, L"Failed to set install scope"); + + hr = _engine->SetVariableNumeric(L"CompileAll", 1); + ExitOnFailure(hr, L"Failed to set compile all setting"); + + hr = BalGetStringVariable(L"DefaultAllUsersTargetDir", &defaultDir); + BalExitOnFailure(hr, "Failed to get the default all users install directory"); + + if (!defaultDir || !*defaultDir) { + BalLogError(E_INVALIDARG, "Default install directory is blank"); + } + + hr = BalFormatString(defaultDir, &targetDir); + BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); + + hr = _engine->SetVariableString(L"TargetDir", targetDir); + ReleaseStr(targetDir); + BalExitOnFailure(hr, "Failed to set install target directory"); + + OnPlan(BOOTSTRAPPER_ACTION_INSTALL); + break; + + case ID_INSTALL_JUST_FOR_ME_BUTTON: + SavePageSettings(); + + hr = _engine->SetVariableNumeric(L"InstallAllUsers", 0); + ExitOnFailure(hr, L"Failed to set install scope"); + + hr = BalGetStringVariable(L"DefaultJustForMeTargetDir", &defaultDir); + BalExitOnFailure(hr, "Failed to get the default per-user install directory"); + + if (!defaultDir || !*defaultDir) { + BalLogError(E_INVALIDARG, "Default install directory is blank"); + } + + hr = BalFormatString(defaultDir, &targetDir); + BalExitOnFailure1(hr, "Failed to format '%ls'", defaultDir); + + hr = _engine->SetVariableString(L"TargetDir", targetDir); + ReleaseStr(targetDir); + BalExitOnFailure(hr, "Failed to set install target directory"); + + OnPlan(BOOTSTRAPPER_ACTION_INSTALL); + break; + + case ID_CUSTOM1_BACK_BUTTON: + SavePageSettings(); + GoToPage(PAGE_INSTALL); + break; + + case ID_INSTALL_CUSTOM_BUTTON: __fallthrough; + case ID_CUSTOM2_BACK_BUTTON: + SavePageSettings(); + GoToPage(PAGE_CUSTOM1); + break; + + case ID_CUSTOM_NEXT_BUTTON: + SavePageSettings(); + GoToPage(PAGE_CUSTOM2); + break; + + case ID_CUSTOM_INSTALL_BUTTON: + SavePageSettings(); + + hr = BalGetStringVariable(L"TargetDir", &targetDir); + if (SUCCEEDED(hr)) { + // TODO: Check whether directory exists and contains another installation + ReleaseStr(targetDir); + } + + OnPlan(_command.action); + break; + + case ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX: + hr = BalGetNumericVariable(L"WixBundleElevated", &elevated); + checked = ThemeIsControlChecked(_theme, ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX); + ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, checked && (FAILED(hr) || !elevated)); + ThemeGetTextControl(_theme, ID_TARGETDIR_EDITBOX, &targetDir); + if (targetDir) { + // Check the current value against the default to see + // if we should switch it automatically. + hr = BalGetStringVariable( + checked ? L"DefaultJustForMeTargetDir" : L"DefaultAllUsersTargetDir", + &defaultDir + ); + + if (SUCCEEDED(hr) && defaultDir) { + LPWSTR formatted = nullptr; + if (defaultDir[0] && SUCCEEDED(BalFormatString(defaultDir, &formatted))) { + if (wcscmp(formatted, targetDir) == 0) { + ReleaseStr(defaultDir); + defaultDir = nullptr; + ReleaseStr(formatted); + formatted = nullptr; + + hr = BalGetStringVariable( + checked ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir", + &defaultDir + ); + if (SUCCEEDED(hr) && defaultDir && defaultDir[0] && SUCCEEDED(BalFormatString(defaultDir, &formatted))) { + ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, formatted); + ReleaseStr(formatted); + } + } else { + ReleaseStr(formatted); + } + } + + ReleaseStr(defaultDir); + } + } + break; + + case ID_CUSTOM_BROWSE_BUTTON: + browseInfo.hwndOwner = _hWnd; + browseInfo.pszDisplayName = wzPath; + browseInfo.lpszTitle = _theme->sczCaption; + browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI; + pidl = ::SHBrowseForFolderW(&browseInfo); + if (pidl && ::SHGetPathFromIDListW(pidl, wzPath)) { + ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, wzPath); + } + + if (pidl) { + ::CoTaskMemFree(pidl); + } + break; + + // Modify commands + case ID_MODIFY_BUTTON: + // Some variables cannot be modified + _engine->SetVariableString(L"InstallAllUsersState", L"disable"); + _engine->SetVariableString(L"TargetDirState", L"disable"); + _engine->SetVariableString(L"CustomBrowseButtonState", L"disable"); + GoToPage(PAGE_CUSTOM1); + break; + + case ID_REPAIR_BUTTON: + OnPlan(BOOTSTRAPPER_ACTION_REPAIR); + break; + + case ID_UNINSTALL_BUTTON: + OnPlan(BOOTSTRAPPER_ACTION_UNINSTALL); + break; + } + + LExit: + return; + } + + void InstallPage_Show() { + // Ensure the All Users install button has a UAC shield + LONGLONG elevated, installAll; + + if (FAILED(BalGetNumericVariable(L"WixBundleElevated", &elevated))) { + elevated = 0; + } + + ThemeControlElevates(_theme, ID_INSTALL_ALL_USERS_BUTTON, !elevated); + + if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll)) && installAll) { + ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, !elevated); + } + } + + void Custom1Page_Show() { + } + + void Custom2Page_Show() { + HRESULT hr; + LONGLONG installAll, elevated, includeLauncher; + + if (FAILED(BalGetNumericVariable(L"WixBundleElevated", &elevated))) { + elevated = 0; + } + if (SUCCEEDED(BalGetNumericVariable(L"InstallAllUsers", &installAll))) { + ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, installAll && !elevated); + } else { + installAll = 0; + } + + if (SUCCEEDED(BalGetNumericVariable(L"Include_launcher", &includeLauncher)) && includeLauncher) { + ThemeControlEnable(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, TRUE); + } else { + ThemeSendControlMessage(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, BM_SETCHECK, BST_UNCHECKED, 0); + ThemeControlEnable(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, FALSE); + } + + LPWSTR targetDir = nullptr; + hr = BalGetStringVariable(L"TargetDir", &targetDir); + if (SUCCEEDED(hr) && targetDir && targetDir[0]) { + ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, targetDir); + StrFree(targetDir); + } else if (SUCCEEDED(hr)) { + StrFree(targetDir); + targetDir = nullptr; + + LPWSTR defaultTargetDir = nullptr; + hr = BalGetStringVariable(L"DefaultCustomTargetDir", &defaultTargetDir); + if (SUCCEEDED(hr) && defaultTargetDir && !defaultTargetDir[0]) { + StrFree(defaultTargetDir); + defaultTargetDir = nullptr; + + hr = BalGetStringVariable( + installAll ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir", + &defaultTargetDir + ); + } + if (SUCCEEDED(hr) && defaultTargetDir) { + if (defaultTargetDir[0] && SUCCEEDED(BalFormatString(defaultTargetDir, &targetDir))) { + ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, targetDir); + StrFree(targetDir); + } + StrFree(defaultTargetDir); + } + } + } + + void ModifyPage_Show() { + ThemeControlEnable(_theme, ID_REPAIR_BUTTON, !_suppressRepair); + } + + void SuccessPage_Show() { + // on the "Success" page, check if the restart or launch button should be enabled. + BOOL showRestartButton = FALSE; + BOOL launchTargetExists = FALSE; + LOC_STRING *successText = nullptr; + HRESULT hr = S_OK; + + if (_restartRequired) { + if (BOOTSTRAPPER_RESTART_PROMPT == _command.restart) { + showRestartButton = TRUE; + } + } else if (ThemeControlExists(_theme, ID_LAUNCH_BUTTON)) { + launchTargetExists = BalStringVariableExists(PYBA_VARIABLE_LAUNCH_TARGET_PATH); + } + + switch (_plannedAction) { + case BOOTSTRAPPER_ACTION_INSTALL: + hr = LocGetString(_wixLoc, L"#(loc.SuccessInstallMessage)", &successText); + break; + case BOOTSTRAPPER_ACTION_MODIFY: + hr = LocGetString(_wixLoc, L"#(loc.SuccessModifyMessage)", &successText); + break; + case BOOTSTRAPPER_ACTION_REPAIR: + hr = LocGetString(_wixLoc, L"#(loc.SuccessRepairMessage)", &successText); + break; + case BOOTSTRAPPER_ACTION_UNINSTALL: + hr = LocGetString(_wixLoc, L"#(loc.SuccessRemoveMessage)", &successText); + break; + } + + if (successText) { + LPWSTR formattedString = nullptr; + BalFormatString(successText->wzText, &formattedString); + if (formattedString) { + ThemeSetTextControl(_theme, ID_SUCCESS_TEXT, formattedString); + StrFree(formattedString); + } + } + + ThemeControlEnable(_theme, ID_LAUNCH_BUTTON, launchTargetExists && BOOTSTRAPPER_ACTION_UNINSTALL < _plannedAction); + ThemeControlEnable(_theme, ID_SUCCESS_RESTART_TEXT, showRestartButton); + ThemeControlEnable(_theme, ID_SUCCESS_RESTART_BUTTON, showRestartButton); + } + + void FailurePage_Show() { + // on the "Failure" page, show error message and check if the restart button should be enabled. + + // if there is a log file variable then we'll assume the log file exists. + BOOL showLogLink = (_bundle.sczLogVariable && *_bundle.sczLogVariable); + BOOL showErrorMessage = FALSE; + BOOL showRestartButton = FALSE; + + if (FAILED(_hrFinal)) { + LPWSTR unformattedText = nullptr; + LPWSTR text = nullptr; + + // If we know the failure message, use that. + if (_failedMessage && *_failedMessage) { + StrAllocString(&unformattedText, _failedMessage, 0); + } else { + // try to get the error message from the error code. + StrAllocFromError(&unformattedText, _hrFinal, nullptr); + if (!unformattedText || !*unformattedText) { + StrAllocFromError(&unformattedText, E_FAIL, nullptr); + } + } + + if (E_WIXSTDBA_CONDITION_FAILED == _hrFinal) { + if (unformattedText) { + StrAllocString(&text, unformattedText, 0); + } + } else { + StrAllocFormatted(&text, L"0x%08x - %ls", _hrFinal, unformattedText); + } + + if (text) { + ThemeSetTextControl(_theme, ID_FAILURE_MESSAGE_TEXT, text); + showErrorMessage = TRUE; + } + + ReleaseStr(text); + ReleaseStr(unformattedText); + } + + if (_restartRequired && BOOTSTRAPPER_RESTART_PROMPT == _command.restart) { + showRestartButton = TRUE; + } + + ThemeControlEnable(_theme, ID_FAILURE_LOGFILE_LINK, showLogLink); + ThemeControlEnable(_theme, ID_FAILURE_MESSAGE_TEXT, showErrorMessage); + ThemeControlEnable(_theme, ID_FAILURE_RESTART_TEXT, showRestartButton); + ThemeControlEnable(_theme, ID_FAILURE_RESTART_BUTTON, showRestartButton); + } + + +public: // IBootstrapperApplication + virtual STDMETHODIMP OnStartup() { + HRESULT hr = S_OK; + DWORD dwUIThreadId = 0; + + // create UI thread + _hUiThread = ::CreateThread(nullptr, 0, UiThreadProc, this, 0, &dwUIThreadId); + if (!_hUiThread) { + ExitWithLastError(hr, "Failed to create UI thread."); + } + + LExit: + return hr; + } + + + virtual STDMETHODIMP_(int) OnShutdown() { + int nResult = IDNOACTION; + + // wait for UI thread to terminate + if (_hUiThread) { + ::WaitForSingleObject(_hUiThread, INFINITE); + ReleaseHandle(_hUiThread); + } + + // If a restart was required. + if (_restartRequired && _allowRestart) { + nResult = IDRESTART; + } + + return nResult; + } + + + virtual STDMETHODIMP_(int) OnDetectRelatedBundle( + __in LPCWSTR wzBundleId, + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in LPCWSTR /*wzBundleTag*/, + __in BOOL fPerMachine, + __in DWORD64 /*dw64Version*/, + __in BOOTSTRAPPER_RELATED_OPERATION operation + ) { + BalInfoAddRelatedBundleAsPackage(&_bundle.packages, wzBundleId, relationType, fPerMachine); + + // Remember when our bundle would cause a downgrade. + if (BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation) { + _downgrading = TRUE; + } + + return CheckCanceled() ? IDCANCEL : IDOK; + } + + + virtual STDMETHODIMP_(void) OnDetectPackageComplete( + __in LPCWSTR wzPackageId, + __in HRESULT /*hrStatus*/, + __in BOOTSTRAPPER_PACKAGE_STATE state + ) { } + + + virtual STDMETHODIMP_(void) OnDetectComplete(__in HRESULT hrStatus) { + if (SUCCEEDED(hrStatus) && _baFunction) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running detect complete BA function"); + _baFunction->OnDetectComplete(); + } + + if (SUCCEEDED(hrStatus)) { + hrStatus = EvaluateConditions(); + } + + SetState(PYBA_STATE_DETECTED, hrStatus); + + // If we're not interacting with the user or we're doing a layout or we're just after a force restart + // then automatically start planning. + if (BOOTSTRAPPER_DISPLAY_FULL > _command.display || + BOOTSTRAPPER_ACTION_LAYOUT == _command.action || + BOOTSTRAPPER_ACTION_UNINSTALL == _command.action || + BOOTSTRAPPER_RESUME_TYPE_REBOOT == _command.resumeType) { + if (SUCCEEDED(hrStatus)) { + ::PostMessageW(_hWnd, WM_PYBA_PLAN_PACKAGES, 0, _command.action); + } + } + } + + + virtual STDMETHODIMP_(int) OnPlanRelatedBundle( + __in_z LPCWSTR /*wzBundleId*/, + __inout_z BOOTSTRAPPER_REQUEST_STATE* pRequestedState + ) { + return CheckCanceled() ? IDCANCEL : IDOK; + } + + + virtual STDMETHODIMP_(int) OnPlanPackageBegin( + __in_z LPCWSTR wzPackageId, + __inout BOOTSTRAPPER_REQUEST_STATE *pRequestState + ) { + HRESULT hr = S_OK; + BAL_INFO_PACKAGE* pPackage = nullptr; + + if (_nextPackageAfterRestart) // after force restart, skip packages until after the package that caused the restart. + { + // After restart we need to finish the dependency registration for our package so allow the package + // to go present. + if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, _nextPackageAfterRestart, -1)) { + // Do not allow a repair because that could put us in a perpetual restart loop. + if (BOOTSTRAPPER_REQUEST_STATE_REPAIR == *pRequestState) { + *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT; + } + + ReleaseNullStr(_nextPackageAfterRestart); // no more skipping now. + } else { + // not the matching package, so skip it. + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Skipping package: %ls, after restart because it was applied before the restart.", wzPackageId); + + *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; + } + } + + return CheckCanceled() ? IDCANCEL : IDOK; + } + + virtual STDMETHODIMP_(int) OnPlanMsiFeature( + __in_z LPCWSTR wzPackageId, + __in_z LPCWSTR wzFeatureId, + __inout BOOTSTRAPPER_FEATURE_STATE* pRequestedState + ) { + LONGLONG install; + + if (wcscmp(wzFeatureId, L"AssociateFiles") == 0) { + if (SUCCEEDED(_engine->GetVariableNumeric(L"AssociateFiles", &install)) && install) { + *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_LOCAL; + } else { + *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_ABSENT; + } + } + return CheckCanceled() ? IDCANCEL : IDNOACTION; + } + + virtual STDMETHODIMP_(void) OnPlanComplete(__in HRESULT hrStatus) { + if (SUCCEEDED(hrStatus) && _baFunction) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running plan complete BA function"); + _baFunction->OnPlanComplete(); + } + + SetState(PYBA_STATE_PLANNED, hrStatus); + + if (SUCCEEDED(hrStatus)) { + ::PostMessageW(_hWnd, WM_PYBA_APPLY_PACKAGES, 0, 0); + } + + _startedExecution = FALSE; + _calculatedCacheProgress = 0; + _calculatedExecuteProgress = 0; + } + + + virtual STDMETHODIMP_(int) OnCachePackageBegin( + __in_z LPCWSTR wzPackageId, + __in DWORD cCachePayloads, + __in DWORD64 dw64PackageCacheSize + ) { + if (wzPackageId && *wzPackageId) { + BAL_INFO_PACKAGE* pPackage = nullptr; + HRESULT hr = BalInfoFindPackageById(&_bundle.packages, wzPackageId, &pPackage); + LPCWSTR wz = (SUCCEEDED(hr) && pPackage->sczDisplayName) ? pPackage->sczDisplayName : wzPackageId; + + ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_PACKAGE_TEXT, wz); + + // If something started executing, leave it in the overall progress text. + if (!_startedExecution) { + ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_PACKAGE_TEXT, wz); + } + } + + return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, dw64PackageCacheSize); + } + + + virtual STDMETHODIMP_(int) OnCacheAcquireProgress( + __in_z LPCWSTR wzPackageOrContainerId, + __in_z_opt LPCWSTR wzPayloadId, + __in DWORD64 dw64Progress, + __in DWORD64 dw64Total, + __in DWORD dwOverallPercentage + ) { + WCHAR wzProgress[5] = { }; + +#ifdef DEBUG + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnCacheAcquireProgress() - container/package: %ls, payload: %ls, progress: %I64u, total: %I64u, overall progress: %u%%", wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage); +#endif + + ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallPercentage); + ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_TEXT, wzProgress); + + ThemeSetProgressControl(_theme, ID_CACHE_PROGRESS_BAR, dwOverallPercentage); + + _calculatedCacheProgress = dwOverallPercentage * PYBA_ACQUIRE_PERCENTAGE / 100; + ThemeSetProgressControl(_theme, ID_OVERALL_CALCULATED_PROGRESS_BAR, _calculatedCacheProgress + _calculatedExecuteProgress); + + SetTaskbarButtonProgress(_calculatedCacheProgress + _calculatedExecuteProgress); + + return __super::OnCacheAcquireProgress(wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage); + } + + + virtual STDMETHODIMP_(int) OnCacheAcquireComplete( + __in_z LPCWSTR wzPackageOrContainerId, + __in_z_opt LPCWSTR wzPayloadId, + __in HRESULT hrStatus, + __in int nRecommendation + ) { + SetProgressState(hrStatus); + return __super::OnCacheAcquireComplete(wzPackageOrContainerId, wzPayloadId, hrStatus, nRecommendation); + } + + + virtual STDMETHODIMP_(int) OnCacheVerifyComplete( + __in_z LPCWSTR wzPackageId, + __in_z LPCWSTR wzPayloadId, + __in HRESULT hrStatus, + __in int nRecommendation + ) { + SetProgressState(hrStatus); + return __super::OnCacheVerifyComplete(wzPackageId, wzPayloadId, hrStatus, nRecommendation); + } + + + virtual STDMETHODIMP_(void) OnCacheComplete(__in HRESULT /*hrStatus*/) { + ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_PACKAGE_TEXT, L""); + SetState(PYBA_STATE_CACHED, S_OK); // we always return success here and let OnApplyComplete() deal with the error. + } + + + virtual STDMETHODIMP_(int) OnError( + __in BOOTSTRAPPER_ERROR_TYPE errorType, + __in LPCWSTR wzPackageId, + __in DWORD dwCode, + __in_z LPCWSTR wzError, + __in DWORD dwUIHint, + __in DWORD /*cData*/, + __in_ecount_z_opt(cData) LPCWSTR* /*rgwzData*/, + __in int nRecommendation + ) { + int nResult = nRecommendation; + LPWSTR sczError = nullptr; + + if (BOOTSTRAPPER_DISPLAY_EMBEDDED == _command.display) { + HRESULT hr = _engine->SendEmbeddedError(dwCode, wzError, dwUIHint, &nResult); + if (FAILED(hr)) { + nResult = IDERROR; + } + } else if (BOOTSTRAPPER_DISPLAY_FULL == _command.display) { + // If this is an authentication failure, let the engine try to handle it for us. + if (BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_SERVER == errorType || BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_PROXY == errorType) { + nResult = IDTRYAGAIN; + } else // show a generic error message box. + { + BalRetryErrorOccurred(wzPackageId, dwCode); + + if (!_showingInternalUIThisPackage) { + // If no error message was provided, use the error code to try and get an error message. + if (!wzError || !*wzError || BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER != errorType) { + HRESULT hr = StrAllocFromError(&sczError, dwCode, nullptr); + if (FAILED(hr) || !sczError || !*sczError) { + StrAllocFormatted(&sczError, L"0x%x", dwCode); + } + } + + nResult = ::MessageBoxW(_hWnd, sczError ? sczError : wzError, _theme->sczCaption, dwUIHint); + } + } + + SetProgressState(HRESULT_FROM_WIN32(dwCode)); + } else { + // just take note of the error code and let things continue. + BalRetryErrorOccurred(wzPackageId, dwCode); + } + + ReleaseStr(sczError); + return nResult; + } + + + virtual STDMETHODIMP_(int) OnExecuteMsiMessage( + __in_z LPCWSTR wzPackageId, + __in INSTALLMESSAGE mt, + __in UINT uiFlags, + __in_z LPCWSTR wzMessage, + __in DWORD cData, + __in_ecount_z_opt(cData) LPCWSTR* rgwzData, + __in int nRecommendation + ) { +#ifdef DEBUG + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnExecuteMsiMessage() - package: %ls, message: %ls", wzPackageId, wzMessage); +#endif + if (BOOTSTRAPPER_DISPLAY_FULL == _command.display && (INSTALLMESSAGE_WARNING == mt || INSTALLMESSAGE_USER == mt)) { + int nResult = ::MessageBoxW(_hWnd, wzMessage, _theme->sczCaption, uiFlags); + return nResult; + } + + if (INSTALLMESSAGE_ACTIONSTART == mt) { + ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, wzMessage); + } + + return __super::OnExecuteMsiMessage(wzPackageId, mt, uiFlags, wzMessage, cData, rgwzData, nRecommendation); + } + + + virtual STDMETHODIMP_(int) OnProgress(__in DWORD dwProgressPercentage, __in DWORD dwOverallProgressPercentage) { + WCHAR wzProgress[5] = { }; + +#ifdef DEBUG + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnProgress() - progress: %u%%, overall progress: %u%%", dwProgressPercentage, dwOverallProgressPercentage); +#endif + + ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage); + ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_TEXT, wzProgress); + + ThemeSetProgressControl(_theme, ID_OVERALL_PROGRESS_BAR, dwOverallProgressPercentage); + SetTaskbarButtonProgress(dwOverallProgressPercentage); + + return __super::OnProgress(dwProgressPercentage, dwOverallProgressPercentage); + } + + + virtual STDMETHODIMP_(int) OnExecutePackageBegin(__in_z LPCWSTR wzPackageId, __in BOOL fExecute) { + LPWSTR sczFormattedString = nullptr; + + _startedExecution = TRUE; + + if (wzPackageId && *wzPackageId) { + BAL_INFO_PACKAGE* pPackage = nullptr; + BalInfoFindPackageById(&_bundle.packages, wzPackageId, &pPackage); + + LPCWSTR wz = wzPackageId; + if (pPackage) { + LOC_STRING* pLocString = nullptr; + + switch (pPackage->type) { + case BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON: + LocGetString(_wixLoc, L"#(loc.ExecuteAddonRelatedBundleMessage)", &pLocString); + break; + + case BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH: + LocGetString(_wixLoc, L"#(loc.ExecutePatchRelatedBundleMessage)", &pLocString); + break; + + case BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE: + LocGetString(_wixLoc, L"#(loc.ExecuteUpgradeRelatedBundleMessage)", &pLocString); + break; + } + + if (pLocString) { + // If the wix developer is showing a hidden variable in the UI, then obviously they don't care about keeping it safe + // so don't go down the rabbit hole of making sure that this is securely freed. + BalFormatString(pLocString->wzText, &sczFormattedString); + } + + wz = sczFormattedString ? sczFormattedString : pPackage->sczDisplayName ? pPackage->sczDisplayName : wzPackageId; + } + + _showingInternalUIThisPackage = pPackage && pPackage->fDisplayInternalUI; + + ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_PACKAGE_TEXT, wz); + ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_PACKAGE_TEXT, wz); + } else { + _showingInternalUIThisPackage = FALSE; + } + + ReleaseStr(sczFormattedString); + return __super::OnExecutePackageBegin(wzPackageId, fExecute); + } + + + virtual int __stdcall OnExecuteProgress( + __in_z LPCWSTR wzPackageId, + __in DWORD dwProgressPercentage, + __in DWORD dwOverallProgressPercentage + ) { + WCHAR wzProgress[8] = { }; + +#ifdef DEBUG + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnExecuteProgress() - package: %ls, progress: %u%%, overall progress: %u%%", wzPackageId, dwProgressPercentage, dwOverallProgressPercentage); +#endif + + ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage); + ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_TEXT, wzProgress); + + ThemeSetProgressControl(_theme, ID_EXECUTE_PROGRESS_BAR, dwOverallProgressPercentage); + + _calculatedExecuteProgress = dwOverallProgressPercentage * (100 - PYBA_ACQUIRE_PERCENTAGE) / 100; + ThemeSetProgressControl(_theme, ID_OVERALL_CALCULATED_PROGRESS_BAR, _calculatedCacheProgress + _calculatedExecuteProgress); + + SetTaskbarButtonProgress(_calculatedCacheProgress + _calculatedExecuteProgress); + + return __super::OnExecuteProgress(wzPackageId, dwProgressPercentage, dwOverallProgressPercentage); + } + + + virtual STDMETHODIMP_(int) OnExecutePackageComplete( + __in_z LPCWSTR wzPackageId, + __in HRESULT hrExitCode, + __in BOOTSTRAPPER_APPLY_RESTART restart, + __in int nRecommendation + ) { + SetProgressState(hrExitCode); + + if (_wcsnicmp(wzPackageId, L"path_", 5) == 0 && SUCCEEDED(hrExitCode)) { + SendMessageTimeoutW( + HWND_BROADCAST, + WM_SETTINGCHANGE, + 0, + reinterpret_cast(L"Environment"), + SMTO_ABORTIFHUNG, + 1000, + nullptr + ); + } + + int nResult = __super::OnExecutePackageComplete(wzPackageId, hrExitCode, restart, nRecommendation); + + return nResult; + } + + + virtual STDMETHODIMP_(void) OnExecuteComplete(__in HRESULT hrStatus) { + ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_PACKAGE_TEXT, L""); + ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L""); + ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_PACKAGE_TEXT, L""); + ThemeControlEnable(_theme, ID_PROGRESS_CANCEL_BUTTON, FALSE); // no more cancel. + + SetState(PYBA_STATE_EXECUTED, S_OK); // we always return success here and let OnApplyComplete() deal with the error. + SetProgressState(hrStatus); + } + + + virtual STDMETHODIMP_(int) OnResolveSource( + __in_z LPCWSTR wzPackageOrContainerId, + __in_z_opt LPCWSTR wzPayloadId, + __in_z LPCWSTR wzLocalSource, + __in_z_opt LPCWSTR wzDownloadSource + ) { + int nResult = IDERROR; // assume we won't resolve source and that is unexpected. + + if (BOOTSTRAPPER_DISPLAY_FULL == _command.display) { + if (wzDownloadSource) { + nResult = IDDOWNLOAD; + } else { + // prompt to change the source location. + OPENFILENAMEW ofn = { }; + WCHAR wzFile[MAX_PATH] = { }; + + ::StringCchCopyW(wzFile, countof(wzFile), wzLocalSource); + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = _hWnd; + ofn.lpstrFile = wzFile; + ofn.nMaxFile = countof(wzFile); + ofn.lpstrFilter = L"All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.lpstrTitle = _theme->sczCaption; + + if (::GetOpenFileNameW(&ofn)) { + HRESULT hr = _engine->SetLocalSource(wzPackageOrContainerId, wzPayloadId, ofn.lpstrFile); + nResult = SUCCEEDED(hr) ? IDRETRY : IDERROR; + } else { + nResult = IDCANCEL; + } + } + } else if (wzDownloadSource) { + // If doing a non-interactive install and download source is available, let's try downloading the package silently + nResult = IDDOWNLOAD; + } + // else there's nothing more we can do in non-interactive mode + + return CheckCanceled() ? IDCANCEL : nResult; + } + + + virtual STDMETHODIMP_(int) OnApplyComplete(__in HRESULT hrStatus, __in BOOTSTRAPPER_APPLY_RESTART restart) { + _restartResult = restart; // remember the restart result so we return the correct error code no matter what the user chooses to do in the UI. + + // If a restart was encountered and we are not suppressing restarts, then restart is required. + _restartRequired = (BOOTSTRAPPER_APPLY_RESTART_NONE != restart && BOOTSTRAPPER_RESTART_NEVER < _command.restart); + // If a restart is required and we're not displaying a UI or we are not supposed to prompt for restart then allow the restart. + _allowRestart = _restartRequired && (BOOTSTRAPPER_DISPLAY_FULL > _command.display || BOOTSTRAPPER_RESTART_PROMPT < _command.restart); + + // If we are showing UI, wait a beat before moving to the final screen. + if (BOOTSTRAPPER_DISPLAY_NONE < _command.display) { + ::Sleep(250); + } + + SetState(PYBA_STATE_APPLIED, hrStatus); + SetTaskbarButtonProgress(100); // show full progress bar, green, yellow, or red + + return IDNOACTION; + } + + virtual STDMETHODIMP_(void) OnLaunchApprovedExeComplete(__in HRESULT hrStatus, __in DWORD /*processId*/) { + if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hrStatus) { + //try with ShelExec next time + OnClickLaunchButton(); + } else { + ::PostMessageW(_hWnd, WM_CLOSE, 0, 0); + } + } + + +private: + // + // UiThreadProc - entrypoint for UI thread. + // + static DWORD WINAPI UiThreadProc(__in LPVOID pvContext) { + HRESULT hr = S_OK; + PythonBootstrapperApplication* pThis = (PythonBootstrapperApplication*)pvContext; + BOOL comInitialized = FALSE; + BOOL ret = FALSE; + MSG msg = { }; + + // Initialize COM and theme. + hr = ::CoInitialize(nullptr); + BalExitOnFailure(hr, "Failed to initialize COM."); + comInitialized = TRUE; + + hr = ThemeInitialize(pThis->_hModule); + BalExitOnFailure(hr, "Failed to initialize theme manager."); + + hr = pThis->InitializeData(); + BalExitOnFailure(hr, "Failed to initialize data in bootstrapper application."); + + // Create main window. + pThis->InitializeTaskbarButton(); + hr = pThis->CreateMainWindow(); + BalExitOnFailure(hr, "Failed to create main window."); + + if (FAILED(pThis->_hrFinal)) { + pThis->SetState(PYBA_STATE_FAILED, hr); + ::PostMessageW(pThis->_hWnd, WM_PYBA_SHOW_FAILURE, 0, 0); + } else { + // Okay, we're ready for packages now. + pThis->SetState(PYBA_STATE_INITIALIZED, hr); + ::PostMessageW(pThis->_hWnd, BOOTSTRAPPER_ACTION_HELP == pThis->_command.action ? WM_PYBA_SHOW_HELP : WM_PYBA_DETECT_PACKAGES, 0, 0); + } + + // message pump + while (0 != (ret = ::GetMessageW(&msg, nullptr, 0, 0))) { + if (-1 == ret) { + hr = E_UNEXPECTED; + BalExitOnFailure(hr, "Unexpected return value from message pump."); + } else if (!ThemeHandleKeyboardMessage(pThis->_theme, msg.hwnd, &msg)) { + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } + } + + // Succeeded thus far, check to see if anything went wrong while actually + // executing changes. + if (FAILED(pThis->_hrFinal)) { + hr = pThis->_hrFinal; + } else if (pThis->CheckCanceled()) { + hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); + } + + LExit: + // destroy main window + pThis->DestroyMainWindow(); + + // initiate engine shutdown + DWORD dwQuit = HRESULT_CODE(hr); + if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->_restartResult) { + dwQuit = ERROR_SUCCESS_REBOOT_INITIATED; + } else if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == pThis->_restartResult) { + dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED; + } + pThis->_engine->Quit(dwQuit); + + ReleaseTheme(pThis->_theme); + ThemeUninitialize(); + + // uninitialize COM + if (comInitialized) { + ::CoUninitialize(); + } + + return hr; + } + + + // + // InitializeData - initializes all the package information. + // + HRESULT InitializeData() { + HRESULT hr = S_OK; + LPWSTR sczModulePath = nullptr; + IXMLDOMDocument *pixdManifest = nullptr; + + hr = BalManifestLoad(_hModule, &pixdManifest); + BalExitOnFailure(hr, "Failed to load bootstrapper application manifest."); + + hr = ParseOverridableVariablesFromXml(pixdManifest); + BalExitOnFailure(hr, "Failed to read overridable variables."); + + hr = ProcessCommandLine(&_language); + ExitOnFailure(hr, "Unknown commandline parameters."); + + hr = PathRelativeToModule(&sczModulePath, nullptr, _hModule); + BalExitOnFailure(hr, "Failed to get module path."); + + hr = LoadLocalization(sczModulePath, _language); + ExitOnFailure(hr, "Failed to load localization."); + + hr = LoadTheme(sczModulePath, _language); + ExitOnFailure(hr, "Failed to load theme."); + + hr = BalInfoParseFromXml(&_bundle, pixdManifest); + BalExitOnFailure(hr, "Failed to load bundle information."); + + hr = BalConditionsParseFromXml(&_conditions, pixdManifest, _wixLoc); + BalExitOnFailure(hr, "Failed to load conditions from XML."); + + hr = LoadBootstrapperBAFunctions(); + BalExitOnFailure(hr, "Failed to load bootstrapper functions."); + + GetBundleFileVersion(); + // don't fail if we couldn't get the version info; best-effort only + + LExit: + ReleaseObject(pixdManifest); + ReleaseStr(sczModulePath); + + return hr; + } + + + // + // ProcessCommandLine - process the provided command line arguments. + // + HRESULT ProcessCommandLine(__inout LPWSTR* psczLanguage) { + HRESULT hr = S_OK; + int argc = 0; + LPWSTR* argv = nullptr; + LPWSTR sczVariableName = nullptr; + LPWSTR sczVariableValue = nullptr; + + if (_command.wzCommandLine && *_command.wzCommandLine) { + argv = ::CommandLineToArgvW(_command.wzCommandLine, &argc); + ExitOnNullWithLastError(argv, hr, "Failed to get command line."); + + for (int i = 0; i < argc; ++i) { + if (argv[i][0] == L'-' || argv[i][0] == L'/') { + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"lang", -1)) { + if (i + 1 >= argc) { + hr = E_INVALIDARG; + BalExitOnFailure(hr, "Must specify a language."); + } + + ++i; + + hr = StrAllocString(psczLanguage, &argv[i][0], 0); + BalExitOnFailure(hr, "Failed to copy language."); + } + } else if (_overridableVariables) { + int value; + const wchar_t* pwc = wcschr(argv[i], L'='); + if (pwc) { + hr = StrAllocString(&sczVariableName, argv[i], pwc - argv[i]); + BalExitOnFailure(hr, "Failed to copy variable name."); + + hr = DictKeyExists(_overridableVariables, sczVariableName); + if (E_NOTFOUND == hr) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Ignoring attempt to set non-overridable variable: '%ls'.", sczVariableName); + hr = S_OK; + continue; + } + ExitOnFailure(hr, "Failed to check the dictionary of overridable variables."); + + hr = StrAllocString(&sczVariableValue, ++pwc, 0); + BalExitOnFailure(hr, "Failed to copy variable value."); + + if (::StrToIntEx(sczVariableValue, STIF_DEFAULT, &value)) { + hr = _engine->SetVariableNumeric(sczVariableName, value); + } else { + hr = _engine->SetVariableString(sczVariableName, sczVariableValue); + } + BalExitOnFailure(hr, "Failed to set variable."); + } else { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Ignoring unknown argument: %ls", argv[i]); + } + } + } + } + + LExit: + if (argv) { + ::LocalFree(argv); + } + + ReleaseStr(sczVariableName); + ReleaseStr(sczVariableValue); + + return hr; + } + + HRESULT LoadLocalization(__in_z LPCWSTR wzModulePath, __in_z_opt LPCWSTR wzLanguage) { + HRESULT hr = S_OK; + LPWSTR sczLocPath = nullptr; + LPCWSTR wzLocFileName = L"Default.wxl"; + + hr = LocProbeForFile(wzModulePath, wzLocFileName, wzLanguage, &sczLocPath); + BalExitOnFailure2(hr, "Failed to probe for loc file: %ls in path: %ls", wzLocFileName, wzModulePath); + + hr = LocLoadFromFile(sczLocPath, &_wixLoc); + BalExitOnFailure1(hr, "Failed to load loc file from path: %ls", sczLocPath); + + if (WIX_LOCALIZATION_LANGUAGE_NOT_SET != _wixLoc->dwLangId) { + ::SetThreadLocale(_wixLoc->dwLangId); + } + + hr = StrAllocString(&_confirmCloseMessage, L"#(loc.ConfirmCancelMessage)", 0); + ExitOnFailure(hr, "Failed to initialize confirm message loc identifier."); + + hr = LocLocalizeString(_wixLoc, &_confirmCloseMessage); + BalExitOnFailure1(hr, "Failed to localize confirm close message: %ls", _confirmCloseMessage); + + LExit: + ReleaseStr(sczLocPath); + + return hr; + } + + + HRESULT LoadTheme(__in_z LPCWSTR wzModulePath, __in_z_opt LPCWSTR wzLanguage) { + HRESULT hr = S_OK; + LPWSTR sczThemePath = nullptr; + LPCWSTR wzThemeFileName = L"Default.thm"; + LPWSTR sczCaption = nullptr; + + hr = LocProbeForFile(wzModulePath, wzThemeFileName, wzLanguage, &sczThemePath); + BalExitOnFailure2(hr, "Failed to probe for theme file: %ls in path: %ls", wzThemeFileName, wzModulePath); + + hr = ThemeLoadFromFile(sczThemePath, &_theme); + BalExitOnFailure1(hr, "Failed to load theme from path: %ls", sczThemePath); + + hr = ThemeLocalize(_theme, _wixLoc); + BalExitOnFailure1(hr, "Failed to localize theme: %ls", sczThemePath); + + // Update the caption if there are any formatted strings in it. + // If the wix developer is showing a hidden variable in the UI, then + // obviously they don't care about keeping it safe so don't go down the + // rabbit hole of making sure that this is securely freed. + hr = BalFormatString(_theme->sczCaption, &sczCaption); + if (SUCCEEDED(hr)) { + ThemeUpdateCaption(_theme, sczCaption); + } + + LExit: + ReleaseStr(sczCaption); + ReleaseStr(sczThemePath); + + return hr; + } + + + HRESULT ParseOverridableVariablesFromXml(__in IXMLDOMDocument* pixdManifest) { + HRESULT hr = S_OK; + IXMLDOMNode* pNode = nullptr; + IXMLDOMNodeList* pNodes = nullptr; + DWORD cNodes = 0; + LPWSTR scz = nullptr; + BOOL hidden = FALSE; + + // get the list of variables users can override on the command line + hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixStdbaOverridableVariable", &pNodes); + if (S_FALSE == hr) { + ExitFunction1(hr = S_OK); + } + ExitOnFailure(hr, "Failed to select overridable variable nodes."); + + hr = pNodes->get_length((long*)&cNodes); + ExitOnFailure(hr, "Failed to get overridable variable node count."); + + if (cNodes) { + hr = DictCreateStringList(&_overridableVariables, 32, DICT_FLAG_NONE); + ExitOnFailure(hr, "Failed to create the string dictionary."); + + for (DWORD i = 0; i < cNodes; ++i) { + hr = XmlNextElement(pNodes, &pNode, nullptr); + ExitOnFailure(hr, "Failed to get next node."); + + // @Name + hr = XmlGetAttributeEx(pNode, L"Name", &scz); + ExitOnFailure(hr, "Failed to get @Name."); + + hr = XmlGetYesNoAttribute(pNode, L"Hidden", &hidden); + + if (!hidden) { + hr = DictAddKey(_overridableVariables, scz); + ExitOnFailure1(hr, "Failed to add \"%ls\" to the string dictionary.", scz); + } + + // prepare next iteration + ReleaseNullObject(pNode); + } + } + + LExit: + ReleaseObject(pNode); + ReleaseObject(pNodes); + ReleaseStr(scz); + return hr; + } + + + // + // Get the file version of the bootstrapper and record in bootstrapper log file + // + HRESULT GetBundleFileVersion() { + HRESULT hr = S_OK; + ULARGE_INTEGER uliVersion = { }; + LPWSTR sczCurrentPath = nullptr; + + hr = PathForCurrentProcess(&sczCurrentPath, nullptr); + BalExitOnFailure(hr, "Failed to get bundle path."); + + hr = FileVersion(sczCurrentPath, &uliVersion.HighPart, &uliVersion.LowPart); + BalExitOnFailure(hr, "Failed to get bundle file version."); + + hr = _engine->SetVariableVersion(PYBA_VARIABLE_BUNDLE_FILE_VERSION, uliVersion.QuadPart); + BalExitOnFailure(hr, "Failed to set WixBundleFileVersion variable."); + + LExit: + ReleaseStr(sczCurrentPath); + + return hr; + } + + + // + // CreateMainWindow - creates the main install window. + // + HRESULT CreateMainWindow() { + HRESULT hr = S_OK; + HICON hIcon = reinterpret_cast(_theme->hIcon); + WNDCLASSW wc = { }; + DWORD dwWindowStyle = 0; + int x = CW_USEDEFAULT; + int y = CW_USEDEFAULT; + POINT ptCursor = { }; + HMONITOR hMonitor = nullptr; + MONITORINFO mi = { }; + + // If the theme did not provide an icon, try using the icon from the bundle engine. + if (!hIcon) { + HMODULE hBootstrapperEngine = ::GetModuleHandleW(nullptr); + if (hBootstrapperEngine) { + hIcon = ::LoadIconW(hBootstrapperEngine, MAKEINTRESOURCEW(1)); + } + } + + // Register the window class and create the window. + wc.lpfnWndProc = PythonBootstrapperApplication::WndProc; + wc.hInstance = _hModule; + wc.hIcon = hIcon; + wc.hCursor = ::LoadCursorW(nullptr, (LPCWSTR)IDC_ARROW); + wc.hbrBackground = _theme->rgFonts[_theme->dwFontId].hBackground; + wc.lpszMenuName = nullptr; + wc.lpszClassName = PYBA_WINDOW_CLASS; + if (!::RegisterClassW(&wc)) { + ExitWithLastError(hr, "Failed to register window."); + } + + _registered = TRUE; + + // Calculate the window style based on the theme style and command display value. + dwWindowStyle = _theme->dwStyle; + if (BOOTSTRAPPER_DISPLAY_NONE >= _command.display) { + dwWindowStyle &= ~WS_VISIBLE; + } + + // Don't show the window if there is a splash screen (it will be made visible when the splash screen is hidden) + if (::IsWindow(_command.hwndSplashScreen)) { + dwWindowStyle &= ~WS_VISIBLE; + } + + // Center the window on the monitor with the mouse. + if (::GetCursorPos(&ptCursor)) { + hMonitor = ::MonitorFromPoint(ptCursor, MONITOR_DEFAULTTONEAREST); + if (hMonitor) { + mi.cbSize = sizeof(mi); + if (::GetMonitorInfoW(hMonitor, &mi)) { + x = mi.rcWork.left + (mi.rcWork.right - mi.rcWork.left - _theme->nWidth) / 2; + y = mi.rcWork.top + (mi.rcWork.bottom - mi.rcWork.top - _theme->nHeight) / 2; + } + } + } + + _hWnd = ::CreateWindowExW( + 0, + wc.lpszClassName, + _theme->sczCaption, + dwWindowStyle, + x, + y, + _theme->nWidth, + _theme->nHeight, + HWND_DESKTOP, + nullptr, + _hModule, + this + ); + ExitOnNullWithLastError(_hWnd, hr, "Failed to create window."); + + hr = S_OK; + + LExit: + return hr; + } + + + // + // InitializeTaskbarButton - initializes taskbar button for progress. + // + void InitializeTaskbarButton() { + HRESULT hr = S_OK; + + hr = ::CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, __uuidof(ITaskbarList3), reinterpret_cast(&_taskbarList)); + if (REGDB_E_CLASSNOTREG == hr) { + // not supported before Windows 7 + ExitFunction1(hr = S_OK); + } + BalExitOnFailure(hr, "Failed to create ITaskbarList3. Continuing."); + + _taskbarButtonCreatedMessage = ::RegisterWindowMessageW(L"TaskbarButtonCreated"); + BalExitOnNullWithLastError(_taskbarButtonCreatedMessage, hr, "Failed to get TaskbarButtonCreated message. Continuing."); + + LExit: + return; + } + + // + // DestroyMainWindow - clean up all the window registration. + // + void DestroyMainWindow() { + if (::IsWindow(_hWnd)) { + ::DestroyWindow(_hWnd); + _hWnd = nullptr; + _taskbarButtonOK = FALSE; + } + + if (_registered) { + ::UnregisterClassW(PYBA_WINDOW_CLASS, _hModule); + _registered = FALSE; + } + } + + + // + // WndProc - standard windows message handler. + // + static LRESULT CALLBACK WndProc( + __in HWND hWnd, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ) { +#pragma warning(suppress:4312) + auto pBA = reinterpret_cast(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)); + + switch (uMsg) { + case WM_NCCREATE: { + LPCREATESTRUCT lpcs = reinterpret_cast(lParam); + pBA = reinterpret_cast(lpcs->lpCreateParams); +#pragma warning(suppress:4244) + ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast(pBA)); + break; + } + + case WM_NCDESTROY: { + LRESULT lres = ThemeDefWindowProc(pBA ? pBA->_theme : nullptr, hWnd, uMsg, wParam, lParam); + ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0); + return lres; + } + + case WM_CREATE: + if (!pBA->OnCreate(hWnd)) { + return -1; + } + break; + + case WM_QUERYENDSESSION: + return IDCANCEL != pBA->OnSystemShutdown(static_cast(lParam), IDCANCEL); + + case WM_CLOSE: + // If the user chose not to close, do *not* let the default window proc handle the message. + if (!pBA->OnClose()) { + return 0; + } + break; + + case WM_DESTROY: + ::PostQuitMessage(0); + break; + + case WM_PAINT: __fallthrough; + case WM_ERASEBKGND: + if (pBA && pBA->_suppressPaint) { + return TRUE; + } + break; + + case WM_PYBA_SHOW_HELP: + pBA->OnShowHelp(); + return 0; + + case WM_PYBA_DETECT_PACKAGES: + pBA->OnDetect(); + return 0; + + case WM_PYBA_PLAN_PACKAGES: + pBA->OnPlan(static_cast(lParam)); + return 0; + + case WM_PYBA_APPLY_PACKAGES: + pBA->OnApply(); + return 0; + + case WM_PYBA_CHANGE_STATE: + pBA->OnChangeState(static_cast(lParam)); + return 0; + + case WM_PYBA_SHOW_FAILURE: + pBA->OnShowFailure(); + return 0; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + // Customize commands + // Success/failure commands + case ID_LAUNCH_BUTTON: + pBA->OnClickLaunchButton(); + return 0; + + case ID_SUCCESS_RESTART_BUTTON: __fallthrough; + case ID_FAILURE_RESTART_BUTTON: + pBA->OnClickRestartButton(); + return 0; + + case IDCANCEL: __fallthrough; + case ID_INSTALL_CANCEL_BUTTON: __fallthrough; + case ID_CUSTOM1_CANCEL_BUTTON: __fallthrough; + case ID_CUSTOM2_CANCEL_BUTTON: __fallthrough; + case ID_MODIFY_CANCEL_BUTTON: __fallthrough; + case ID_PROGRESS_CANCEL_BUTTON: __fallthrough; + case ID_SUCCESS_CANCEL_BUTTON: __fallthrough; + case ID_FAILURE_CANCEL_BUTTON: __fallthrough; + case ID_CLOSE_BUTTON: + pBA->OnCommand(ID_CLOSE_BUTTON); + return 0; + + default: + pBA->OnCommand((CONTROL_ID)LOWORD(wParam)); + } + break; + + case WM_NOTIFY: + if (lParam) { + LPNMHDR pnmhdr = reinterpret_cast(lParam); + switch (pnmhdr->code) { + case NM_CLICK: __fallthrough; + case NM_RETURN: + switch (static_cast(pnmhdr->idFrom)) { + case ID_FAILURE_LOGFILE_LINK: + pBA->OnClickLogFileLink(); + return 1; + } + } + } + break; + + case WM_CTLCOLORBTN: + if (pBA) { + HWND button = (HWND)lParam; + DWORD style = GetWindowLong(button, GWL_STYLE) & BS_TYPEMASK; + if (style == BS_COMMANDLINK || style == BS_DEFCOMMANDLINK) { + return (LRESULT)pBA->_theme->rgFonts[pBA->_theme->dwFontId].hBackground; + } + } + break; + } + + if (pBA && pBA->_taskbarList && uMsg == pBA->_taskbarButtonCreatedMessage) { + pBA->_taskbarButtonOK = TRUE; + return 0; + } + + return ThemeDefWindowProc(pBA ? pBA->_theme : nullptr, hWnd, uMsg, wParam, lParam); + } + + // + // OnCreate - finishes loading the theme. + // + BOOL OnCreate(__in HWND hWnd) { + HRESULT hr = S_OK; + + hr = ThemeLoadControls(_theme, hWnd, CONTROL_ID_NAMES, countof(CONTROL_ID_NAMES)); + BalExitOnFailure(hr, "Failed to load theme controls."); + + C_ASSERT(COUNT_PAGE == countof(PAGE_NAMES)); + C_ASSERT(countof(_pageIds) == countof(PAGE_NAMES)); + + ThemeGetPageIds(_theme, PAGE_NAMES, _pageIds, countof(_pageIds)); + + // Initialize the text on all "application" (non-page) controls. + for (DWORD i = 0; i < _theme->cControls; ++i) { + THEME_CONTROL* pControl = _theme->rgControls + i; + LPWSTR text = nullptr; + LPWSTR name = nullptr; + LOC_STRING *locText = nullptr; + + // If a command link has a note, then add it. + if ((pControl->dwStyle & BS_TYPEMASK) == BS_COMMANDLINK || + (pControl->dwStyle & BS_TYPEMASK) == BS_DEFCOMMANDLINK) { + hr = StrAllocFormatted(&name, L"#(loc.%lsNote)", pControl->sczName); + if (SUCCEEDED(hr)) { + hr = LocGetString(_wixLoc, name, &locText); + ReleaseStr(name); + if (SUCCEEDED(hr) && locText && locText->wzText && locText->wzText[0]) { + hr = BalFormatString(locText->wzText, &text); + if (SUCCEEDED(hr) && text && text[0]) { + ThemeSendControlMessage(_theme, pControl->wId, BCM_SETNOTE, 0, (LPARAM)text); + ReleaseStr(text); + text = nullptr; + } + } + } + hr = S_OK; + } + + if (!pControl->wPageId && pControl->sczText && *pControl->sczText) { + HRESULT hrFormat; + + // If the wix developer is showing a hidden variable in the UI, + // then obviously they don't care about keeping it safe so don't + // go down the rabbit hole of making sure that this is securely + // freed. + hrFormat = BalFormatString(pControl->sczText, &text); + if (SUCCEEDED(hrFormat)) { + ThemeSetTextControl(_theme, pControl->wId, text); + ReleaseStr(text); + } + } + } + + LExit: + return SUCCEEDED(hr); + } + + + // + // OnShowFailure - display the failure page. + // + void OnShowFailure() { + SetState(PYBA_STATE_FAILED, S_OK); + + // If the UI should be visible, display it now and hide the splash screen + if (BOOTSTRAPPER_DISPLAY_NONE < _command.display) { + ::ShowWindow(_theme->hwndParent, SW_SHOW); + } + + _engine->CloseSplashScreen(); + + return; + } + + + // + // OnShowHelp - display the help page. + // + void OnShowHelp() { + SetState(PYBA_STATE_HELP, S_OK); + + // If the UI should be visible, display it now and hide the splash screen + if (BOOTSTRAPPER_DISPLAY_NONE < _command.display) { + ::ShowWindow(_theme->hwndParent, SW_SHOW); + } + + _engine->CloseSplashScreen(); + + return; + } + + + // + // OnDetect - start the processing of packages. + // + void OnDetect() { + HRESULT hr = S_OK; + + if (_baFunction) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running detect BA function"); + hr = _baFunction->OnDetect(); + BalExitOnFailure(hr, "Failed calling detect BA function."); + } + + SetState(PYBA_STATE_DETECTING, hr); + + // If the UI should be visible, display it now and hide the splash screen + if (BOOTSTRAPPER_DISPLAY_NONE < _command.display) { + ::ShowWindow(_theme->hwndParent, SW_SHOW); + } + + _engine->CloseSplashScreen(); + + // Tell the core we're ready for the packages to be processed now. + hr = _engine->Detect(); + BalExitOnFailure(hr, "Failed to start detecting chain."); + + LExit: + if (FAILED(hr)) { + SetState(PYBA_STATE_DETECTING, hr); + } + + return; + } + + + // + // OnPlan - plan the detected changes. + // + void OnPlan(__in BOOTSTRAPPER_ACTION action) { + HRESULT hr = S_OK; + LPCWSTR likeInstalling = nullptr; + LPCWSTR likeInstallation = nullptr; + + _plannedAction = action; + + switch (action) { + case BOOTSTRAPPER_ACTION_INSTALL: + likeInstalling = L"Installing"; + likeInstallation = L"Installation"; + break; + case BOOTSTRAPPER_ACTION_MODIFY: + // For modify, we actually want to pass INSTALL + action = BOOTSTRAPPER_ACTION_INSTALL; + likeInstalling = L"Modifying"; + likeInstallation = L"Modification"; + break; + case BOOTSTRAPPER_ACTION_REPAIR: + likeInstalling = L"Repairing"; + likeInstallation = L"Repair"; + break; + case BOOTSTRAPPER_ACTION_UNINSTALL: + likeInstalling = L"Uninstalling"; + likeInstallation = L"Uninstallation"; + break; + } + + if (likeInstalling) { + LPWSTR locName = nullptr; + LOC_STRING *locText = nullptr; + hr = StrAllocFormatted(&locName, L"#(loc.%ls)", likeInstalling); + if (SUCCEEDED(hr)) { + hr = LocGetString(_wixLoc, locName, &locText); + ReleaseStr(locName); + } + _engine->SetVariableString( + L"ActionLikeInstalling", + SUCCEEDED(hr) && locText ? locText->wzText : likeInstalling + ); + } + + if (likeInstallation) { + LPWSTR locName = nullptr; + LOC_STRING *locText = nullptr; + hr = StrAllocFormatted(&locName, L"#(loc.%ls)", likeInstallation); + if (SUCCEEDED(hr)) { + hr = LocGetString(_wixLoc, locName, &locText); + ReleaseStr(locName); + } + _engine->SetVariableString( + L"ActionLikeInstallation", + SUCCEEDED(hr) && locText ? locText->wzText : likeInstallation + ); + } + + // If we are going to apply a downgrade, bail. + if (_downgrading && BOOTSTRAPPER_ACTION_UNINSTALL < action) { + if (_suppressDowngradeFailure) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "A newer version of this product is installed but downgrade failure has been suppressed; continuing..."); + } else { + hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_VERSION); + BalExitOnFailure(hr, "Cannot install a product when a newer version is installed."); + } + } + + SetState(PYBA_STATE_PLANNING, hr); + + if (_baFunction) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running plan BA function"); + _baFunction->OnPlan(); + } + + hr = _engine->Plan(action); + BalExitOnFailure(hr, "Failed to start planning packages."); + + LExit: + if (FAILED(hr)) { + SetState(PYBA_STATE_PLANNING, hr); + } + + return; + } + + + // + // OnApply - apply the packages. + // + void OnApply() { + HRESULT hr = S_OK; + + SetState(PYBA_STATE_APPLYING, hr); + SetProgressState(hr); + SetTaskbarButtonProgress(0); + + hr = _engine->Apply(_hWnd); + BalExitOnFailure(hr, "Failed to start applying packages."); + + ThemeControlEnable(_theme, ID_PROGRESS_CANCEL_BUTTON, TRUE); // ensure the cancel button is enabled before starting. + + LExit: + if (FAILED(hr)) { + SetState(PYBA_STATE_APPLYING, hr); + } + + return; + } + + + // + // OnChangeState - change state. + // + void OnChangeState(__in PYBA_STATE state) { + LPWSTR unformattedText = nullptr; + + _state = state; + + // If our install is at the end (success or failure) and we're not showing full UI + // then exit (prompt for restart if required). + if ((PYBA_STATE_APPLIED <= _state && BOOTSTRAPPER_DISPLAY_FULL > _command.display)) { + // If a restart was required but we were not automatically allowed to + // accept the reboot then do the prompt. + if (_restartRequired && !_allowRestart) { + StrAllocFromError(&unformattedText, HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), nullptr); + + _allowRestart = IDOK == ::MessageBoxW( + _hWnd, + unformattedText ? unformattedText : L"The requested operation is successful. Changes will not be effective until the system is rebooted.", + _theme->sczCaption, + MB_ICONEXCLAMATION | MB_OKCANCEL + ); + } + + // Quietly exit. + ::PostMessageW(_hWnd, WM_CLOSE, 0, 0); + } else { // try to change the pages. + DWORD newPageId = 0; + DeterminePageId(_state, &newPageId); + + if (_visiblePageId != newPageId) { + ShowPage(newPageId); + } + } + + ReleaseStr(unformattedText); + } + + // + // Called before showing a page to handle all controls. + // + void ProcessPageControls(THEME_PAGE *pPage) { + if (!pPage) { + return; + } + + for (DWORD i = 0; i < pPage->cControlIndices; ++i) { + THEME_CONTROL* pControl = _theme->rgControls + pPage->rgdwControlIndices[i]; + + // If this is a named control, try to set its default state. + if (pControl->sczName && *pControl->sczName) { + // If this is a checkable control, try to set its default state + // to the state of a matching named Burn variable. + if (IsCheckable(pControl)) { + LONGLONG llValue = 0; + HRESULT hr = BalGetNumericVariable(pControl->sczName, &llValue); + + // If the control value isn't set then disable it. + if (!SUCCEEDED(hr)) { + ThemeControlEnable(_theme, pControl->wId, FALSE); + } else { + ThemeSendControlMessage( + _theme, + pControl->wId, + BM_SETCHECK, + SUCCEEDED(hr) && llValue ? BST_CHECKED : BST_UNCHECKED, + 0 + ); + } + } + + // Hide or disable controls based on the control name with 'State' appended + LPWSTR controlName = nullptr; + HRESULT hr = StrAllocFormatted(&controlName, L"%lsState", pControl->sczName); + if (SUCCEEDED(hr)) { + LPWSTR controlState = nullptr; + hr = BalGetStringVariable(controlName, &controlState); + if (SUCCEEDED(hr) && controlState && *controlState) { + if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, controlState, -1, L"disable", -1)) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Disable control %ls", pControl->sczName); + ThemeControlEnable(_theme, pControl->wId, FALSE); + } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, controlState, -1, L"hide", -1)) { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Hide control %ls", pControl->sczName); + // TODO: This doesn't work + ThemeShowControl(_theme, pControl->wId, SW_HIDE); + } + } + StrFree(controlState); + } + StrFree(controlName); + } + + // Format the text in each of the new page's controls + if (pControl->sczText && *pControl->sczText) { + // If the wix developer is showing a hidden variable + // in the UI, then obviously they don't care about + // keeping it safe so don't go down the rabbit hole + // of making sure that this is securely freed. + LPWSTR text = nullptr; + HRESULT hr = BalFormatString(pControl->sczText, &text); + if (SUCCEEDED(hr)) { + ThemeSetTextControl(_theme, pControl->wId, text); + } + } + } + } + + // + // OnClose - called when the window is trying to be closed. + // + BOOL OnClose() { + BOOL close = FALSE; + + // If we've already succeeded or failed or showing the help page, just close (prompts are annoying if the bootstrapper is done). + if (PYBA_STATE_APPLIED <= _state || PYBA_STATE_HELP == _state) { + close = TRUE; + } else { + // prompt the user or force the cancel if there is no UI. + close = PromptCancel( + _hWnd, + BOOTSTRAPPER_DISPLAY_FULL != _command.display, + _confirmCloseMessage ? _confirmCloseMessage : L"Are you sure you want to cancel?", + _theme->sczCaption + ); + } + + // If we're doing progress then we never close, we just cancel to let rollback occur. + if (PYBA_STATE_APPLYING <= _state && PYBA_STATE_APPLIED > _state) { + // If we canceled disable cancel button since clicking it again is silly. + if (close) { + ThemeControlEnable(_theme, ID_PROGRESS_CANCEL_BUTTON, FALSE); + } + + close = FALSE; + } + + return close; + } + + // + // OnClickCloseButton - close the application. + // + void OnClickCloseButton() { + ::SendMessageW(_hWnd, WM_CLOSE, 0, 0); + } + + + // + // OnClickLaunchButton - launch the app from the success page. + // + void OnClickLaunchButton() { + HRESULT hr = S_OK; + LPWSTR sczUnformattedLaunchTarget = nullptr; + LPWSTR sczLaunchTarget = nullptr; + LPWSTR sczLaunchTargetElevatedId = nullptr; + LPWSTR sczUnformattedArguments = nullptr; + LPWSTR sczArguments = nullptr; + int nCmdShow = SW_SHOWNORMAL; + + hr = BalGetStringVariable(PYBA_VARIABLE_LAUNCH_TARGET_PATH, &sczUnformattedLaunchTarget); + BalExitOnFailure1(hr, "Failed to get launch target variable '%ls'.", PYBA_VARIABLE_LAUNCH_TARGET_PATH); + + hr = BalFormatString(sczUnformattedLaunchTarget, &sczLaunchTarget); + BalExitOnFailure1(hr, "Failed to format launch target variable: %ls", sczUnformattedLaunchTarget); + + if (BalStringVariableExists(PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID)) { + hr = BalGetStringVariable(PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID, &sczLaunchTargetElevatedId); + BalExitOnFailure1(hr, "Failed to get launch target elevated id '%ls'.", PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID); + } + + if (BalStringVariableExists(PYBA_VARIABLE_LAUNCH_ARGUMENTS)) { + hr = BalGetStringVariable(PYBA_VARIABLE_LAUNCH_ARGUMENTS, &sczUnformattedArguments); + BalExitOnFailure1(hr, "Failed to get launch arguments '%ls'.", PYBA_VARIABLE_LAUNCH_ARGUMENTS); + } + + if (BalStringVariableExists(PYBA_VARIABLE_LAUNCH_HIDDEN)) { + nCmdShow = SW_HIDE; + } + + if (sczLaunchTargetElevatedId && !_triedToLaunchElevated) { + _triedToLaunchElevated = TRUE; + hr = _engine->LaunchApprovedExe(_hWnd, sczLaunchTargetElevatedId, sczUnformattedArguments, 0); + if (FAILED(hr)) { + BalLogError(hr, "Failed to launch elevated target: %ls", sczLaunchTargetElevatedId); + + //try with ShelExec next time + OnClickLaunchButton(); + } + } else { + if (sczUnformattedArguments) { + hr = BalFormatString(sczUnformattedArguments, &sczArguments); + BalExitOnFailure1(hr, "Failed to format launch arguments variable: %ls", sczUnformattedArguments); + } + + hr = ShelExec(sczLaunchTarget, sczArguments, L"open", nullptr, nCmdShow, _hWnd, nullptr); + BalExitOnFailure1(hr, "Failed to launch target: %ls", sczLaunchTarget); + + ::PostMessageW(_hWnd, WM_CLOSE, 0, 0); + } + + LExit: + StrSecureZeroFreeString(sczArguments); + ReleaseStr(sczUnformattedArguments); + ReleaseStr(sczLaunchTargetElevatedId); + StrSecureZeroFreeString(sczLaunchTarget); + ReleaseStr(sczUnformattedLaunchTarget); + + return; + } + + + // + // OnClickRestartButton - allows the restart and closes the app. + // + void OnClickRestartButton() { + AssertSz(_restartRequired, "Restart must be requested to be able to click on the restart button."); + + _allowRestart = TRUE; + ::SendMessageW(_hWnd, WM_CLOSE, 0, 0); + + return; + } + + + // + // OnClickLogFileLink - show the log file. + // + void OnClickLogFileLink() { + HRESULT hr = S_OK; + LPWSTR sczLogFile = nullptr; + + hr = BalGetStringVariable(_bundle.sczLogVariable, &sczLogFile); + BalExitOnFailure1(hr, "Failed to get log file variable '%ls'.", _bundle.sczLogVariable); + + hr = ShelExec(L"notepad.exe", sczLogFile, L"open", nullptr, SW_SHOWDEFAULT, _hWnd, nullptr); + BalExitOnFailure1(hr, "Failed to open log file target: %ls", sczLogFile); + + LExit: + ReleaseStr(sczLogFile); + + return; + } + + + // + // SetState + // + void SetState(__in PYBA_STATE state, __in HRESULT hrStatus) { + if (FAILED(hrStatus)) { + _hrFinal = hrStatus; + } + + if (FAILED(_hrFinal)) { + state = PYBA_STATE_FAILED; + } + + if (_state != state) { + ::PostMessageW(_hWnd, WM_PYBA_CHANGE_STATE, 0, state); + } + } + + // + // GoToPage + // + void GoToPage(__in PAGE page) { + _installPage = page; + ::PostMessageW(_hWnd, WM_PYBA_CHANGE_STATE, 0, _state); + } + + void DeterminePageId(__in PYBA_STATE state, __out DWORD* pdwPageId) { + LONGLONG simple; + + if (BOOTSTRAPPER_DISPLAY_PASSIVE == _command.display) { + switch (state) { + case PYBA_STATE_INITIALIZED: + *pdwPageId = BOOTSTRAPPER_ACTION_HELP == _command.action + ? _pageIds[PAGE_HELP] + : _pageIds[PAGE_LOADING]; + break; + + case PYBA_STATE_HELP: + *pdwPageId = _pageIds[PAGE_HELP]; + break; + + case PYBA_STATE_DETECTING: + *pdwPageId = _pageIds[PAGE_LOADING] + ? _pageIds[PAGE_LOADING] + : _pageIds[PAGE_PROGRESS_PASSIVE] + ? _pageIds[PAGE_PROGRESS_PASSIVE] + : _pageIds[PAGE_PROGRESS]; + break; + + case PYBA_STATE_DETECTED: __fallthrough; + case PYBA_STATE_PLANNING: __fallthrough; + case PYBA_STATE_PLANNED: __fallthrough; + case PYBA_STATE_APPLYING: __fallthrough; + case PYBA_STATE_CACHING: __fallthrough; + case PYBA_STATE_CACHED: __fallthrough; + case PYBA_STATE_EXECUTING: __fallthrough; + case PYBA_STATE_EXECUTED: + *pdwPageId = _pageIds[PAGE_PROGRESS_PASSIVE] + ? _pageIds[PAGE_PROGRESS_PASSIVE] + : _pageIds[PAGE_PROGRESS]; + break; + + default: + *pdwPageId = 0; + break; + } + } else if (BOOTSTRAPPER_DISPLAY_FULL == _command.display) { + switch (state) { + case PYBA_STATE_INITIALIZING: + *pdwPageId = 0; + break; + + case PYBA_STATE_INITIALIZED: + *pdwPageId = BOOTSTRAPPER_ACTION_HELP == _command.action + ? _pageIds[PAGE_HELP] + : _pageIds[PAGE_LOADING]; + break; + + case PYBA_STATE_HELP: + *pdwPageId = _pageIds[PAGE_HELP]; + break; + + case PYBA_STATE_DETECTING: + *pdwPageId = _pageIds[PAGE_LOADING]; + break; + + case PYBA_STATE_DETECTED: + if (_installPage == PAGE_LOADING) { + switch (_command.action) { + case BOOTSTRAPPER_ACTION_INSTALL: + if (SUCCEEDED(BalGetNumericVariable(L"SimpleInstall", &simple)) && simple) { + _installPage = PAGE_SIMPLE_INSTALL; + } else { + _installPage = PAGE_INSTALL; + } + break; + + case BOOTSTRAPPER_ACTION_MODIFY: __fallthrough; + case BOOTSTRAPPER_ACTION_REPAIR: __fallthrough; + case BOOTSTRAPPER_ACTION_UNINSTALL: + _installPage = PAGE_MODIFY; + break; + } + } + *pdwPageId = _pageIds[_installPage]; + break; + + case PYBA_STATE_PLANNING: __fallthrough; + case PYBA_STATE_PLANNED: __fallthrough; + case PYBA_STATE_APPLYING: __fallthrough; + case PYBA_STATE_CACHING: __fallthrough; + case PYBA_STATE_CACHED: __fallthrough; + case PYBA_STATE_EXECUTING: __fallthrough; + case PYBA_STATE_EXECUTED: + *pdwPageId = _pageIds[PAGE_PROGRESS]; + break; + + case PYBA_STATE_APPLIED: + *pdwPageId = _pageIds[PAGE_SUCCESS]; + break; + + case PYBA_STATE_FAILED: + *pdwPageId = _pageIds[PAGE_FAILURE]; + break; + } + } + } + + + HRESULT EvaluateConditions() { + HRESULT hr = S_OK; + BOOL result = FALSE; + + for (DWORD i = 0; i < _conditions.cConditions; ++i) { + BAL_CONDITION* pCondition = _conditions.rgConditions + i; + + hr = BalConditionEvaluate(pCondition, _engine, &result, &_failedMessage); + BalExitOnFailure(hr, "Failed to evaluate condition."); + + if (!result) { + // Hope they didn't have hidden variables in their message, because it's going in the log in plaintext. + BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "%ls", _failedMessage); + + hr = E_WIXSTDBA_CONDITION_FAILED; + // todo: remove in WiX v4, in case people are relying on v3.x logging behavior + BalExitOnFailure1(hr, "Bundle condition evaluated to false: %ls", pCondition->sczCondition); + } + } + + ReleaseNullStrSecure(_failedMessage); + + LExit: + return hr; + } + + + void SetTaskbarButtonProgress(__in DWORD dwOverallPercentage) { + HRESULT hr = S_OK; + + if (_taskbarButtonOK) { + hr = _taskbarList->SetProgressValue(_hWnd, dwOverallPercentage, 100UL); + BalExitOnFailure1(hr, "Failed to set taskbar button progress to: %d%%.", dwOverallPercentage); + } + + LExit: + return; + } + + + void SetTaskbarButtonState(__in TBPFLAG tbpFlags) { + HRESULT hr = S_OK; + + if (_taskbarButtonOK) { + hr = _taskbarList->SetProgressState(_hWnd, tbpFlags); + BalExitOnFailure1(hr, "Failed to set taskbar button state.", tbpFlags); + } + + LExit: + return; + } + + + void SetProgressState(__in HRESULT hrStatus) { + TBPFLAG flag = TBPF_NORMAL; + + if (IsCanceled() || HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) == hrStatus) { + flag = TBPF_PAUSED; + } else if (IsRollingBack() || FAILED(hrStatus)) { + flag = TBPF_ERROR; + } + + SetTaskbarButtonState(flag); + } + + + HRESULT LoadBootstrapperBAFunctions() { + HRESULT hr = S_OK; + LPWSTR sczBafPath = nullptr; + + hr = PathRelativeToModule(&sczBafPath, L"bafunctions.dll", _hModule); + BalExitOnFailure(hr, "Failed to get path to BA function DLL."); + +#ifdef DEBUG + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: LoadBootstrapperBAFunctions() - BA function DLL %ls", sczBafPath); +#endif + + _hBAFModule = ::LoadLibraryW(sczBafPath); + if (_hBAFModule) { + auto pfnBAFunctionCreate = reinterpret_cast(::GetProcAddress(_hBAFModule, "CreateBootstrapperBAFunction")); + BalExitOnNullWithLastError1(pfnBAFunctionCreate, hr, "Failed to get CreateBootstrapperBAFunction entry-point from: %ls", sczBafPath); + + hr = pfnBAFunctionCreate(_engine, _hBAFModule, &_baFunction); + BalExitOnFailure(hr, "Failed to create BA function."); + } +#ifdef DEBUG + else { + BalLogError(HRESULT_FROM_WIN32(::GetLastError()), "PYBA: LoadBootstrapperBAFunctions() - Failed to load DLL %ls", sczBafPath); + } +#endif + + LExit: + if (_hBAFModule && !_baFunction) { + ::FreeLibrary(_hBAFModule); + _hBAFModule = nullptr; + } + ReleaseStr(sczBafPath); + + return hr; + } + + BOOL IsCheckable(THEME_CONTROL* pControl) { + if (!pControl->sczName || !pControl->sczName[0]) { + return FALSE; + } + + if (pControl->type == THEME_CONTROL_TYPE_CHECKBOX) { + return TRUE; + } + + if (pControl->type == THEME_CONTROL_TYPE_BUTTON) { + if ((pControl->dwStyle & BS_TYPEMASK) == BS_AUTORADIOBUTTON) { + return TRUE; + } + } + + return FALSE; + } + + void SavePageSettings() { + DWORD pageId = 0; + THEME_PAGE* pPage = nullptr; + + DeterminePageId(_state, &pageId); + pPage = ThemeGetPage(_theme, pageId); + if (!pPage) { + return; + } + + for (DWORD i = 0; i < pPage->cControlIndices; ++i) { + // Loop through all the checkable controls and set a Burn variable + // with that name to true or false. + THEME_CONTROL* pControl = _theme->rgControls + pPage->rgdwControlIndices[i]; + if (IsCheckable(pControl) && ThemeControlEnabled(_theme, pControl->wId)) { + BOOL checked = ThemeIsControlChecked(_theme, pControl->wId); + _engine->SetVariableNumeric(pControl->sczName, checked ? 1 : 0); + } + + // Loop through all the editbox controls with names and set a + // Burn variable with that name to the contents. + if (THEME_CONTROL_TYPE_EDITBOX == pControl->type && pControl->sczName && *pControl->sczName) { + LPWSTR sczValue = nullptr; + ThemeGetTextControl(_theme, pControl->wId, &sczValue); + _engine->SetVariableString(pControl->sczName, sczValue); + } + } + } + + +public: + // + // Constructor - initialize member variables. + // + PythonBootstrapperApplication( + __in HMODULE hModule, + __in BOOL fPrereq, + __in HRESULT hrHostInitialization, + __in IBootstrapperEngine* pEngine, + __in const BOOTSTRAPPER_COMMAND* pCommand + ) : CBalBaseBootstrapperApplication(pEngine, pCommand, 3, 3000) { + _hModule = hModule; + memcpy_s(&_command, sizeof(_command), pCommand, sizeof(BOOTSTRAPPER_COMMAND)); + + LONGLONG llInstalled = 0; + HRESULT hr = BalGetNumericVariable(L"WixBundleInstalled", &llInstalled); + if (SUCCEEDED(hr) && BOOTSTRAPPER_RESUME_TYPE_REBOOT != _command.resumeType && 0 < llInstalled && BOOTSTRAPPER_ACTION_INSTALL == _command.action) { + _command.action = BOOTSTRAPPER_ACTION_MODIFY; + } else if (0 == llInstalled && (BOOTSTRAPPER_ACTION_MODIFY == _command.action || BOOTSTRAPPER_ACTION_REPAIR == _command.action)) { + _command.action = BOOTSTRAPPER_ACTION_INSTALL; + } + + _plannedAction = BOOTSTRAPPER_ACTION_UNKNOWN; + + + // When resuming from restart doing some install-like operation, try to find the package that forced the + // restart. We'll use this information during planning. + _nextPackageAfterRestart = nullptr; + + if (BOOTSTRAPPER_RESUME_TYPE_REBOOT == _command.resumeType && BOOTSTRAPPER_ACTION_UNINSTALL < _command.action) { + // Ensure the forced restart package variable is null when it is an empty string. + HRESULT hr = BalGetStringVariable(L"WixBundleForcedRestartPackage", &_nextPackageAfterRestart); + if (FAILED(hr) || !_nextPackageAfterRestart || !*_nextPackageAfterRestart) { + ReleaseNullStr(_nextPackageAfterRestart); + } + } + + _wixLoc = nullptr; + memset(&_bundle, 0, sizeof(_bundle)); + memset(&_conditions, 0, sizeof(_conditions)); + _confirmCloseMessage = nullptr; + _failedMessage = nullptr; + + _language = nullptr; + _theme = nullptr; + memset(_pageIds, 0, sizeof(_pageIds)); + _hUiThread = nullptr; + _registered = FALSE; + _hWnd = nullptr; + + _state = PYBA_STATE_INITIALIZING; + _visiblePageId = 0; + _installPage = PAGE_LOADING; + _hrFinal = hrHostInitialization; + + _downgrading = FALSE; + _restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE; + _restartRequired = FALSE; + _allowRestart = FALSE; + + _suppressDowngradeFailure = FALSE; + _suppressRepair = FALSE; + + _overridableVariables = nullptr; + _taskbarList = nullptr; + _taskbarButtonCreatedMessage = UINT_MAX; + _taskbarButtonOK = FALSE; + _showingInternalUIThisPackage = FALSE; + _triedToLaunchElevated = FALSE; + + _suppressPaint = FALSE; + + pEngine->AddRef(); + _engine = pEngine; + + _hBAFModule = nullptr; + _baFunction = nullptr; + } + + + // + // Destructor - release member variables. + // + ~PythonBootstrapperApplication() { + AssertSz(!::IsWindow(_hWnd), "Window should have been destroyed before destructor."); + AssertSz(!_theme, "Theme should have been released before destructor."); + + ReleaseObject(_taskbarList); + ReleaseDict(_overridableVariables); + ReleaseStr(_failedMessage); + ReleaseStr(_confirmCloseMessage); + BalConditionsUninitialize(&_conditions); + BalInfoUninitialize(&_bundle); + LocFree(_wixLoc); + + ReleaseStr(_language); + ReleaseStr(_nextPackageAfterRestart); + ReleaseNullObject(_engine); + + if (_hBAFModule) { + ::FreeLibrary(_hBAFModule); + _hBAFModule = nullptr; + } + } + +private: + HMODULE _hModule; + BOOTSTRAPPER_COMMAND _command; + IBootstrapperEngine* _engine; + BOOTSTRAPPER_ACTION _plannedAction; + + LPWSTR _nextPackageAfterRestart; + + WIX_LOCALIZATION* _wixLoc; + BAL_INFO_BUNDLE _bundle; + BAL_CONDITIONS _conditions; + LPWSTR _failedMessage; + LPWSTR _confirmCloseMessage; + + LPWSTR _language; + THEME* _theme; + DWORD _pageIds[countof(PAGE_NAMES)]; + HANDLE _hUiThread; + BOOL _registered; + HWND _hWnd; + + PYBA_STATE _state; + HRESULT _hrFinal; + DWORD _visiblePageId; + PAGE _installPage; + + BOOL _startedExecution; + DWORD _calculatedCacheProgress; + DWORD _calculatedExecuteProgress; + + BOOL _downgrading; + BOOTSTRAPPER_APPLY_RESTART _restartResult; + BOOL _restartRequired; + BOOL _allowRestart; + + BOOL _suppressDowngradeFailure; + BOOL _suppressRepair; + + STRINGDICT_HANDLE _overridableVariables; + + ITaskbarList3* _taskbarList; + UINT _taskbarButtonCreatedMessage; + BOOL _taskbarButtonOK; + BOOL _showingInternalUIThisPackage; + BOOL _triedToLaunchElevated; + + BOOL _suppressPaint; + + HMODULE _hBAFModule; + IBootstrapperBAFunction* _baFunction; +}; + +// +// CreateBootstrapperApplication - creates a new IBootstrapperApplication object. +// +HRESULT CreateBootstrapperApplication( + __in HMODULE hModule, + __in BOOL fPrereq, + __in HRESULT hrHostInitialization, + __in IBootstrapperEngine* pEngine, + __in const BOOTSTRAPPER_COMMAND* pCommand, + __out IBootstrapperApplication** ppApplication + ) { + HRESULT hr = S_OK; + + if (fPrereq) { + hr = E_INVALIDARG; + ExitWithLastError(hr, "Failed to create UI thread."); + } + + PythonBootstrapperApplication* pApplication = nullptr; + + pApplication = new PythonBootstrapperApplication(hModule, fPrereq, hrHostInitialization, pEngine, pCommand); + ExitOnNull(pApplication, hr, E_OUTOFMEMORY, "Failed to create new standard bootstrapper application object."); + + *ppApplication = pApplication; + pApplication = nullptr; + +LExit: + ReleaseObject(pApplication); + return hr; +} diff --git a/Tools/msi/bundle/bootstrap/pch.cpp b/Tools/msi/bundle/bootstrap/pch.cpp new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/pch.cpp @@ -0,0 +1,1 @@ +#include "pch.h" diff --git a/Tools/msi/bundle/bootstrap/pch.h b/Tools/msi/bundle/bootstrap/pch.h new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/pch.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2004, Outercurve Foundation. +// This software is released under Microsoft Reciprocal License (MS-RL). +// The license and further copyright text can be found in the file +// LICENSE.TXT at the root directory of the distribution. +// +// +// +// Precompiled header for standard bootstrapper application. +// +//------------------------------------------------------------------------------------------------- + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dutil.h" +#include "memutil.h" +#include "dictutil.h" +#include "dirutil.h" +#include "fileutil.h" +#include "locutil.h" +#include "logutil.h" +#include "pathutil.h" +#include "resrutil.h" +#include "shelutil.h" +#include "strutil.h" +#include "thmutil.h" +#include "uriutil.h" +#include "xmlutil.h" + +#include "IBootstrapperEngine.h" +#include "IBootstrapperApplication.h" + +#include "BalBaseBootstrapperApplication.h" +#include "balinfo.h" +#include "balcondition.h" + +HRESULT CreateBootstrapperApplication( + __in HMODULE hModule, + __in BOOL fPrereq, + __in HRESULT hrHostInitialization, + __in IBootstrapperEngine* pEngine, + __in const BOOTSTRAPPER_COMMAND* pCommand, + __out IBootstrapperApplication** ppApplication +); + +#include "IBootstrapperBAFunction.h" + diff --git a/Tools/msi/bundle/bootstrap/pythonba.cpp b/Tools/msi/bundle/bootstrap/pythonba.cpp new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/pythonba.cpp @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2004, Outercurve Foundation. +// This software is released under Microsoft Reciprocal License (MS-RL). +// The license and further copyright text can be found in the file +// LICENSE.TXT at the root directory of the distribution. +// +// +// +// Setup chainer/bootstrapper standard UI for WiX toolset. +// +//------------------------------------------------------------------------------------------------- + +#include "pch.h" + +static HINSTANCE vhInstance = NULL; + +extern "C" BOOL WINAPI DllMain( + IN HINSTANCE hInstance, + IN DWORD dwReason, + IN LPVOID /* pvReserved */ + ) +{ + switch(dwReason) + { + case DLL_PROCESS_ATTACH: + ::DisableThreadLibraryCalls(hInstance); + vhInstance = hInstance; + break; + + case DLL_PROCESS_DETACH: + vhInstance = NULL; + break; + } + + return TRUE; +} + + +extern "C" HRESULT WINAPI BootstrapperApplicationCreate( + __in IBootstrapperEngine* pEngine, + __in const BOOTSTRAPPER_COMMAND* pCommand, + __out IBootstrapperApplication** ppApplication + ) +{ + HRESULT hr = S_OK; + + BalInitialize(pEngine); + + hr = CreateBootstrapperApplication(vhInstance, FALSE, S_OK, pEngine, pCommand, ppApplication); + BalExitOnFailure(hr, "Failed to create bootstrapper application interface."); + +LExit: + return hr; +} + + +extern "C" void WINAPI BootstrapperApplicationDestroy() +{ + BalUninitialize(); +} + + +extern "C" HRESULT WINAPI MbaPrereqBootstrapperApplicationCreate( + __in HRESULT hrHostInitialization, + __in IBootstrapperEngine* pEngine, + __in const BOOTSTRAPPER_COMMAND* pCommand, + __out IBootstrapperApplication** ppApplication + ) +{ + return E_NOTIMPL; +} + + +extern "C" void WINAPI MbaPrereqBootstrapperApplicationDestroy() +{ } diff --git a/Tools/msi/bundle/bootstrap/pythonba.def b/Tools/msi/bundle/bootstrap/pythonba.def new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/pythonba.def @@ -0,0 +1,18 @@ +;------------------------------------------------------------------------------------------------- +; +; Copyright (c) 2004, Outercurve Foundation. +; This software is released under Microsoft Reciprocal License (MS-RL). +; The license and further copyright text can be found in the file +; LICENSE.TXT at the root directory of the distribution. +; +; +; +; WiX Standard Bootstrapper Application DLL entry points. +; +;------------------------------------------------------------------------------------------------- + +EXPORTS + BootstrapperApplicationCreate + BootstrapperApplicationDestroy + MbaPrereqBootstrapperApplicationCreate + MbaPrereqBootstrapperApplicationDestroy diff --git a/Tools/msi/bundle/bootstrap/pythonba.sln b/Tools/msi/bundle/bootstrap/pythonba.sln new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/pythonba.sln @@ -0,0 +1,22 @@ +? +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythonba", "pythonba.vcxproj", "{7A09B132-B3EE-499B-A700-A4B2157FEA3D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Debug|Win32.ActiveCfg = Debug|Win32 + {7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Debug|Win32.Build.0 = Debug|Win32 + {7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Release|Win32.ActiveCfg = Release|Win32 + {7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Tools/msi/bundle/bootstrap/pythonba.vcxproj b/Tools/msi/bundle/bootstrap/pythonba.vcxproj new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/pythonba.vcxproj @@ -0,0 +1,69 @@ +? + + + + + Debug + Win32 + + + Release + Win32 + + + + Release + Win32 + v140 + v120 + {7A09B132-B3EE-499B-A700-A4B2157FEA3D} + PythonBA + + + + + DynamicLibrary + Unicode + $(ProjectDir)..\..\obj\$(Configuration)_Bootstrap\ + $(IntDir) + + + + + _CRT_STDIO_LEGACY_WIDE_SPECIFIERS=1;%(PreprocessorDefinitions) + $(WixInstallPath)sdk\inc + Use + pch.h + MultiThreaded + + + comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib;dutil.lib;balutil.lib;version.lib;uxtheme.lib;%(AdditionalDependencies) + $(WixInstallPath)sdk\vs2015\lib\x86 + $(WixInstallPath)sdk\vs2013\lib\x86 + pythonba.def + true + + + + + + + Create + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/bootstrap/resource.h b/Tools/msi/bundle/bootstrap/resource.h new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bootstrap/resource.h @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2004, Outercurve Foundation. +// This software is released under Microsoft Reciprocal License (MS-RL). +// The license and further copyright text can be found in the file +// LICENSE.TXT at the root directory of the distribution. +// +//------------------------------------------------------------------------------------------------- + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// +#define IDC_STATIC -1 + + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Tools/msi/bundle/bundle.ico b/Tools/msi/bundle/bundle.ico new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1ab629eff26946e1b8c0cd3223e80257b74deb88 GIT binary patch [stripped] diff --git a/Tools/msi/bundle/bundle.targets b/Tools/msi/bundle/bundle.targets new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bundle.targets @@ -0,0 +1,99 @@ + + + + 2.0 + Bundle + + Release + 1132;1135;1140 + $(OutputName)-$(PythonVersion) + $(OutputName)-$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber).$(RevisionNumber) + $(OutputName)-amd64 + $(OutputName)-$(OutputSuffix) + + $(OutputPath)en-us\ + $(OutputPath) + + $(DownloadUrlBase.TrimEnd(`/`))/$(PythonVersion)/$(ArchName)/{2} + $(DefineConstants);DownloadUrl=$(DownloadUrl) + $(DefineConstants);DownloadUrl={2} + + + + + WixUtilExtension + WixUtilExtension + + + WixDependencyExtension + WixDependencyExtension + + + WixBalExtension + WixBalExtension + + + + + + + + + + + + + + + + + + + + + + + BuildForRelease=$(BuildForRelease) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(DefineConstants);BootstrapApp=$(BootstrapAppPath) + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/bundle.wxs b/Tools/msi/bundle/bundle.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/bundle.wxs @@ -0,0 +1,80 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/bundle/full.wixproj b/Tools/msi/bundle/full.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/full.wixproj @@ -0,0 +1,21 @@ + + + + {3E204ADD-238D-4D10-852C-4F859325C839} + python + full + + + + + + + $(DefineConstants); + CompressMSI=yes; + CompressPDB=yes; + CompressMSI_D=yes; + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/core.wxs b/Tools/msi/bundle/packagegroups/core.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/core.wxs @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/crt.wxs b/Tools/msi/bundle/packagegroups/crt.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/crt.wxs @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/dev.wxs b/Tools/msi/bundle/packagegroups/dev.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/dev.wxs @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/doc.wxs b/Tools/msi/bundle/packagegroups/doc.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/doc.wxs @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/exe.wxs b/Tools/msi/bundle/packagegroups/exe.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/exe.wxs @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/launcher.wxs b/Tools/msi/bundle/packagegroups/launcher.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/launcher.wxs @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/lib.wxs b/Tools/msi/bundle/packagegroups/lib.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/lib.wxs @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/postinstall.wxs b/Tools/msi/bundle/packagegroups/postinstall.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/postinstall.wxs @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/tcltk.wxs b/Tools/msi/bundle/packagegroups/tcltk.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/tcltk.wxs @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/test.wxs b/Tools/msi/bundle/packagegroups/test.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/test.wxs @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/packagegroups/tools.wxs b/Tools/msi/bundle/packagegroups/tools.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/packagegroups/tools.wxs @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/postinstall_en-US.wxl_template b/Tools/msi/bundle/postinstall_en-US.wxl_template new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/postinstall_en-US.wxl_template @@ -0,0 +1,4 @@ + + + Precompiling standard library + diff --git a/Tools/msi/bundle/releaselocal.wixproj b/Tools/msi/bundle/releaselocal.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/releaselocal.wixproj @@ -0,0 +1,21 @@ + + + + {FCD43AC9-969F-49A1-8AC5-EDC27599D1EB} + python + + + + + + + + $(DefineConstants); + CompressMSI=yes; + CompressPDB=no; + CompressMSI_D=no + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/releaseweb.wixproj b/Tools/msi/bundle/releaseweb.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/releaseweb.wixproj @@ -0,0 +1,21 @@ + + + + {71CDE213-CB39-4BD9-B89D-BBB878689144} + python + webinstall + + + + + + + $(DefineConstants); + CompressMSI=no; + CompressPDB=no; + CompressMSI_D=no + + + + + \ No newline at end of file diff --git a/Tools/msi/bundle/snapshot.wixproj b/Tools/msi/bundle/snapshot.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/bundle/snapshot.wixproj @@ -0,0 +1,21 @@ + + + + {8A4A1162-4BF9-4FF6-9A98-315F01E44932} + python + + + + + + + + $(DefineConstants); + CompressMSI=no; + CompressPDB=no; + CompressMSI_D=no; + + + + + \ No newline at end of file diff --git a/Tools/msi/common.wxs b/Tools/msi/common.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/common.wxs @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + Installed OR NOT DOWNGRADE + Installed OR NOT MISSING_CORE + Installed OR TARGETDIR OR Suppress_TARGETDIR_Check + + + UPGRADE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/common_en-US.wxl_template b/Tools/msi/common_en-US.wxl_template new file mode 100644 --- /dev/null +++ b/Tools/msi/common_en-US.wxl_template @@ -0,0 +1,17 @@ + + + 1033 + en-us + Python {{ShortVersion}} + Python {{LongVersion}} ({{Bitness}}) + Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}}) + Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}}) + Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} symbols) + Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} symbols) + Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} debug) + Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} debug) + Python Software Foundation + A newer version of !(loc.ProductName) is already installed. + An incorrect version of a prerequisite package is installed. Please uninstall any other versions of !(loc.ProductName) and try installing this again. + The TARGETDIR variable must be provided when invoking this installer. + diff --git a/Tools/msi/core/core.props b/Tools/msi/core/core.props new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core.props @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/core/core.wixproj b/Tools/msi/core/core.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core.wixproj @@ -0,0 +1,11 @@ + + + + {1B4502D5-B627-4F50-ABEA-4CC5A8E88265} + 2.0 + core + Package + IncludeDefaultFeature=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/core/core.wxs b/Tools/msi/core/core.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core.wxs @@ -0,0 +1,25 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/core/core_d.wixproj b/Tools/msi/core/core_d.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core_d.wixproj @@ -0,0 +1,11 @@ + + + + {D3677DCF-098A-4398-9FA5-8E74AC37E0DF} + 2.0 + core_d + Package + IncludeDebugBinaries=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/core/core_en-US.wxl b/Tools/msi/core/core_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core_en-US.wxl @@ -0,0 +1,5 @@ +? + + Core Interpreter + core + diff --git a/Tools/msi/core/core_files.wxs b/Tools/msi/core/core_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core_files.wxs @@ -0,0 +1,31 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/core/core_pdb.wixproj b/Tools/msi/core/core_pdb.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core_pdb.wixproj @@ -0,0 +1,11 @@ + + + + {E98E7539-64E7-4DCE-AACD-01E3ADE40EFD} + 2.0 + core_pdb + Package + IncludeSymbols=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/crt/crt.wixproj b/Tools/msi/crt/crt.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/crt/crt.wixproj @@ -0,0 +1,20 @@ + + + + {91C99298-8E2E-4422-A5AF-CC4FFF9A58D3} + 2.0 + crt + Package + ICE71 + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/crt/crt.wxs b/Tools/msi/crt/crt.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/crt/crt.wxs @@ -0,0 +1,26 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/crt/crt_en-US.wxl b/Tools/msi/crt/crt_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/crt/crt_en-US.wxl @@ -0,0 +1,5 @@ +? + + C Runtime + crt + diff --git a/Tools/msi/crt/crt_files.12.0.wxs b/Tools/msi/crt/crt_files.12.0.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/crt/crt_files.12.0.wxs @@ -0,0 +1,20 @@ +? + + + + + + + + + + ALLUSERS=1 + + + + NOT ALLUSERS=1 + + + + + diff --git a/Tools/msi/crt/crt_files.14.0.wxs b/Tools/msi/crt/crt_files.14.0.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/crt/crt_files.14.0.wxs @@ -0,0 +1,40 @@ +? + + + + + + + + + + + + + + ALLUSERS=1 + + + + ALLUSERS=1 + + + + ALLUSERS=1 + + + + NOT ALLUSERS=1 + + + + NOT ALLUSERS=1 + + + + NOT ALLUSERS=1 + + + + + diff --git a/Tools/msi/crt/crtlicense.txt b/Tools/msi/crt/crtlicense.txt new file mode 100644 --- /dev/null +++ b/Tools/msi/crt/crtlicense.txt @@ -0,0 +1,47 @@ + + +Additional Conditions for this Windows binary build +--------------------------------------------------- + +This program is linked with and uses Microsoft Distributable Code, +copyrighted by Microsoft Corporation. The Microsoft Distributable Code +includes the following files: + +appcrt140.dll +desktopcrt140.dll +vcruntime140.dll +msvcp140.dll +concrt140.dll +vccorlib140.dll + +If you further distribute programs that include the Microsoft +Distributable Code, you must comply with the restrictions on +distribution specified by Microsoft. In particular, you must require +distributors and external end users to agree to terms that protect the +Microsoft Distributable Code at least as much as Microsoft's own +requirements for the Distributable Code. See Microsoft's documentation +(included in its developer tools and on its website at microsoft.com) +for specific details. + +Redistribution of the Windows binary build of the Python interpreter +complies with this agreement, provided that you do not: + +- alter any copyright, trademark or patent notice in Microsoft's +Distributable Code; + +- use Microsoft's trademarks in your programs' names or in a way that +suggests your programs come from or are endorsed by Microsoft; + +- distribute Microsoft's Distributable Code to run on a platform other +than Microsoft operating systems, run-time technologies or application +platforms; or + +- include Microsoft Distributable Code in malicious, deceptive or +unlawful programs. + +These restrictions apply only to the Microsoft Distributable Code as +defined above, not to Python itself or any programs running on the +Python interpreter. The redistribution of the Python interpreter and +libraries is governed by the Python Software License included with this +file, or by other licenses as marked. + diff --git a/Tools/msi/crtlicense.txt b/Tools/msi/crtlicense.txt deleted file mode 100644 --- a/Tools/msi/crtlicense.txt +++ /dev/null @@ -1,44 +0,0 @@ - - -Additional Conditions for this Windows binary build ---------------------------------------------------- - -This program is linked with and uses Microsoft Distributable Code, -copyrighted by Microsoft Corporation. The Microsoft Distributable Code -includes the following files: - -msvcr90.dll -msvcp90.dll -msvcm90.dll - -If you further distribute programs that include the Microsoft -Distributable Code, you must comply with the restrictions on -distribution specified by Microsoft. In particular, you must require -distributors and external end users to agree to terms that protect the -Microsoft Distributable Code at least as much as Microsoft's own -requirements for the Distributable Code. See Microsoft's documentation -(included in its developer tools and on its website at microsoft.com) -for specific details. - -Redistribution of the Windows binary build of the Python interpreter -complies with this agreement, provided that you do not: - -- alter any copyright, trademark or patent notice in Microsoft's -Distributable Code; - -- use Microsoft's trademarks in your programs' names or in a way that -suggests your programs come from or are endorsed by Microsoft; - -- distribute Microsoft's Distributable Code to run on a platform other -than Microsoft operating systems, run-time technologies or application -platforms; or - -- include Microsoft Distributable Code in malicious, deceptive or -unlawful programs. - -These restrictions apply only to the Microsoft Distributable Code as -defined above, not to Python itself or any programs running on the -Python interpreter. The redistribution of the Python interpreter and -libraries is governed by the Python Software License included with this -file, or by other licenses as marked. - diff --git a/Tools/msi/csv_to_wxs.py b/Tools/msi/csv_to_wxs.py new file mode 100644 --- /dev/null +++ b/Tools/msi/csv_to_wxs.py @@ -0,0 +1,127 @@ +''' +Processes a CSV file containing a list of files into a WXS file with +components for each listed file. + +The CSV columns are: + source of file, target for file, group name + +Usage:: + py txt_to_wxs.py [path to file list .csv] [path to destination .wxs] + +This is necessary to handle structures where some directories only +contain other directories. MSBuild is not able to generate the +Directory entries in the WXS file correctly, as it operates on files. +Python, however, can easily fill in the gap. +''' + +__author__ = "Steve Dower " + +import csv +import re +import sys + +from collections import defaultdict +from itertools import chain, zip_longest +from pathlib import PureWindowsPath +from uuid import uuid1 + +ID_CHAR_SUBS = { + '-': '_', + '+': '_P', +} + +def make_id(path): + return re.sub( + r'[^A-Za-z0-9_.]', + lambda m: ID_CHAR_SUBS.get(m.group(0), '_'), + str(path).rstrip('/\\'), + flags=re.I + ) + +DIRECTORIES = set() + +def main(file_source, install_target): + with open(file_source, 'r', newline='') as f: + files = list(csv.reader(f)) + + assert len(files) == len(set(make_id(f[1]) for f in files)), "Duplicate file IDs exist" + + directories = defaultdict(set) + cache_directories = defaultdict(set) + groups = defaultdict(list) + for source, target, group, disk_id, condition in files: + target = PureWindowsPath(target) + groups[group].append((source, target, disk_id, condition)) + + if target.suffix.lower() in {".py", ".pyw"}: + cache_directories[group].add(target.parent) + + for dirname in target.parents: + parent = make_id(dirname.parent) + if parent and parent != '.': + directories[parent].add(dirname.name) + + lines = [ + '', + ' ', + ] + for dir_parent in sorted(directories): + lines.append(' '.format(dir_parent)) + for dir_name in sorted(directories[dir_parent]): + lines.append(' '.format(dir_parent, make_id(dir_name), dir_name)) + lines.append(' ') + for dir_parent in (make_id(d) for group in cache_directories.values() for d in group): + lines.append(' '.format(dir_parent)) + lines.append(' '.format(dir_parent)) + lines.append(' ') + lines.append(' ') + + for group in sorted(groups): + lines.extend([ + ' ', + ' '.format(group), + ]) + for source, target, disk_id, condition in groups[group]: + lines.append(' '.format(make_id(target), make_id(target.parent))) + if condition: + lines.append(' {}'.format(condition)) + + if disk_id: + lines.append(' '.format(make_id(target), target.name, source, disk_id)) + else: + lines.append(' '.format(make_id(target), target.name, source)) + lines.append(' ') + + create_folders = {make_id(p) + "___pycache__" for p in cache_directories[group]} + remove_folders = {make_id(p2) for p1 in cache_directories[group] for p2 in chain((p1,), p1.parents)} + create_folders.discard(".") + remove_folders.discard(".") + if create_folders or remove_folders: + lines.append(' '.format(group, uuid1())) + lines.extend(' '.format(p) for p in create_folders) + lines.extend(' '.format(p) for p in create_folders) + lines.extend(' '.format(p) for p in create_folders | remove_folders) + lines.append(' ') + + lines.extend([ + ' ', + ' ', + ]) + lines.append('') + + # Check if the file matches. If so, we don't want to touch it so + # that we can skip rebuilding. + try: + with open(install_target, 'r') as f: + if all(x.rstrip('\r\n') == y for x, y in zip_longest(f, lines)): + print('File is up to date') + return + except IOError: + pass + + with open(install_target, 'w') as f: + f.writelines(line + '\n' for line in lines) + print('Wrote {} lines to {}'.format(len(lines), install_target)) + +if __name__ == '__main__': + main(sys.argv[1], sys.argv[2]) diff --git a/Tools/msi/dev/dev.props b/Tools/msi/dev/dev.props new file mode 100644 --- /dev/null +++ b/Tools/msi/dev/dev.props @@ -0,0 +1,42 @@ + + + + + + $(DefineConstants); + IncludeMinGWLib=1; + + + + + + + + + + + $(PySourcePath) + !(bindpath.src) + $(PySourcePath) + + dev_include + + + + + + + <_GenDefPlatform>i386 + <_GenDefPlatform Condition="$(Platform) == 'x64'">i386:x86-64 + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/dev/dev.wixproj b/Tools/msi/dev/dev.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/dev/dev.wixproj @@ -0,0 +1,11 @@ + + + + {5F23F608-D74B-4259-A0CE-8DC65CC7FE53} + 2.0 + dev + Package + IncludeDefaultFeature=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/dev/dev.wxs b/Tools/msi/dev/dev.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/dev/dev.wxs @@ -0,0 +1,25 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/dev/dev_d.wixproj b/Tools/msi/dev/dev_d.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/dev/dev_d.wixproj @@ -0,0 +1,11 @@ + + + + {C11B4945-76BD-4137-B2E3-649460117A77} + 2.0 + dev_d + Package + IncludeDebugBinaries=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/dev/dev_en-US.wxl b/Tools/msi/dev/dev_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/dev/dev_en-US.wxl @@ -0,0 +1,5 @@ +? + + Development Libraries + dev + diff --git a/Tools/msi/dev/dev_files.wxs b/Tools/msi/dev/dev_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/dev/dev_files.wxs @@ -0,0 +1,42 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/doc/doc.wixproj b/Tools/msi/doc/doc.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/doc/doc.wixproj @@ -0,0 +1,30 @@ + + + + {0D62A2BB-5F71-4447-8C8C-9708407B3674} + 2.0 + doc + Package + + ICE43 + + + + python$(MajorVersionNumber)$(MinorVersionNumber)$(MicroVersionNumber)$(ReleaseLevelName).chm + false + true + + + $(DefineConstants);DocFilename=$(DocFilename); + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/doc/doc.wxs b/Tools/msi/doc/doc.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/doc/doc.wxs @@ -0,0 +1,26 @@ +? + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/doc/doc_en-US.wxl_template b/Tools/msi/doc/doc_en-US.wxl_template new file mode 100644 --- /dev/null +++ b/Tools/msi/doc/doc_en-US.wxl_template @@ -0,0 +1,7 @@ +? + + doc + Documentation + Python {{ShortVersion}} {{Bitness}} Manuals + View the !(loc.ProductName) documentation. + diff --git a/Tools/msi/doc/doc_files.wxs b/Tools/msi/doc/doc_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/doc/doc_files.wxs @@ -0,0 +1,12 @@ +? + + + + + + + + + + + diff --git a/Tools/msi/doc/doc_no_files.wxs b/Tools/msi/doc/doc_no_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/doc/doc_no_files.wxs @@ -0,0 +1,17 @@ +? + + + + + + + + + + + diff --git a/Tools/msi/exe/crtlicense.txt b/Tools/msi/exe/crtlicense.txt new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/crtlicense.txt @@ -0,0 +1,44 @@ + + +Additional Conditions for this Windows binary build +--------------------------------------------------- + +This program is linked with and uses Microsoft Distributable Code, +copyrighted by Microsoft Corporation. The Microsoft Distributable Code +includes the following files: + +msvcr90.dll +msvcp90.dll +msvcm90.dll + +If you further distribute programs that include the Microsoft +Distributable Code, you must comply with the restrictions on +distribution specified by Microsoft. In particular, you must require +distributors and external end users to agree to terms that protect the +Microsoft Distributable Code at least as much as Microsoft's own +requirements for the Distributable Code. See Microsoft's documentation +(included in its developer tools and on its website at microsoft.com) +for specific details. + +Redistribution of the Windows binary build of the Python interpreter +complies with this agreement, provided that you do not: + +- alter any copyright, trademark or patent notice in Microsoft's +Distributable Code; + +- use Microsoft's trademarks in your programs' names or in a way that +suggests your programs come from or are endorsed by Microsoft; + +- distribute Microsoft's Distributable Code to run on a platform other +than Microsoft operating systems, run-time technologies or application +platforms; or + +- include Microsoft Distributable Code in malicious, deceptive or +unlawful programs. + +These restrictions apply only to the Microsoft Distributable Code as +defined above, not to Python itself or any programs running on the +Python interpreter. The redistribution of the Python interpreter and +libraries is governed by the Python Software License included with this +file, or by other licenses as marked. + diff --git a/Tools/msi/exe/exe.props b/Tools/msi/exe/exe.props new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe.props @@ -0,0 +1,36 @@ + + + + + ICE43 + + + + + + + + + + + + + + <_LicenseFiles Include="@(LicenseFiles)"> + $([System.IO.File]::ReadAllText(%(FullPath))) + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/exe/exe.wixproj b/Tools/msi/exe/exe.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe.wixproj @@ -0,0 +1,11 @@ + + + + {6BD53305-B03E-49DC-85FB-5551B8CCC843} + 2.0 + exe + Package + IncludeDefaultFeature=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/exe/exe.wxs b/Tools/msi/exe/exe.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe.wxs @@ -0,0 +1,40 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/exe/exe_d.wixproj b/Tools/msi/exe/exe_d.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe_d.wixproj @@ -0,0 +1,11 @@ + + + + {B1CA739C-8DB0-403B-9010-D79507507CE9} + 2.0 + exe_d + Package + IncludeDebugBinaries=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/exe/exe_en-US.wxl_template b/Tools/msi/exe/exe_en-US.wxl_template new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe_en-US.wxl_template @@ -0,0 +1,9 @@ +? + + Executables + executable + Python {{ShortVersion}} ({{Bitness}}) + Launches the !(loc.ProductName) interpreter. + Add to PATH + Adds the install directory to PATH and .py to PATHEXT. + diff --git a/Tools/msi/exe/exe_files.wxs b/Tools/msi/exe/exe_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe_files.wxs @@ -0,0 +1,68 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/exe/exe_pdb.wixproj b/Tools/msi/exe/exe_pdb.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe_pdb.wixproj @@ -0,0 +1,11 @@ + + + + {4A1F7045-8EE2-4276-ABB8-5E0C40E5F38B} + 2.0 + exe_pdb + Package + IncludeSymbols=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/get_wix.py b/Tools/msi/get_wix.py new file mode 100644 --- /dev/null +++ b/Tools/msi/get_wix.py @@ -0,0 +1,49 @@ +''' +Downloads and extracts WiX to a local directory +''' + +__author__ = 'Steve Dower ' + +import io +import os +import sys + +from pathlib import Path +from subprocess import Popen +from zipfile import ZipFile + +EXTERNALS_DIR = None +for p in Path(__file__).parents: + if any(p.glob("PCBuild/*.vcxproj")): + EXTERNALS_DIR = p / "externals" + break + +if not EXTERNALS_DIR: + print("Cannot find project root") + sys.exit(1) + +WIX_BINARIES_ZIP = 'http://wixtoolset.org/downloads/v3.10.1124.0/wix310-binaries.zip' +TARGET_BIN_ZIP = EXTERNALS_DIR / "wix.zip" +TARGET_BIN_DIR = EXTERNALS_DIR / "wix" + +POWERSHELL_COMMAND = "[IO.File]::WriteAllBytes('{}', (Invoke-WebRequest {} -UseBasicParsing).Content)" + +if __name__ == '__main__': + if TARGET_BIN_DIR.exists() and any(TARGET_BIN_DIR.glob("*")): + print('WiX is already installed') + sys.exit(0) + + try: + TARGET_BIN_DIR.mkdir() + except FileExistsError: + pass + + print('Downloading WiX to', TARGET_BIN_ZIP) + p = Popen(["powershell.exe", "-Command", POWERSHELL_COMMAND.format(TARGET_BIN_ZIP, WIX_BINARIES_ZIP)]) + p.wait() + print('Extracting WiX to', TARGET_BIN_DIR) + with ZipFile(str(TARGET_BIN_ZIP)) as z: + z.extractall(str(TARGET_BIN_DIR)) + TARGET_BIN_ZIP.unlink() + + print('Extracted WiX') diff --git a/Tools/msi/launcher/launcher.props b/Tools/msi/launcher/launcher.props new file mode 100644 --- /dev/null +++ b/Tools/msi/launcher/launcher.props @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/launcher/launcher.wixproj b/Tools/msi/launcher/launcher.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/launcher/launcher.wixproj @@ -0,0 +1,11 @@ + + + + {921CF0E6-AEBC-4376-BA1D-CD46EBFE6DA5} + 2.0 + launcher + Package + IncludeDefaultFeature=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/launcher/launcher.wxs b/Tools/msi/launcher/launcher.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/launcher/launcher.wxs @@ -0,0 +1,38 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOT Installed AND NOT ALLUSERS=1 + NOT Installed AND ALLUSERS=1 + + + diff --git a/Tools/msi/launcher/launcher_en-US.wxl b/Tools/msi/launcher/launcher_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/launcher/launcher_en-US.wxl @@ -0,0 +1,8 @@ +? + + Launcher + launcher + Python File + Python File (no console) + Compiled Python File + diff --git a/Tools/msi/launcher/launcher_files.wxs b/Tools/msi/launcher/launcher_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/launcher/launcher_files.wxs @@ -0,0 +1,35 @@ +? + + + + + + + + + + + + NOT ALLUSERS=1 + + + + + + ALLUSERS=1 + + + + + + + + + + + + + + + + diff --git a/Tools/msi/launcher/launcher_pdb.wixproj b/Tools/msi/launcher/launcher_pdb.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/launcher/launcher_pdb.wixproj @@ -0,0 +1,11 @@ + + + + {A21D4A23-483F-4822-A0B1-FCB14D8CEBA7} + 2.0 + launcher_pdb + Package + IncludeSymbols=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/launcher/launcher_reg.wxs b/Tools/msi/launcher/launcher_reg.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/launcher/launcher_reg.wxs @@ -0,0 +1,32 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/lib/lib.props b/Tools/msi/lib/lib.props new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib.props @@ -0,0 +1,27 @@ + + + + + + + + + + + + + $(PySourcePath)Lib + !(bindpath.src)Lib\ + $(PySourcePath)Lib + Lib\ + lib_py + + + + + \ No newline at end of file diff --git a/Tools/msi/lib/lib.wixproj b/Tools/msi/lib/lib.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib.wixproj @@ -0,0 +1,11 @@ + + + + {11367E76-3337-4602-8F1E-77DB4F370D7E} + 2.0 + lib + Package + IncludeDefaultFeature=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/lib/lib.wxs b/Tools/msi/lib/lib.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib.wxs @@ -0,0 +1,28 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/lib/lib_d.wixproj b/Tools/msi/lib/lib_d.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib_d.wixproj @@ -0,0 +1,11 @@ + + + + {6C443CD3-8258-4335-BA03-49DA9C34CE4D} + 2.0 + lib_d + Package + IncludeDebugBinaries=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/lib/lib_en-US.wxl b/Tools/msi/lib/lib_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib_en-US.wxl @@ -0,0 +1,5 @@ +? + + Standard Library + lib + diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib_files.wxs @@ -0,0 +1,72 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + SYMBOLS=1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/lib/lib_pdb.wixproj b/Tools/msi/lib/lib_pdb.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib_pdb.wixproj @@ -0,0 +1,11 @@ + + + + {5E0BCE93-D1AC-4591-BBCB-3A2BE5A4B3D1} + 2.0 + lib_pdb + Package + IncludeSymbols=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props new file mode 100644 --- /dev/null +++ b/Tools/msi/msi.props @@ -0,0 +1,161 @@ + + + + false + false + $(SuppressIces);ICE03;ICE57;ICE61 + 1026 + false + true + Release + x86 + perUser + + $(ComputerName) + $(ReleaseUri)/ + + + + + + + + + + WixUtilExtension + WixUtilExtension + + + + + $(MSBuildThisFileDirectory)\obj\$(Configuration)_$(Platform)\$(OutputName) + $(IntermediateOutputPath)_$(OutputSuffix) + $(BuildPath) + $(OutputPath)\ + $(OutputPath) + true + $(CommonProgramFiles)\Merge Modules\Microsoft_VC120_CRT_$(Platform).msm + $(CommonProgramFiles)\Merge Modules\Microsoft_VC140_CRT_$(Platform).msm + $([System.IO.Path]::GetFullPath(`$(VS120COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC120.CRT`)) + $([System.IO.Path]::GetFullPath(`$(VS140COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC140.CRT`)) + + + $(ReleaseLevelNumber) + $([System.Math]::Floor($([System.DateTime]::Now.Subtract($([System.DateTime]::new(2001, 1, 1))).TotalDays))) + + + + 32-bit + 64-bit + + $(DefineConstants); + Version=$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber).$(RevisionNumber); + ShortVersion=$(MajorVersionNumber).$(MinorVersionNumber); + LongVersion=$(PythonVersion); + MajorVersionNumber=$(MajorVersionNumber); + MinorVersionNumber=$(MinorVersionNumber); + UpgradeMinimumVersion=$(MajorVersionNumber).$(MinorVersionNumber).0.0; + UpgradeMaximumVersion=$(MajorVersionNumber).$(MinorVersionNumber).150.0; + NextMajorVersionNumber=$(MajorVersionNumber).$([msbuild]::Add($(MinorVersionNumber), 1)).0.0; + PyDebugExt=$(PyDebugExt); + + + $(DefineConstants);CRTModule=$(CRTModule); + + + $(DefineConstants);CRTRedist=$(CRTRedist); + + + $(DefineConstants);TestPrefix=;FileExtension=py; + + + $(DefineConstants);TestPrefix=x;FileExtension=px; + + + $(DefineConstants);Suffix32=-32; + + + $(DefineConstants);Suffix32=; + + + + + + generated_filelist + + + + + false + + + + + + + + src + + + tcltk + + + crt + + + + + + + + + <_Uuid Include="CoreUpgradeCode"> + upgradecode + + <_Uuid Include="UpgradeCode"> + upgradecode/$(OutputName) + + <_Uuid Include="InstallDirectoryGuidSeed"> + installdirectoryseed + + <_Uuid Include="PythonExeComponentGuid"> + python.exe + + <_Uuid Include="PythonwExeComponentGuid"> + pythonw.exe + + <_Uuid Include="RemoveLib2to3PickleComponentGuid"> + lib2to3/pickles + + + + + <_Uuids>@(_Uuid->'("%(Identity)", "%(Uri)")',',') + <_GenerateCommand>import uuid; print('\n'.join('{}={}'.format(i, uuid.uuid5(uuid.UUID('c8d9733e-a70c-43ff-ab0c-e26456f11083'), '$(ReleaseUri)' + j)) for i,j in [$(_Uuids.Replace(`"`,`'`))])) + + + + + + + + + + $(DefineConstants);@(_UuidValue,';'); + + + \ No newline at end of file diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py deleted file mode 100644 --- a/Tools/msi/msi.py +++ /dev/null @@ -1,1454 +0,0 @@ -# Python MSI Generator -# (C) 2003 Martin v. Loewis -# See "FOO" in comments refers to MSDN sections with the title FOO. -import msilib, schema, sequence, os, glob, time, re, shutil, zipfile -import subprocess, tempfile -from msilib import Feature, CAB, Directory, Dialog, Binary, add_data -import uisample -from win32com.client import constants -from distutils.spawn import find_executable - -# Settings can be overridden in config.py below -# 0 for official python.org releases -# 1 for intermediate releases by anybody, with -# a new product code for every package. -snapshot = 1 -# 1 means that file extension is px, not py, -# and binaries start with x -testpackage = 0 -# Location of build tree -srcdir = os.path.abspath("../..") -# Text to be displayed as the version in dialogs etc. -# goes into file name and ProductCode. Defaults to -# current_version.day for Snapshot, current_version otherwise -full_current_version = None -# Is Tcl available at all? -have_tcl = True -# path to PCbuild directory -PCBUILD="PCbuild" -# msvcrt version -MSVCR = "100" -# Name of certificate in default store to sign MSI with -certname = None -# Make a zip file containing the PDB files for this build? -pdbzip = True - -try: - from config import * -except ImportError: - pass - -# Extract current version from Include/patchlevel.h -lines = open(srcdir + "/Include/patchlevel.h").readlines() -major = minor = micro = level = serial = None -levels = { - 'PY_RELEASE_LEVEL_ALPHA':0xA, - 'PY_RELEASE_LEVEL_BETA': 0xB, - 'PY_RELEASE_LEVEL_GAMMA':0xC, - 'PY_RELEASE_LEVEL_FINAL':0xF - } -for l in lines: - if not l.startswith("#define"): - continue - l = l.split() - if len(l) != 3: - continue - _, name, value = l - if name == 'PY_MAJOR_VERSION': major = value - if name == 'PY_MINOR_VERSION': minor = value - if name == 'PY_MICRO_VERSION': micro = value - if name == 'PY_RELEASE_LEVEL': level = levels[value] - if name == 'PY_RELEASE_SERIAL': serial = value - -short_version = major+"."+minor -# See PC/make_versioninfo.c -FIELD3 = 1000*int(micro) + 10*level + int(serial) -current_version = "%s.%d" % (short_version, FIELD3) - -# This should never change. The UpgradeCode of this package can be -# used in the Upgrade table of future packages to make the future -# package replace this one. See "UpgradeCode Property". -# upgrade_code gets set to upgrade_code_64 when we have determined -# that the target is Win64. -upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}' -upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}' -upgrade_code_64='{6A965A0C-6EE6-4E3A-9983-3263F56311EC}' - -if snapshot: - current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24)) - -if full_current_version is None: - full_current_version = current_version - -extensions = [ - 'pyexpat.pyd', - 'select.pyd', - 'unicodedata.pyd', - 'winsound.pyd', - '_bz2.pyd', - '_elementtree.pyd', - '_socket.pyd', - '_ssl.pyd', - '_testcapi.pyd', - '_tkinter.pyd', - '_msi.pyd', - '_ctypes.pyd', - '_ctypes_test.pyd', - '_sqlite3.pyd', - '_hashlib.pyd', - '_multiprocessing.pyd', - '_lzma.pyd', - '_decimal.pyd', - '_testbuffer.pyd', - '_testimportmultiple.pyd', - '_overlapped.pyd', -] - -# Well-known component UUIDs -# These are needed for SharedDLLs reference counter; if -# a different UUID was used for each incarnation of, say, -# python24.dll, an upgrade would set the reference counter -# from 1 to 2 (due to what I consider a bug in MSI) -# Using the same UUID is fine since these files are versioned, -# so Installer will always keep the newest version. -# NOTE: All uuids are self generated. -pythondll_uuid = { - "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}", - "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}", - "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}", - "27":"{4fe21c76-1760-437b-a2f2-99909130a175}", - "30":"{6953bc3b-6768-4291-8410-7914ce6e2ca8}", - "31":"{4afcba0b-13e4-47c3-bebe-477428b46913}", - "32":"{3ff95315-1096-4d31-bd86-601d5438ad5e}", - "33":"{f7581ca4-d368-4eea-8f82-d48c64c4f047}", - "34":"{7A0C5812-2583-40D9-BCBB-CD7485F11377}", - } [major+minor] - -# Compute the name that Sphinx gives to the docfile -docfile = micro -if level < 0xf: - if level == 0xC: - docfile += "rc%s" % (serial,) - else: - docfile += '%x%s' % (level, serial) -docfile = 'python%s%s%s.chm' % (major, minor, docfile) - -# Build the mingw import library, libpythonXY.a -# This requires 'nm' and 'dlltool' executables on your PATH -def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib): - warning = "WARNING: %s - libpythonXX.a not built" - nm = find_executable('nm') - dlltool = find_executable('dlltool') - - if not nm or not dlltool: - print(warning % "nm and/or dlltool were not found") - return False - - nm_command = '%s -Cs %s' % (nm, lib_file) - dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \ - (dlltool, dll_file, def_file, mingw_lib) - export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match - - f = open(def_file,'w') - f.write("LIBRARY %s\n" % dll_file) - f.write("EXPORTS\n") - - nm_pipe = os.popen(nm_command) - for line in nm_pipe.readlines(): - m = export_match(line) - if m: - f.write(m.group(1)+"\n") - f.close() - exit = nm_pipe.close() - - if exit: - print(warning % "nm did not run successfully") - return False - - if os.system(dlltool_command) != 0: - print(warning % "dlltool did not run successfully") - return False - - return True - -# Target files (.def and .a) go in PCBuild directory -lib_file = os.path.join(srcdir, PCBUILD, "python%s%s.lib" % (major, minor)) -def_file = os.path.join(srcdir, PCBUILD, "python%s%s.def" % (major, minor)) -dll_file = "python%s%s.dll" % (major, minor) -mingw_lib = os.path.join(srcdir, PCBUILD, "libpython%s%s.a" % (major, minor)) - -have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib) - -# Determine the target architecture -if os.system("nmake /nologo /c /f msisupport.mak") != 0: - raise RuntimeError("'nmake /f msisupport.mak' failed") -dll_path = os.path.join(srcdir, PCBUILD, dll_file) -msilib.set_arch_from_file(dll_path) -if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"): - raise SystemError("msisupport.dll for incorrect architecture") - -if msilib.Win64: - upgrade_code = upgrade_code_64 - -if snapshot: - product_code = msilib.gen_uuid() -else: - # official release: generate UUID from the download link that the file will have - import uuid - product_code = uuid.uuid3(uuid.NAMESPACE_URL, - 'http://www.python.org/ftp/python/%s.%s.%s/python-%s%s.msi' % - (major, minor, micro, full_current_version, msilib.arch_ext)) - product_code = '{%s}' % product_code - -if testpackage: - ext = 'px' - testprefix = 'x' -else: - ext = 'py' - testprefix = '' - -if msilib.Win64: - SystemFolderName = "[System64Folder]" - registry_component = 4|256 -else: - SystemFolderName = "[SystemFolder]" - registry_component = 4 - -msilib.reset() - -# condition in which to install pythonxy.dll in system32: -# a) it is Windows 9x or -# b) it is NT, the user is privileged, and has chosen per-machine installation -sys32cond = "(Windows9x or (Privileged and ALLUSERS))" - -def build_database(): - """Generate an empty database, with just the schema and the - Summary information stream.""" - if snapshot: - uc = upgrade_code_snapshot - else: - uc = upgrade_code - if msilib.Win64: - productsuffix = " (64-bit)" - else: - productsuffix = "" - # schema represents the installer 2.0 database schema. - # sequence is the set of standard sequences - # (ui/execute, admin/advt/install) - msiname = "python-%s%s.msi" % (full_current_version, msilib.arch_ext) - db = msilib.init_database(msiname, - schema, ProductName="Python "+full_current_version+productsuffix, - ProductCode=product_code, - ProductVersion=current_version, - Manufacturer=u"Python Software Foundation", - request_uac = True) - # The default sequencing of the RemoveExistingProducts action causes - # removal of files that got just installed. Place it after - # InstallInitialize, so we first uninstall everything, but still roll - # back in case the installation is interrupted - msilib.change_sequence(sequence.InstallExecuteSequence, - "RemoveExistingProducts", 1510) - msilib.add_tables(db, sequence) - # We cannot set ALLUSERS in the property table, as this cannot be - # reset if the user choses a per-user installation. Instead, we - # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages - # this property, and when the execution starts, ALLUSERS is set - # accordingly. - add_data(db, "Property", [("UpgradeCode", uc), - ("WhichUsers", "ALL"), - ("ProductLine", "Python%s%s" % (major, minor)), - ]) - db.Commit() - return db, msiname - -def remove_old_versions(db): - "Fill the upgrade table." - start = "%s.%s.0" % (major, minor) - # This requests that feature selection states of an older - # installation should be forwarded into this one. Upgrading - # requires that both the old and the new installation are - # either both per-machine or per-user. - migrate_features = 1 - # See "Upgrade Table". We remove releases with the same major and - # minor version. For an snapshot, we remove all earlier snapshots. For - # a release, we remove all snapshots, and all earlier releases. - if snapshot: - add_data(db, "Upgrade", - [(upgrade_code_snapshot, start, - current_version, - None, # Ignore language - migrate_features, - None, # Migrate ALL features - "REMOVEOLDSNAPSHOT")]) - props = "REMOVEOLDSNAPSHOT" - else: - add_data(db, "Upgrade", - [(upgrade_code, start, current_version, - None, migrate_features, None, "REMOVEOLDVERSION"), - (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1), - None, migrate_features, None, "REMOVEOLDSNAPSHOT")]) - props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION" - - props += ";TARGETDIR;DLLDIR;LAUNCHERDIR" - # Installer collects the product codes of the earlier releases in - # these properties. In order to allow modification of the properties, - # they must be declared as secure. See "SecureCustomProperties Property" - add_data(db, "Property", [("SecureCustomProperties", props)]) - -class PyDialog(Dialog): - """Dialog class with a fixed layout: controls at the top, then a ruler, - then a list of buttons: back, next, cancel. Optionally a bitmap at the - left.""" - def __init__(self, *args, **kw): - """Dialog(database, name, x, y, w, h, attributes, title, first, - default, cancel, bitmap=true)""" - Dialog.__init__(self, *args) - ruler = self.h - 36 - bmwidth = 152*ruler/328 - if kw.get("bitmap", True): - self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") - self.line("BottomLine", 0, ruler, self.w, 0) - - def title(self, title): - "Set the title text of the dialog at the top." - # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, - # text, in VerdanaBold10 - self.text("Title", 135, 10, 220, 60, 0x30003, - r"{\VerdanaBold10}%s" % title) - - def back(self, title, next, name = "Back", active = 1): - """Add a back button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) - - def cancel(self, title, next, name = "Cancel", active = 1): - """Add a cancel button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) - - def next(self, title, next, name = "Next", active = 1): - """Add a Next button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) - - def xbutton(self, name, title, next, xpos): - """Add a button with a given title, the tab-next button, - its name in the Control table, giving its x position; the - y-position is aligned with the other buttons. - - Return the button, so that events can be associated""" - return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) - -def add_ui(db): - x = y = 50 - w = 370 - h = 300 - title = "[ProductName] Setup" - - # see "Dialog Style Bits" - modal = 3 # visible | modal - modeless = 1 # visible - track_disk_space = 32 - - add_data(db, 'ActionText', uisample.ActionText) - add_data(db, 'UIText', uisample.UIText) - - # Bitmaps - if not os.path.exists(srcdir+r"\PC\python_icon.exe"): - raise RuntimeError("Run icons.mak in PC directory") - add_data(db, "Binary", - [("PythonWin", msilib.Binary(r"%s\PCbuild\installer.bmp" % srcdir)), # 152x328 pixels - ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")), - ]) - add_data(db, "Icon", - [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))]) - - # Scripts - # CheckDir sets TargetExists if TARGETDIR exists. - # UpdateEditIDLE sets the REGISTRY.tcl component into - # the installed/uninstalled state according to both the - # Extensions and TclTk features. - add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))]) - # See "Custom Action Type 1" - if msilib.Win64: - CheckDir = "CheckDir" - UpdateEditIDLE = "UpdateEditIDLE" - else: - CheckDir = "_CheckDir at 4" - UpdateEditIDLE = "_UpdateEditIDLE at 4" - add_data(db, "CustomAction", - [("CheckDir", 1, "Script", CheckDir)]) - if have_tcl: - add_data(db, "CustomAction", - [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)]) - - # UI customization properties - add_data(db, "Property", - # See "DefaultUIFont Property" - [("DefaultUIFont", "DlgFont8"), - # See "ErrorDialog Style Bit" - ("ErrorDialog", "ErrorDlg"), - ("Progress1", "Install"), # modified in maintenance type dlg - ("Progress2", "installs"), - ("MaintenanceForm_Action", "Repair")]) - - # Fonts, see "TextStyle Table" - add_data(db, "TextStyle", - [("DlgFont8", "Tahoma", 9, None, 0), - ("DlgFontBold8", "Tahoma", 8, None, 1), #bold - ("VerdanaBold10", "Verdana", 10, None, 1), - ("VerdanaRed9", "Verdana", 9, 255, 0), - ]) - - compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TARGETDIR]Lib"' - lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"' - updatepipargs = r'-m ensurepip -U --default-pip' - removepipargs = r'-B -m ensurepip._uninstall' - # See "CustomAction Table" - add_data(db, "CustomAction", [ - # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty - # See "Custom Action Type 51", - # "Custom Action Execution Scheduling Options" - ("InitialTargetDir", 307, "TARGETDIR", - "[WindowsVolume]Python%s%s" % (major, minor)), - ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"), - ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName), - ("SetLauncherDirToTarget", 307, "LAUNCHERDIR", "[TARGETDIR]"), - ("SetLauncherDirToWindows", 307, "LAUNCHERDIR", "[WindowsFolder]"), - # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile - # See "Custom Action Type 18" - # msidbCustomActionTypeInScript (1024); run during actual installation - # msidbCustomActionTypeNoImpersonate (2048); run action in system account, not user account - ("CompilePyc", 18+1024+2048, "python.exe", compileargs), - ("CompilePyo", 18+1024+2048, "python.exe", "-O "+compileargs), - ("CompileGrammar", 18+1024+2048, "python.exe", lib2to3args), - ("UpdatePip", 18+1024+2048, "python.exe", updatepipargs), - ("RemovePip", 18+1024+2048, "python.exe", removepipargs), - ]) - - # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" - # Numbers indicate sequence; see sequence.py for how these action integrate - add_data(db, "InstallUISequence", - [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), - ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), - ("InitialTargetDir", 'TARGETDIR=""', 750), - # In the user interface, assume all-users installation if privileged. - ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), - ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), - ("SetLauncherDirToWindows", 'LAUNCHERDIR="" and ' + sys32cond, 753), - ("SetLauncherDirToTarget", 'LAUNCHERDIR="" and not ' + sys32cond, 754), - ("SelectDirectoryDlg", "Not Installed", 1230), - # XXX no support for resume installations yet - #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), - ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), - ("ProgressDlg", None, 1280)]) - add_data(db, "AdminUISequence", - [("InitialTargetDir", 'TARGETDIR=""', 750), - ("SetDLLDirToTarget", 'DLLDIR=""', 751), - ("SetLauncherDirToTarget", 'LAUNCHERDIR=""', 752), - ]) - - # Prepend TARGETDIR to the system path, and remove it on uninstall. - add_data(db, "Environment", - [("PathAddition", "=-*Path", "[TARGETDIR];[TARGETDIR]Scripts;[~]", "REGISTRY.path")]) - - # Execute Sequences - add_data(db, "InstallExecuteSequence", - [("InitialTargetDir", 'TARGETDIR=""', 750), - ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), - ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), - ("SetLauncherDirToWindows", 'LAUNCHERDIR="" and ' + sys32cond, 753), - ("SetLauncherDirToTarget", 'LAUNCHERDIR="" and not ' + sys32cond, 754), - ("UpdateEditIDLE", None, 1050), - # run command if install state of pip changes to INSTALLSTATE_LOCAL - # run after InstallFiles - ("UpdatePip", "&pip_feature=3", 4001), - # remove pip when state changes to INSTALLSTATE_ABSENT - # run before RemoveFiles - ("RemovePip", "&pip_feature=2", 3499), - ("CompilePyc", "COMPILEALL", 4002), - ("CompilePyo", "COMPILEALL", 4003), - ("CompileGrammar", "COMPILEALL", 4004), - ]) - add_data(db, "AdminExecuteSequence", - [("InitialTargetDir", 'TARGETDIR=""', 750), - ("SetDLLDirToTarget", 'DLLDIR=""', 751), - ("SetLauncherDirToTarget", 'LAUNCHERDIR=""', 752), - ]) - - ##################################################################### - # Standard dialogs: FatalError, UserExit, ExitDialog - fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - fatal.title("[ProductName] Installer ended prematurely") - fatal.back("< Back", "Finish", active = 0) - fatal.cancel("Cancel", "Back", active = 0) - fatal.text("Description1", 135, 70, 220, 80, 0x30003, - "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.") - fatal.text("Description2", 135, 155, 220, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c=fatal.next("Finish", "Cancel", name="Finish") - # See "ControlEvent Table". Parameters are the event, the parameter - # to the action, and optionally the condition for the event, and the order - # of events. - c.event("EndDialog", "Exit") - - user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - user_exit.title("[ProductName] Installer was interrupted") - user_exit.back("< Back", "Finish", active = 0) - user_exit.cancel("Cancel", "Back", active = 0) - user_exit.text("Description1", 135, 70, 220, 80, 0x30003, - "[ProductName] setup was interrupted. Your system has not been modified. " - "To install this program at a later time, please run the installation again.") - user_exit.text("Description2", 135, 155, 220, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c = user_exit.next("Finish", "Cancel", name="Finish") - c.event("EndDialog", "Exit") - - exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - exit_dialog.title("Complete the [ProductName] Installer") - exit_dialog.back("< Back", "Finish", active = 0) - exit_dialog.cancel("Cancel", "Back", active = 0) - exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003, - "Special Windows thanks to:\n" - " Mark Hammond, without whose years of freely \n" - " shared Windows expertise, Python for Windows \n" - " would still be Python for DOS.") - - c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003, - "{\\VerdanaRed9}Warning: Python 2.5.x is the last " - "Python release for Windows 9x.") - c.condition("Hide", "NOT Version9X") - - exit_dialog.text("Description", 135, 235, 220, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c = exit_dialog.next("Finish", "Cancel", name="Finish") - c.event("EndDialog", "Return") - - ##################################################################### - # Required dialog: FilesInUse, ErrorDlg - inuse = PyDialog(db, "FilesInUse", - x, y, w, h, - 19, # KeepModeless|Modal|Visible - title, - "Retry", "Retry", "Retry", bitmap=False) - inuse.text("Title", 15, 6, 200, 15, 0x30003, - r"{\DlgFontBold8}Files in Use") - inuse.text("Description", 20, 23, 280, 20, 0x30003, - "Some files that need to be updated are currently in use.") - inuse.text("Text", 20, 55, 330, 50, 3, - "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.") - inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", - None, None, None) - c=inuse.back("Exit", "Ignore", name="Exit") - c.event("EndDialog", "Exit") - c=inuse.next("Ignore", "Retry", name="Ignore") - c.event("EndDialog", "Ignore") - c=inuse.cancel("Retry", "Exit", name="Retry") - c.event("EndDialog","Retry") - - - # See "Error Dialog". See "ICE20" for the required names of the controls. - error = Dialog(db, "ErrorDlg", - 50, 10, 330, 101, - 65543, # Error|Minimize|Modal|Visible - title, - "ErrorText", None, None) - error.text("ErrorText", 50,9,280,48,3, "") - error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) - error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") - error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") - error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") - error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") - error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") - error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") - error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") - - ##################################################################### - # Global "Query Cancel" dialog - cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, - "No", "No", "No") - cancel.text("Text", 48, 15, 194, 30, 3, - "Are you sure you want to cancel [ProductName] installation?") - cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, - "py.ico", None, None) - c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") - c.event("EndDialog", "Exit") - - c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") - c.event("EndDialog", "Return") - - ##################################################################### - # Global "Wait for costing" dialog - costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, - "Return", "Return", "Return") - costing.text("Text", 48, 15, 194, 30, 3, - "Please wait while the installer finishes determining your disk space requirements.") - costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, - "py.ico", None, None) - c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) - c.event("EndDialog", "Exit") - - ##################################################################### - # Preparation dialog: no user input except cancellation - prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel") - prep.text("Description", 135, 70, 220, 40, 0x30003, - "Please wait while the Installer prepares to guide you through the installation.") - prep.title("Welcome to the [ProductName] Installer") - c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...") - c.mapping("ActionText", "Text") - c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None) - c.mapping("ActionData", "Text") - prep.back("Back", None, active=0) - prep.next("Next", None, active=0) - c=prep.cancel("Cancel", None) - c.event("SpawnDialog", "CancelDlg") - - ##################################################################### - # Target directory selection - seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") - seldlg.title("Select Destination Directory") - c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003, - "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.") - c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""') - seldlg.text("Description", 135, 50, 220, 40, 0x30003, - "Please select a directory for the [ProductName] files.") - - seldlg.back("< Back", None, active=0) - c = seldlg.next("Next >", "Cancel") - c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1) - # If the target exists, but we found that we are going to remove old versions, don't bother - # confirming that the target directory exists. Strictly speaking, we should determine that - # the target directory is indeed the target of the product that we are going to remove, but - # I don't know how to do that. - c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2) - c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3) - c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4) - c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5) - - c = seldlg.cancel("Cancel", "DirectoryCombo") - c.event("SpawnDialog", "CancelDlg") - - seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219, - "TARGETDIR", None, "DirectoryList", None) - seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR", - None, "PathEdit", None) - seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None) - c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None) - c.event("DirectoryListUp", "0") - c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None) - c.event("DirectoryListNew", "0") - - ##################################################################### - # SelectFeaturesDlg - features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space, - title, "Tree", "Next", "Cancel") - features.title("Customize [ProductName]") - features.text("Description", 135, 35, 220, 15, 0x30003, - "Select the way you want features to be installed.") - features.text("Text", 135,45,220,30, 3, - "Click on the icons in the tree below to change the way features will be installed.") - - c=features.back("< Back", "Next") - c.event("NewDialog", "SelectDirectoryDlg") - - c=features.next("Next >", "Cancel") - c.mapping("SelectionNoItems", "Enabled") - c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1) - c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2) - - c=features.cancel("Cancel", "Tree") - c.event("SpawnDialog", "CancelDlg") - - # The browse property is not used, since we have only a single target path (selected already) - features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty", - "Tree of selections", "Back", None) - - #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost") - #c.mapping("SelectionNoItems", "Enabled") - #c.event("Reset", "0") - - features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None) - - c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10) - c.mapping("SelectionNoItems","Enabled") - c.event("SpawnDialog", "DiskCostDlg") - - c=features.xbutton("Advanced", "Advanced", None, 0.30) - c.event("SpawnDialog", "AdvancedDlg") - - c=features.text("ItemDescription", 140, 180, 210, 40, 3, - "Multiline description of the currently selected item.") - c.mapping("SelectionDescription","Text") - - c=features.text("ItemSize", 140, 225, 210, 33, 3, - "The size of the currently selected item.") - c.mapping("SelectionSize", "Text") - - ##################################################################### - # Disk cost - cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, - "OK", "OK", "OK", bitmap=False) - cost.text("Title", 15, 6, 200, 15, 0x30003, - "{\DlgFontBold8}Disk Space Requirements") - cost.text("Description", 20, 20, 280, 20, 0x30003, - "The disk space required for the installation of the selected features.") - cost.text("Text", 20, 53, 330, 60, 3, - "The highlighted volumes (if any) do not have enough disk space " - "available for the currently selected features. You can either " - "remove some files from the highlighted volumes, or choose to " - "install less features onto local drive(s), or select different " - "destination drive(s).") - cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, - None, "{120}{70}{70}{70}{70}", None, None) - cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") - - ##################################################################### - # WhichUsers Dialog. Only available on NT, and for privileged users. - # This must be run before FindRelatedProducts, because that will - # take into account whether the previous installation was per-user - # or per-machine. We currently don't support going back to this - # dialog after "Next" was selected; to support this, we would need to - # find how to reset the ALLUSERS property, and how to re-run - # FindRelatedProducts. - # On Windows9x, the ALLUSERS property is ignored on the command line - # and in the Property table, but installer fails according to the documentation - # if a dialog attempts to set ALLUSERS. - whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, - "AdminInstall", "Next", "Cancel") - whichusers.title("Select whether to install [ProductName] for all users of this computer.") - # A radio group with two options: allusers, justme - g = whichusers.radiogroup("AdminInstall", 135, 60, 235, 80, 3, - "WhichUsers", "", "Next") - g.condition("Disable", "VersionNT=600") # Not available on Vista and Windows 2008 - g.add("ALL", 0, 5, 150, 20, "Install for all users") - g.add("JUSTME", 0, 25, 235, 20, "Install just for me (not available on Windows Vista)") - - whichusers.back("Back", None, active=0) - - c = whichusers.next("Next >", "Cancel") - c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) - c.event("EndDialog", "Return", order = 2) - - c = whichusers.cancel("Cancel", "AdminInstall") - c.event("SpawnDialog", "CancelDlg") - - ##################################################################### - # Advanced Dialog. - advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title, - "CompilePyc", "Ok", "Ok") - advanced.title("Advanced Options for [ProductName]") - - # A checkbox whether to build pyc files - advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3, - "COMPILEALL", "Compile .py files to byte code after installation", "Ok") - - c = advanced.cancel("Ok", "CompilePyc", name="Ok") # Button just has location of cancel button. - c.event("EndDialog", "Return") - - ##################################################################### - # Existing Directory dialog - dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title, - "No", "No", "No") - dlg.text("Title", 10, 20, 180, 40, 3, - "[TARGETDIR] exists. Are you sure you want to overwrite existing files?") - c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No") - c.event("[TargetExists]", "0", order=1) - c.event("[TargetExistsOk]", "1", order=2) - c.event("EndDialog", "Return", order=3) - c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes") - c.event("EndDialog", "Return") - - ##################################################################### - # Installation Progress dialog (modeless) - progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel", bitmap=False) - progress.text("Title", 20, 15, 200, 15, 0x30003, - "{\DlgFontBold8}[Progress1] [ProductName]") - progress.text("Text", 35, 65, 300, 30, 3, - "Please wait while the Installer [Progress2] [ProductName]. " - "This may take several minutes.") - progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") - - c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") - c.mapping("ActionText", "Text") - - #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) - #c.mapping("ActionData", "Text") - - c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, - None, "Progress done", None, None) - c.mapping("SetProgress", "Progress") - - progress.back("< Back", "Next", active=False) - progress.next("Next >", "Cancel", active=False) - progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg") - - # Maintenance type: repair/uninstall - maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") - maint.title("Welcome to the [ProductName] Setup Wizard") - maint.text("BodyText", 135, 63, 230, 42, 3, - "Select whether you want to repair or remove [ProductName].") - g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3, - "MaintenanceForm_Action", "", "Next") - g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") - g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") - g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") - - maint.back("< Back", None, active=False) - c=maint.next("Finish", "Cancel") - # Change installation: Change progress dialog to "Change", then ask - # for feature selection - c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) - c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) - - # Reinstall: Change progress dialog to "Repair", then invoke reinstall - # Also set list of reinstalled features to "ALL" - c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5) - c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6) - c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7) - c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8) - - # Uninstall: Change progress to "Remove", then invoke uninstall - # Also set list of removed features to "ALL" - c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11) - c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12) - c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13) - c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14) - - # Close dialog when maintenance action scheduled - c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) - c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) - - maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") - - -# See "Feature Table". The feature level is 1 for all features, -# and the feature attributes are 0 for the DefaultFeature, and -# FollowParent for all other features. The numbers are the Display -# column. -def add_features(db): - # feature attributes: - # msidbFeatureAttributesFollowParent == 2 - # msidbFeatureAttributesDisallowAdvertise == 8 - # Features that need to be installed with together with the main feature - # (i.e. additional Python libraries) need to follow the parent feature. - # Features that have no advertisement trigger (e.g. the test suite) - # must not support advertisement - global default_feature, tcltk, htmlfiles, tools, testsuite - global ext_feature, private_crt, prepend_path, pip_feature - default_feature = Feature(db, "DefaultFeature", "Python", - "Python Interpreter and Libraries", - 1, directory = "TARGETDIR") - shared_crt = Feature(db, "SharedCRT", "MSVCRT", "C Run-Time (system-wide)", 0, - level=0) - private_crt = Feature(db, "PrivateCRT", "MSVCRT", "C Run-Time (private)", 0, - level=0) - add_data(db, "Condition", [("SharedCRT", 1, sys32cond), - ("PrivateCRT", 1, "not "+sys32cond)]) - # We don't support advertisement of extensions - ext_feature = Feature(db, "Extensions", "Register Extensions", - "Make this Python installation the default Python installation", 3, - parent = default_feature, attributes=2|8) - if have_tcl: - tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5, - parent = default_feature, attributes=2) - htmlfiles = Feature(db, "Documentation", "Documentation", - "Python HTMLHelp File", 7, parent = default_feature) - tools = Feature(db, "Tools", "Utility Scripts", - "Python utility scripts (Tools/)", 9, - parent = default_feature, attributes=2) - # pip installation isn't enabled by default until a clean uninstall procedure - # becomes possible - pip_feature = Feature(db, "pip_feature", "pip", - "Install (or upgrade from an earlier version) pip, " - "a tool for installing and managing Python packages.", 11, - parent = default_feature, attributes=2|8) - testsuite = Feature(db, "Testsuite", "Test suite", - "Python test suite (Lib/test/)", 13, - parent = default_feature, attributes=2|8) - # prepend_path is an additional feature which is to be off by default. - # Since the default level for the above features is 1, this needs to be - # at least level higher. - prepend_path = Feature(db, "PrependPath", "Add python.exe to Path", - "Prepend [TARGETDIR] to the system Path variable. " - "This allows you to type 'python' into a command " - "prompt without needing the full path.", 15, - parent = default_feature, attributes=2|8, - level=2) - -def extract_msvcr100(): - # Find the redistributable files - if msilib.Win64: - arch = "x64" - else: - arch = "x86" - dir = os.path.join(os.environ['VS100COMNTOOLS'], r"..\..\VC\redist\%s\Microsoft.VC100.CRT" % arch) - - result = [] - installer = msilib.MakeInstaller() - # At least for VS2010, manifests are no longer provided - name = "msvcr100.dll" - path = os.path.join(dir, name) - kw = {'src':path} - kw['version'] = installer.FileVersion(path, 0) - kw['language'] = installer.FileVersion(path, 1) - return name, kw - -def generate_license(): - import shutil, glob - out = open("LICENSE.txt", "w") - shutil.copyfileobj(open(os.path.join(srcdir, "LICENSE")), out) - shutil.copyfileobj(open("crtlicense.txt"), out) - for name, pat, file in (("bzip2","bzip2-*", "LICENSE"), - ("openssl", "openssl-*", "LICENSE"), - ("Tcl", "tcl-8*", "license.terms"), - ("Tk", "tk-8*", "license.terms"), - ("Tix", "tix-*", "license.terms")): - out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name) - dirs = glob.glob(srcdir+"/../"+pat) - if not dirs: - raise ValueError, "Could not find "+srcdir+"/../"+pat - if len(dirs) > 2 and not snapshot: - raise ValueError, "Multiple copies of "+pat - dir = dirs[0] - shutil.copyfileobj(open(os.path.join(dir, file)), out) - out.close() - - -class PyDirectory(Directory): - """By default, all components in the Python installer - can run from source.""" - def __init__(self, *args, **kw): - if "componentflags" not in kw: - kw['componentflags'] = 2 #msidbComponentAttributesOptional - Directory.__init__(self, *args, **kw) - -def hgmanifest(): - # Fetch file list from Mercurial - process = subprocess.Popen(['hg', 'manifest'], stdout=subprocess.PIPE) - stdout, stderr = process.communicate() - # Create nested directories for file tree - result = {} - for line in stdout.splitlines(): - components = line.split('/') - d = result - while len(components) > 1: - d1 = d.setdefault(components[0], {}) - d = d1 - del components[0] - d[components[0]] = None - return result - - -# See "File Table", "Component Table", "Directory Table", -# "FeatureComponents Table" -def add_files(db): - installer = msilib.MakeInstaller() - hgfiles = hgmanifest() - cab = CAB("python") - tmpfiles = [] - # Add all executables, icons, text files into the TARGETDIR component - root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir") - default_feature.set_current() - root.add_file("README.txt", src="README") - root.add_file("NEWS.txt", src="Misc/NEWS") - generate_license() - root.add_file("LICENSE.txt", src=os.path.abspath("LICENSE.txt")) - root.start_component("python.exe", keyfile="python.exe") - root.add_file("%s/python.exe" % PCBUILD) - root.start_component("pythonw.exe", keyfile="pythonw.exe") - root.add_file("%s/pythonw.exe" % PCBUILD) - - # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table" - dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".") - launcherdir = PyDirectory(db, cab, root, srcdir, "LAUNCHERDIR", ".") - - # msidbComponentAttributes64bit = 256; this disables registry redirection - # to allow setting the SharedDLLs key in the 64-bit portion even for a - # 32-bit installer. - # XXX does this still allow to install the component on a 32-bit system? - # Pick up 32-bit binary always - launchersrc = PCBUILD - if launchersrc.lower() == 'pcbuild\\x64-pgo': - launchersrc = 'PCBuild\\win32-pgo' - if launchersrc.lower() == 'pcbuild\\amd64': - launchersrc = 'PCBuild' - launcher = os.path.join(srcdir, launchersrc, "py.exe") - launcherdir.start_component("launcher", flags = 8+256, keyfile="py.exe") - launcherdir.add_file(launcher, - version=installer.FileVersion(launcher, 0), - language=installer.FileVersion(launcher, 1)) - launcherw = os.path.join(srcdir, launchersrc, "pyw.exe") - launcherdir.start_component("launcherw", flags = 8+256, keyfile="pyw.exe") - launcherdir.add_file(launcherw, - version=installer.FileVersion(launcherw, 0), - language=installer.FileVersion(launcherw, 1)) - - pydll = "python%s%s.dll" % (major, minor) - pydllsrc = os.path.join(srcdir, PCBUILD, pydll) - dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid) - pyversion = installer.FileVersion(pydllsrc, 0) - if not snapshot: - # For releases, the Python DLL has the same version as the - # installer package. - assert pyversion.split(".")[:3] == current_version.split(".") - dlldir.add_file("%s/python%s%s.dll" % (PCBUILD, major, minor), - version=pyversion, - language=installer.FileVersion(pydllsrc, 1)) - DLLs = PyDirectory(db, cab, root, srcdir + "/" + PCBUILD, "DLLs", "DLLS|DLLs") - - # msvcr90.dll: Need to place the DLL and the manifest into the root directory, - # plus another copy of the manifest in the DLLs directory, with the manifest - # pointing to the root directory - root.start_component("msvcr90", feature=private_crt) - # Results are ID,keyword pairs - crtdll, kwds = extract_msvcr100() - root.add_file(crtdll, **kwds) - # Copy the manifest - # Actually, don't do that anymore - no DLL in DLLs should have a manifest - # dependency on msvcr90.dll anymore, so this should not be necessary - #manifest_dlls = manifest[0]+".root" - #open(manifest_dlls, "w").write(open(manifest[1]['src']).read().replace("msvcr","../msvcr")) - #DLLs.start_component("msvcr90_dlls", feature=private_crt) - #DLLs.add_file(manifest[0], src=os.path.abspath(manifest_dlls)) - - # Now start the main component for the DLLs directory; - # no regular files have been added to the directory yet. - DLLs.start_component() - - # Check if _ctypes.pyd exists - have_ctypes = os.path.exists(srcdir+"/%s/_ctypes.pyd" % PCBUILD) - if not have_ctypes: - print("WARNING: _ctypes.pyd not found, ctypes will not be included") - extensions.remove("_ctypes.pyd") - - # Add all .py files in Lib, except tkinter, test - dirs = [] - pydirs = [(root, "Lib", hgfiles["Lib"], default_feature)] - while pydirs: - # Commit every now and then, or else installer will complain - db.Commit() - parent, dir, files, feature = pydirs.pop() - if dir.startswith("plat-"): - continue - if dir in ["tkinter", "idlelib", "turtledemo"]: - if not have_tcl: - continue - feature = tcltk - tcltk.set_current() - elif dir in ('test', 'tests'): - feature = testsuite - elif not have_ctypes and dir == "ctypes": - continue - feature.set_current() - lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir)) - dirs.append(lib) - has_py = False - for name, subdir in files.items(): - if subdir is None: - assert os.path.isfile(os.path.join(lib.absolute, name)) - if name == 'README': - lib.add_file("README.txt", src="README") - else: - lib.add_file(name) - has_py = has_py or name.endswith(".py") or name.endswith(".pyw") - else: - assert os.path.isdir(os.path.join(lib.absolute, name)) - pydirs.append((lib, name, subdir, feature)) - - if has_py: - lib.remove_pyc() - # Add DLLs - default_feature.set_current() - lib = DLLs - lib.add_file("py.ico", src=srcdir+"/PC/py.ico") - lib.add_file("pyc.ico", src=srcdir+"/PC/pyc.ico") - dlls = [] - tclfiles = [] - for f in extensions: - if f=="_tkinter.pyd": - continue - if not os.path.exists(srcdir + "/" + PCBUILD + "/" + f): - print("WARNING: Missing extension", f) - continue - dlls.append(f) - lib.add_file(f) - lib.add_file('python3.dll') - # Add sqlite - if msilib.msi_type=="Intel64;1033": - sqlite_arch = "/ia64" - elif msilib.msi_type=="x64;1033": - sqlite_arch = "/amd64" - tclsuffix = "64" - else: - sqlite_arch = "" - tclsuffix = "" - lib.add_file("sqlite3.dll") - if have_tcl: - if not os.path.exists("%s/%s/_tkinter.pyd" % (srcdir, PCBUILD)): - print("WARNING: Missing _tkinter.pyd") - else: - lib.start_component("TkDLLs", tcltk) - lib.add_file("_tkinter.pyd") - dlls.append("_tkinter.pyd") - tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix)) - for f in glob.glob1(tcldir, "*.dll"): - lib.add_file(f, src=os.path.join(tcldir, f)) - # check whether there are any unknown extensions - for f in glob.glob1(srcdir+"/"+PCBUILD, "*.pyd"): - if f.endswith("_d.pyd"): continue # debug version - if f in dlls: continue - print("WARNING: Unknown extension", f) - - # Add headers - default_feature.set_current() - lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include") - lib.glob("*.h") - lib.add_file("pyconfig.h", src="../PC/pyconfig.h") - # Add import libraries - lib = PyDirectory(db, cab, root, PCBUILD, "libs", "LIBS|libs") - for f in dlls: - lib.add_file(f.replace('pyd','lib')) - lib.add_file('python%s%s.lib' % (major, minor)) - lib.add_file('python3.lib') - # Add the mingw-format library - if have_mingw: - lib.add_file('libpython%s%s.a' % (major, minor)) - if have_tcl: - # Add Tcl/Tk - tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')] - tcltk.set_current() - while tcldirs: - parent, phys, dir = tcldirs.pop() - lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir)) - if not os.path.exists(lib.absolute): - continue - for f in os.listdir(lib.absolute): - if os.path.isdir(os.path.join(lib.absolute, f)): - tcldirs.append((lib, f, f)) - else: - lib.add_file(f) - # Add tools - tools.set_current() - tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools") - for f in ['i18n', 'pynche', 'Scripts']: - lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f)) - lib.glob("*.py") - lib.glob("*.pyw") - lib.remove_pyc() - lib.glob("*.txt") - if f == "pynche": - x = PyDirectory(db, cab, lib, "X", "X", "X|X") - x.glob("*.txt") - if os.path.exists(os.path.join(lib.absolute, "README")): - lib.add_file("README.txt", src="README") - if f == 'Scripts': - lib.add_file("2to3.py", src="2to3") - lib.add_file("pydoc3.py", src="pydoc3") - lib.add_file("pyvenv.py", src="pyvenv") - # Add documentation - htmlfiles.set_current() - lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc") - lib.start_component("documentation", keyfile=docfile) - lib.add_file(docfile, src="build/htmlhelp/"+docfile) - - cab.commit(db) - - for f in tmpfiles: - os.unlink(f) - -# See "Registry Table", "Component Table" -def add_registry(db): - # File extensions, associated with the REGISTRY.def component - # IDLE verbs depend on the tcltk feature. - # msidbComponentAttributesRegistryKeyPath = 4 - # -1 for Root specifies "dependent on ALLUSERS property" - tcldata = [] - if have_tcl: - tcldata = [ - ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", registry_component, None, - "py.IDLE")] - add_data(db, "Component", - # msidbComponentAttributesRegistryKeyPath = 4 - [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", registry_component, None, - "InstallPath"), - ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", registry_component, None, - "Documentation"), - ("REGISTRY.path", msilib.gen_uuid(), "TARGETDIR", registry_component, None, - None), - ("REGISTRY.ensurepip", msilib.gen_uuid(), "TARGETDIR", registry_component, "EnsurePipRun", - None), - ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component, - None, None)] + tcldata) - # See "FeatureComponents Table". - # The association between TclTk and pythonw.exe is necessary to make ICE59 - # happy, because the installer otherwise believes that the IDLE and PyDoc - # shortcuts might get installed without pythonw.exe being install. This - # is not true, since installing TclTk will install the default feature, which - # will cause pythonw.exe to be installed. - # REGISTRY.tcl is not associated with any feature, as it will be requested - # through a custom action - tcldata = [] - if have_tcl: - tcldata = [(tcltk.id, "pythonw.exe")] - add_data(db, "FeatureComponents", - [(default_feature.id, "REGISTRY"), - (htmlfiles.id, "REGISTRY.doc"), - (prepend_path.id, "REGISTRY.path"), - (pip_feature.id, "REGISTRY.ensurepip"), - (ext_feature.id, "REGISTRY.def")] + - tcldata - ) - # Extensions are not advertised. For advertised extensions, - # we would need separate binaries that install along with the - # extension. - pat = r"Software\Classes\%sPython.%sFile\shell\%s\command" - ewi = "Edit with IDLE" - pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon" - pat3 = r"Software\Classes\%sPython.%sFile" - pat4 = r"Software\Classes\%sPython.%sFile\shellex\DropHandler" - tcl_verbs = [] - if have_tcl: - tcl_verbs=[ - ("py.IDLE", -1, pat % (testprefix, "", ewi), "", - r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"', - "REGISTRY.tcl"), - ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "", - r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -e "%1"', - "REGISTRY.tcl"), - ] - add_data(db, "Registry", - [# Extensions - ("py.ext", -1, r"Software\Classes\."+ext, "", - "Python.File", "REGISTRY.def"), - ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "", - "Python.NoConFile", "REGISTRY.def"), - ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "", - "Python.CompiledFile", "REGISTRY.def"), - ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "", - "Python.CompiledFile", "REGISTRY.def"), - # MIME types - ("py.mime", -1, r"Software\Classes\."+ext, "Content Type", - "text/plain", "REGISTRY.def"), - ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type", - "text/plain", "REGISTRY.def"), - #Verbs - ("py.open", -1, pat % (testprefix, "", "open"), "", - r'"[LAUNCHERDIR]py.exe" "%1" %*', "REGISTRY.def"), - ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "", - r'"[LAUNCHERDIR]pyw.exe" "%1" %*', "REGISTRY.def"), - ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "", - r'"[LAUNCHERDIR]py.exe" "%1" %*', "REGISTRY.def"), - ] + tcl_verbs + [ - #Icons - ("py.icon", -1, pat2 % (testprefix, ""), "", - r'[DLLs]py.ico', "REGISTRY.def"), - ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "", - r'[DLLs]py.ico', "REGISTRY.def"), - ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "", - r'[DLLs]pyc.ico', "REGISTRY.def"), - # Descriptions - ("py.txt", -1, pat3 % (testprefix, ""), "", - "Python File", "REGISTRY.def"), - ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "", - "Python File (no console)", "REGISTRY.def"), - ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "", - "Compiled Python File", "REGISTRY.def"), - # Drop Handler - ("py.drop", -1, pat4 % (testprefix, ""), "", - "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"), - ("pyw.drop", -1, pat4 % (testprefix, "NoCon"), "", - "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"), - ("pyc.drop", -1, pat4 % (testprefix, "Compiled"), "", - "{60254CA5-953B-11CF-8C96-00AA00B8708C}", "REGISTRY.def"), - ]) - - # PATHEXT - add_data(db, "Environment", - [("PathExtAddition", "=-*PathExt", "[~];.PY", "REGISTRY.def")]) - - # Registry keys - prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version) - add_data(db, "Registry", - [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"), - ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "", - "Python %s" % short_version, "REGISTRY"), - ("PythonPath", -1, prefix+r"\PythonPath", "", - r"[TARGETDIR]Lib;[TARGETDIR]DLLs", "REGISTRY"), - ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "", - "[TARGETDIR]Doc\\"+docfile , "REGISTRY.doc"), - ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"), - ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe", - "", r"[TARGETDIR]Python.exe", "REGISTRY.def"), - ("DisplayIcon", -1, - r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code, - "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY"), - # Fake registry entry to allow installer to track whether ensurepip has been run - ("EnsurePipRun", -1, prefix+r"\EnsurePipRun", "", "#1", "REGISTRY.ensurepip"), - ]) - # Shortcuts, see "Shortcut Table" - add_data(db, "Directory", - [("ProgramMenuFolder", "TARGETDIR", "."), - ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))]) - add_data(db, "RemoveFile", - [("MenuDir", "TARGETDIR", None, "MenuDir", 2)]) - tcltkshortcuts = [] - if msilib.Win64: - bitted = "64 bit" - else: - bitted = "32 bit" - if have_tcl: - tcltkshortcuts = [ - ("IDLE", "MenuDir", - "IDLE|IDLE (Python "+short_version+" GUI - "+bitted+")", - "pythonw.exe", tcltk.id, r'"[TARGETDIR]Lib\idlelib\idle.pyw"', - None, None, "python_icon.exe", 0, None, "TARGETDIR"), - ] - add_data(db, "Shortcut", - tcltkshortcuts + - [# Advertised shortcuts: targets are features, not files - ("Python", "MenuDir", - "PYTHON|Python "+short_version+" (command line - "+bitted+")", - "python.exe", default_feature.id, None, None, None, - "python_icon.exe", 2, None, "TARGETDIR"), - # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an - # icon first. - #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation", - # htmlfiles.id, None, None, None, None, None, None, None), - ## Non-advertised shortcuts: must be associated with a registry component - ("Manual", "MenuDir", "MANUAL|Python "+short_version+" Manuals", - "REGISTRY.doc", "[#%s]" % docfile, - None, None, None, None, None, None, None), - ("PyDoc", "MenuDir", - "MODDOCS|Python "+short_version+" Docs Server (pydoc - "+ - bitted+")", "python.exe", default_feature.id, r'-m pydoc -b', - None, None, "python_icon.exe", 0, None, "TARGETDIR"), - ("Uninstall", "MenuDir", "UNINST|Uninstall Python "+ - short_version+" ("+bitted+")", "REGISTRY", - SystemFolderName+"msiexec", "/x%s" % product_code, - None, None, None, None, None, None), - ]) - db.Commit() - -def build_pdbzip(): - pdbexclude = ['kill_python.pdb', 'make_buildinfo.pdb', - 'make_versioninfo.pdb'] - path = "python-%s%s-pdb.zip" % (full_current_version, msilib.arch_ext) - pdbzip = zipfile.ZipFile(path, 'w') - for f in glob.glob1(os.path.join(srcdir, PCBUILD), "*.pdb"): - if f not in pdbexclude and not f.endswith('_d.pdb'): - pdbzip.write(os.path.join(srcdir, PCBUILD, f), f) - pdbzip.close() - -db,msiname = build_database() -try: - add_features(db) - add_ui(db) - add_files(db) - add_registry(db) - remove_old_versions(db) - db.Commit() -finally: - del db - -# Merge CRT into MSI file. This requires the database to be closed. -mod_dir = os.path.join(os.environ["ProgramFiles"], "Common Files", "Merge Modules") -if msilib.Win64: - modules = ["Microsoft_VC100_CRT_x64.msm"] -else: - modules = ["Microsoft_VC100_CRT_x86.msm"] - -for i, n in enumerate(modules): - modules[i] = os.path.join(mod_dir, n) - -def merge(msi, feature, rootdir, modules): - cab_and_filecount = [] - # Step 1: Merge databases, extract cabfiles - m = msilib.MakeMerge2() - m.OpenLog("merge.log") - m.OpenDatabase(msi) - for module in modules: - print module - m.OpenModule(module,0) - m.Merge(feature, rootdir) - print "Errors:" - for e in m.Errors: - print e.Type, e.ModuleTable, e.DatabaseTable - print " Modkeys:", - for s in e.ModuleKeys: print s, - print - print " DBKeys:", - for s in e.DatabaseKeys: print s, - print - cabname = tempfile.mktemp(suffix=".cab") - m.ExtractCAB(cabname) - cab_and_filecount.append((cabname, len(m.ModuleFiles))) - m.CloseModule() - m.CloseDatabase(True) - m.CloseLog() - - # Step 2: Add CAB files - i = msilib.MakeInstaller() - db = i.OpenDatabase(msi, constants.msiOpenDatabaseModeTransact) - - v = db.OpenView("SELECT LastSequence FROM Media") - v.Execute(None) - maxmedia = -1 - while 1: - r = v.Fetch() - if not r: break - seq = r.IntegerData(1) - if seq > maxmedia: - maxmedia = seq - print "Start of Media", maxmedia - - for cabname, count in cab_and_filecount: - stream = "merged%d" % maxmedia - msilib.add_data(db, "Media", - [(maxmedia+1, maxmedia+count, None, "#"+stream, None, None)]) - msilib.add_stream(db, stream, cabname) - os.unlink(cabname) - maxmedia += count - # The merge module sets ALLUSERS to 1 in the property table. - # This is undesired; delete that - v = db.OpenView("DELETE FROM Property WHERE Property='ALLUSERS'") - v.Execute(None) - v.Close() - db.Commit() - -merge(msiname, "SharedCRT", "TARGETDIR", modules) - -# certname (from config.py) should be (a substring of) -# the certificate subject, e.g. "Python Software Foundation" -if certname: - os.system('signtool sign /n "%s" ' - '/t http://timestamp.verisign.com/scripts/timestamp.dll ' - '/d "Python %s" ' - '%s' % (certname, full_current_version, msiname)) - -if pdbzip: - build_pdbzip() diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets new file mode 100644 --- /dev/null +++ b/Tools/msi/msi.targets @@ -0,0 +1,62 @@ + + + + + + <_FileListTarget>$(IntermediateOutputPath)$(MSBuildProjectName).g.csv + <_InstallFilesTarget>$(IntermediateOutputPath)$(MSBuildProjectName).g.wxs + + + + + <_Source>%(Source)$([msbuild]::MakeRelative(%(SourceBase), %(FullPath))) + <_Target>%(Target_)$([msbuild]::MakeRelative(%(TargetBase), %(FullPath))) + + + + + + + + + + + + + + + <_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)`).Replace(`{{LongVersion}}`, `$(PythonVersion)`).Replace(`{{Bitness}}`, `$(Bitness)`)) + <_ExistingContent Condition="Exists('$(IntermediateOutputPath)%(WxlTemplate.Filename).wxl')">$([System.IO.File]::ReadAllText($(IntermediateOutputPath)%(WxlTemplate.Filename).wxl)) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/msilib.py b/Tools/msi/msilib.py deleted file mode 100644 --- a/Tools/msi/msilib.py +++ /dev/null @@ -1,679 +0,0 @@ -# Microsoft Installer Library -# (C) 2003 Martin v. Loewis - -import win32com.client.gencache -import win32com.client -import pythoncom, pywintypes -from win32com.client import constants -import re, string, os, sets, glob, subprocess, sys, _winreg, struct, _msi - -try: - basestring -except NameError: - basestring = (str, unicode) - -# Partially taken from Wine -datasizemask= 0x00ff -type_valid= 0x0100 -type_localizable= 0x0200 - -typemask= 0x0c00 -type_long= 0x0000 -type_short= 0x0400 -type_string= 0x0c00 -type_binary= 0x0800 - -type_nullable= 0x1000 -type_key= 0x2000 -# XXX temporary, localizable? -knownbits = datasizemask | type_valid | type_localizable | \ - typemask | type_nullable | type_key - -# Summary Info Property IDs -PID_CODEPAGE=1 -PID_TITLE=2 -PID_SUBJECT=3 -PID_AUTHOR=4 -PID_KEYWORDS=5 -PID_COMMENTS=6 -PID_TEMPLATE=7 -PID_LASTAUTHOR=8 -PID_REVNUMBER=9 -PID_LASTPRINTED=11 -PID_CREATE_DTM=12 -PID_LASTSAVE_DTM=13 -PID_PAGECOUNT=14 -PID_WORDCOUNT=15 -PID_CHARCOUNT=16 -PID_APPNAME=18 -PID_SECURITY=19 - -def reset(): - global _directories - _directories = sets.Set() - -def EnsureMSI(): - win32com.client.gencache.EnsureModule('{000C1092-0000-0000-C000-000000000046}', 1033, 1, 0) - -def EnsureMSM(): - try: - win32com.client.gencache.EnsureModule('{0ADDA82F-2C26-11D2-AD65-00A0C9AF11A6}', 0, 1, 0) - except pywintypes.com_error: - win32com.client.gencache.EnsureModule('{0ADDA82F-2C26-11D2-AD65-00A0C9AF11A6}', 0, 2, 0) - -_Installer=None -def MakeInstaller(): - global _Installer - if _Installer is None: - EnsureMSI() - _Installer = win32com.client.Dispatch('WindowsInstaller.Installer', - resultCLSID='{000C1090-0000-0000-C000-000000000046}') - return _Installer - -_Merge=None -def MakeMerge2(): - global _Merge - if _Merge is None: - EnsureMSM() - _Merge = win32com.client.Dispatch("Msm.Merge2.1") - return _Merge - -class Table: - def __init__(self, name): - self.name = name - self.fields = [] - - def add_field(self, index, name, type): - self.fields.append((index,name,type)) - - def sql(self): - fields = [] - keys = [] - self.fields.sort() - fields = [None]*len(self.fields) - for index, name, type in self.fields: - index -= 1 - unk = type & ~knownbits - if unk: - print "%s.%s unknown bits %x" % (self.name, name, unk) - size = type & datasizemask - dtype = type & typemask - if dtype == type_string: - if size: - tname="CHAR(%d)" % size - else: - tname="CHAR" - elif dtype == type_short: - assert size==2 - tname = "SHORT" - elif dtype == type_long: - assert size==4 - tname="LONG" - elif dtype == type_binary: - assert size==0 - tname="OBJECT" - else: - tname="unknown" - print "%s.%sunknown integer type %d" % (self.name, name, size) - if type & type_nullable: - flags = "" - else: - flags = " NOT NULL" - if type & type_localizable: - flags += " LOCALIZABLE" - fields[index] = "`%s` %s%s" % (name, tname, flags) - if type & type_key: - keys.append("`%s`" % name) - fields = ", ".join(fields) - keys = ", ".join(keys) - return "CREATE TABLE %s (%s PRIMARY KEY %s)" % (self.name, fields, keys) - - def create(self, db): - v = db.OpenView(self.sql()) - v.Execute(None) - v.Close() - -class Binary: - def __init__(self, fname): - self.name = fname - def __repr__(self): - return 'msilib.Binary(os.path.join(dirname,"%s"))' % self.name - -def gen_schema(destpath, schemapath): - d = MakeInstaller() - schema = d.OpenDatabase(schemapath, - win32com.client.constants.msiOpenDatabaseModeReadOnly) - - # XXX ORBER BY - v=schema.OpenView("SELECT * FROM _Columns") - curtable=None - tables = [] - v.Execute(None) - f = open(destpath, "wt") - f.write("from msilib import Table\n") - while 1: - r=v.Fetch() - if not r:break - name=r.StringData(1) - if curtable != name: - f.write("\n%s = Table('%s')\n" % (name,name)) - curtable = name - tables.append(name) - f.write("%s.add_field(%d,'%s',%d)\n" % - (name, r.IntegerData(2), r.StringData(3), r.IntegerData(4))) - v.Close() - - f.write("\ntables=[%s]\n\n" % (", ".join(tables))) - - # Fill the _Validation table - f.write("_Validation_records = [\n") - v = schema.OpenView("SELECT * FROM _Validation") - v.Execute(None) - while 1: - r = v.Fetch() - if not r:break - # Table, Column, Nullable - f.write("(%s,%s,%s," % - (`r.StringData(1)`, `r.StringData(2)`, `r.StringData(3)`)) - def put_int(i): - if r.IsNull(i):f.write("None, ") - else:f.write("%d," % r.IntegerData(i)) - def put_str(i): - if r.IsNull(i):f.write("None, ") - else:f.write("%s," % `r.StringData(i)`) - put_int(4) # MinValue - put_int(5) # MaxValue - put_str(6) # KeyTable - put_int(7) # KeyColumn - put_str(8) # Category - put_str(9) # Set - put_str(10)# Description - f.write("),\n") - f.write("]\n\n") - - f.close() - -def gen_sequence(destpath, msipath): - dir = os.path.dirname(destpath) - d = MakeInstaller() - seqmsi = d.OpenDatabase(msipath, - win32com.client.constants.msiOpenDatabaseModeReadOnly) - - v = seqmsi.OpenView("SELECT * FROM _Tables"); - v.Execute(None) - f = open(destpath, "w") - print >>f, "import msilib,os;dirname=os.path.dirname(__file__)" - tables = [] - while 1: - r = v.Fetch() - if not r:break - table = r.StringData(1) - tables.append(table) - f.write("%s = [\n" % table) - v1 = seqmsi.OpenView("SELECT * FROM `%s`" % table) - v1.Execute(None) - info = v1.ColumnInfo(constants.msiColumnInfoTypes) - while 1: - r = v1.Fetch() - if not r:break - rec = [] - for i in range(1,r.FieldCount+1): - if r.IsNull(i): - rec.append(None) - elif info.StringData(i)[0] in "iI": - rec.append(r.IntegerData(i)) - elif info.StringData(i)[0] in "slSL": - rec.append(r.StringData(i)) - elif info.StringData(i)[0]=="v": - size = r.DataSize(i) - bytes = r.ReadStream(i, size, constants.msiReadStreamBytes) - bytes = bytes.encode("latin-1") # binary data represented "as-is" - if table == "Binary": - fname = rec[0]+".bin" - open(os.path.join(dir,fname),"wb").write(bytes) - rec.append(Binary(fname)) - else: - rec.append(bytes) - else: - raise "Unsupported column type", info.StringData(i) - f.write(repr(tuple(rec))+",\n") - v1.Close() - f.write("]\n\n") - v.Close() - f.write("tables=%s\n" % repr(map(str,tables))) - f.close() - -class _Unspecified:pass -def change_sequence(seq, action, seqno=_Unspecified, cond = _Unspecified): - "Change the sequence number of an action in a sequence list" - for i in range(len(seq)): - if seq[i][0] == action: - if cond is _Unspecified: - cond = seq[i][1] - if seqno is _Unspecified: - seqno = seq[i][2] - seq[i] = (action, cond, seqno) - return - raise ValueError, "Action not found in sequence" - -def add_data(db, table, values): - d = MakeInstaller() - v = db.OpenView("SELECT * FROM `%s`" % table) - count = v.ColumnInfo(0).FieldCount - r = d.CreateRecord(count) - for value in values: - assert len(value) == count, value - for i in range(count): - field = value[i] - if isinstance(field, (int, long)): - r.SetIntegerData(i+1,field) - elif isinstance(field, basestring): - r.SetStringData(i+1,field) - elif field is None: - pass - elif isinstance(field, Binary): - r.SetStream(i+1, field.name) - else: - raise TypeError, "Unsupported type %s" % field.__class__.__name__ - v.Modify(win32com.client.constants.msiViewModifyInsert, r) - r.ClearData() - v.Close() - -def add_stream(db, name, path): - d = MakeInstaller() - v = db.OpenView("INSERT INTO _Streams (Name, Data) VALUES ('%s', ?)" % name) - r = d.CreateRecord(1) - r.SetStream(1, path) - v.Execute(r) - v.Close() - -def init_database(name, schema, - ProductName, ProductCode, ProductVersion, - Manufacturer, - request_uac = False): - try: - os.unlink(name) - except OSError: - pass - ProductCode = ProductCode.upper() - d = MakeInstaller() - # Create the database - db = d.OpenDatabase(name, - win32com.client.constants.msiOpenDatabaseModeCreate) - # Create the tables - for t in schema.tables: - t.create(db) - # Fill the validation table - add_data(db, "_Validation", schema._Validation_records) - # Initialize the summary information, allowing at most 20 properties - si = db.GetSummaryInformation(20) - si.SetProperty(PID_TITLE, "Installation Database") - si.SetProperty(PID_SUBJECT, ProductName) - si.SetProperty(PID_AUTHOR, Manufacturer) - si.SetProperty(PID_TEMPLATE, msi_type) - si.SetProperty(PID_REVNUMBER, gen_uuid()) - if request_uac: - wc = 2 # long file names, compressed, original media - else: - wc = 2 | 8 # +never invoke UAC - si.SetProperty(PID_WORDCOUNT, wc) - si.SetProperty(PID_PAGECOUNT, 200) - si.SetProperty(PID_APPNAME, "Python MSI Library") - # XXX more properties - si.Persist() - add_data(db, "Property", [ - ("ProductName", ProductName), - ("ProductCode", ProductCode), - ("ProductVersion", ProductVersion), - ("Manufacturer", Manufacturer), - ("ProductLanguage", "1033")]) - db.Commit() - return db - -def add_tables(db, module): - for table in module.tables: - add_data(db, table, getattr(module, table)) - -def make_id(str): - #str = str.replace(".", "_") # colons are allowed - str = str.replace(" ", "_") - str = str.replace("-", "_") - str = str.replace("+", "_") - if str[0] in string.digits: - str = "_"+str - assert re.match("^[A-Za-z_][A-Za-z0-9_.]*$", str), "FILE"+str - return str - -def gen_uuid(): - return str(pythoncom.CreateGuid()) - -class CAB: - def __init__(self, name): - self.name = name - self.files = [] - self.filenames = sets.Set() - self.index = 0 - - def gen_id(self, dir, file): - logical = _logical = make_id(file) - pos = 1 - while logical in self.filenames: - logical = "%s.%d" % (_logical, pos) - pos += 1 - self.filenames.add(logical) - return logical - - def append(self, full, file, logical = None): - if os.path.isdir(full): - return - if not logical: - logical = self.gen_id(dir, file) - self.index += 1 - self.files.append((full, logical)) - return self.index, logical - - def commit(self, db): - try: - os.unlink(self.name+".cab") - except OSError: - pass - _msi.FCICreate(self.name+".cab", self.files) - add_data(db, "Media", - [(1, self.index, None, "#"+self.name, None, None)]) - add_stream(db, self.name, self.name+".cab") - os.unlink(self.name+".cab") - db.Commit() - -_directories = sets.Set() -class Directory: - def __init__(self, db, cab, basedir, physical, _logical, default, componentflags=None): - """Create a new directory in the Directory table. There is a current component - at each point in time for the directory, which is either explicitly created - through start_component, or implicitly when files are added for the first - time. Files are added into the current component, and into the cab file. - To create a directory, a base directory object needs to be specified (can be - None), the path to the physical directory, and a logical directory name. - Default specifies the DefaultDir slot in the directory table. componentflags - specifies the default flags that new components get.""" - index = 1 - _logical = make_id(_logical) - logical = _logical - while logical in _directories: - logical = "%s%d" % (_logical, index) - index += 1 - _directories.add(logical) - self.db = db - self.cab = cab - self.basedir = basedir - self.physical = physical - self.logical = logical - self.component = None - self.short_names = {} - self.ids = sets.Set() - self.keyfiles = {} - self.componentflags = componentflags - if basedir: - self.absolute = os.path.join(basedir.absolute, physical) - blogical = basedir.logical - else: - self.absolute = physical - blogical = None - # initially assume that all files in this directory are unpackaged - # as files from self.absolute get added, this set is reduced - self.unpackaged_files = set() - for f in os.listdir(self.absolute): - if os.path.isfile(os.path.join(self.absolute, f)): - self.unpackaged_files.add(f) - add_data(db, "Directory", [(logical, blogical, default)]) - - def start_component(self, component = None, feature = None, flags = None, keyfile = None, uuid=None): - """Add an entry to the Component table, and make this component the current for this - directory. If no component name is given, the directory name is used. If no feature - is given, the current feature is used. If no flags are given, the directory's default - flags are used. If no keyfile is given, the KeyPath is left null in the Component - table.""" - if flags is None: - flags = self.componentflags - if uuid is None: - uuid = gen_uuid() - else: - uuid = uuid.upper() - if component is None: - component = self.logical - self.component = component - if Win64: - flags |= 256 - if keyfile: - keyid = self.cab.gen_id(self.absolute, keyfile) - self.keyfiles[keyfile] = keyid - else: - keyid = None - add_data(self.db, "Component", - [(component, uuid, self.logical, flags, None, keyid)]) - if feature is None: - feature = current_feature - add_data(self.db, "FeatureComponents", - [(feature.id, component)]) - - def make_short(self, file): - long = file - file = re.sub(r'[\?|><:/*"+,;=\[\]]', '_', file) # restrictions on short names - parts = file.split(".", 1) - if len(parts)>1: - suffix = parts[1].upper() - else: - suffix = '' - prefix = parts[0].upper() - if len(prefix) <= 8 and '.' not in suffix and len(suffix) <= 3: - if suffix: - file = prefix+"."+suffix - else: - file = prefix - assert file not in self.short_names, (file, self.short_names[file]) - else: - prefix = prefix[:6] - if suffix: - # last three characters of last suffix - suffix = suffix.rsplit('.')[-1][:3] - pos = 1 - while 1: - if suffix: - file = "%s~%d.%s" % (prefix, pos, suffix) - else: - file = "%s~%d" % (prefix, pos) - if file not in self.short_names: break - pos += 1 - assert pos < 10000 - if pos in (10, 100, 1000): - prefix = prefix[:-1] - self.short_names[file] = long - return file - - def add_file(self, file, src=None, version=None, language=None): - """Add a file to the current component of the directory, starting a new one - if there is no current component. By default, the file name in the source - and the file table will be identical. If the src file is specified, it is - interpreted relative to the current directory. Optionally, a version and a - language can be specified for the entry in the File table.""" - if not self.component: - self.start_component(self.logical, current_feature) - if not src: - # Allow relative paths for file if src is not specified - src = file - file = os.path.basename(file) - absolute = os.path.join(self.absolute, src) - if absolute.startswith(self.absolute): - # mark file as packaged - relative = absolute[len(self.absolute)+1:] - if relative in self.unpackaged_files: - self.unpackaged_files.remove(relative) - assert not re.search(r'[\?|><:/*]"', file) # restrictions on long names - if self.keyfiles.has_key(file): - logical = self.keyfiles[file] - else: - logical = None - sequence, logical = self.cab.append(absolute, file, logical) - assert logical not in self.ids - self.ids.add(logical) - short = self.make_short(file) - full = "%s|%s" % (short, file) - filesize = os.stat(absolute).st_size - # constants.msidbFileAttributesVital - # Compressed omitted, since it is the database default - # could add r/o, system, hidden - attributes = 512 - add_data(self.db, "File", - [(logical, self.component, full, filesize, version, - language, attributes, sequence)]) - if not version: - # Add hash if the file is not versioned - filehash = MakeInstaller().FileHash(absolute, 0) - add_data(self.db, "MsiFileHash", - [(logical, 0, filehash.IntegerData(1), - filehash.IntegerData(2), filehash.IntegerData(3), - filehash.IntegerData(4))]) - # Automatically remove .pyc/.pyo files on uninstall (2) - # XXX: adding so many RemoveFile entries makes installer unbelievably - # slow. So instead, we have to use wildcard remove entries - # if file.endswith(".py"): - # add_data(self.db, "RemoveFile", - # [(logical+"c", self.component, "%sC|%sc" % (short, file), - # self.logical, 2), - # (logical+"o", self.component, "%sO|%so" % (short, file), - # self.logical, 2)]) - - def glob(self, pattern, exclude = None): - """Add a list of files to the current component as specified in the - glob pattern. Individual files can be excluded in the exclude list.""" - files = glob.glob1(self.absolute, pattern) - for f in files: - if exclude and f in exclude: continue - self.add_file(f) - return files - - def remove_pyc(self): - "Remove .pyc/.pyo files from __pycache__ on uninstall" - directory = self.logical + "_pycache" - add_data(self.db, "Directory", [(directory, self.logical, "__PYCA~1|__pycache__")]) - flags = 256 if Win64 else 0 - add_data(self.db, "Component", - [(directory, gen_uuid(), directory, flags, None, None)]) - add_data(self.db, "FeatureComponents", [(current_feature.id, directory)]) - add_data(self.db, "CreateFolder", [(directory, directory)]) - add_data(self.db, "RemoveFile", - [(self.component, self.component, "*.*", directory, 2), - ]) - - def removefile(self, key, pattern): - "Add a RemoveFile entry" - add_data(self.db, "RemoveFile", [(self.component+key, self.component, pattern, self.logical, 2)]) - - -class Feature: - def __init__(self, db, id, title, desc, display, level = 1, - parent=None, directory = None, attributes=0): - self.id = id - if parent: - parent = parent.id - add_data(db, "Feature", - [(id, parent, title, desc, display, - level, directory, attributes)]) - def set_current(self): - global current_feature - current_feature = self - -class Control: - def __init__(self, dlg, name): - self.dlg = dlg - self.name = name - - def event(self, ev, arg, cond = "1", order = None): - add_data(self.dlg.db, "ControlEvent", - [(self.dlg.name, self.name, ev, arg, cond, order)]) - - def mapping(self, ev, attr): - add_data(self.dlg.db, "EventMapping", - [(self.dlg.name, self.name, ev, attr)]) - - def condition(self, action, condition): - add_data(self.dlg.db, "ControlCondition", - [(self.dlg.name, self.name, action, condition)]) - -class RadioButtonGroup(Control): - def __init__(self, dlg, name, property): - self.dlg = dlg - self.name = name - self.property = property - self.index = 1 - - def add(self, name, x, y, w, h, text, value = None): - if value is None: - value = name - add_data(self.dlg.db, "RadioButton", - [(self.property, self.index, value, - x, y, w, h, text, None)]) - self.index += 1 - -class Dialog: - def __init__(self, db, name, x, y, w, h, attr, title, first, default, cancel): - self.db = db - self.name = name - self.x, self.y, self.w, self.h = x,y,w,h - add_data(db, "Dialog", [(name, x,y,w,h,attr,title,first,default,cancel)]) - - def control(self, name, type, x, y, w, h, attr, prop, text, next, help): - add_data(self.db, "Control", - [(self.name, name, type, x, y, w, h, attr, prop, text, next, help)]) - return Control(self, name) - - def text(self, name, x, y, w, h, attr, text): - return self.control(name, "Text", x, y, w, h, attr, None, - text, None, None) - - def bitmap(self, name, x, y, w, h, text): - return self.control(name, "Bitmap", x, y, w, h, 1, None, text, None, None) - - def line(self, name, x, y, w, h): - return self.control(name, "Line", x, y, w, h, 1, None, None, None, None) - - def pushbutton(self, name, x, y, w, h, attr, text, next): - return self.control(name, "PushButton", x, y, w, h, attr, None, text, next, None) - - def radiogroup(self, name, x, y, w, h, attr, prop, text, next): - add_data(self.db, "Control", - [(self.name, name, "RadioButtonGroup", - x, y, w, h, attr, prop, text, next, None)]) - return RadioButtonGroup(self, name, prop) - - def checkbox(self, name, x, y, w, h, attr, prop, text, next): - return self.control(name, "CheckBox", x, y, w, h, attr, prop, text, next, None) - -def pe_type(path): - header = open(path, "rb").read(1000) - # offset of PE header is at offset 0x3c - pe_offset = struct.unpack(" + + + {91C99298-8E2E-4422-A5AF-CC4FFF9A58D3} + 2.0 + path + Package + ICE71 + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/path/path.wxs b/Tools/msi/path/path.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/path/path.wxs @@ -0,0 +1,35 @@ +? + + + + + + + + + + NOT ALLUSERS=1 + + + + + + + + + + ALLUSERS=1 + + + + + + + + + + + + + + diff --git a/Tools/msi/path/path_en-US.wxl b/Tools/msi/path/path_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/path/path_en-US.wxl @@ -0,0 +1,6 @@ +? + + Add to Path + Path + No !(loc.ProductName) installation was detected. + diff --git a/Tools/msi/pip/pip.wixproj b/Tools/msi/pip/pip.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/pip/pip.wixproj @@ -0,0 +1,19 @@ + + + + {91C99298-8E2E-4422-A5AF-CC4FFF9A58D3} + 2.0 + pip + Package + ICE71 + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/pip/pip.wxs b/Tools/msi/pip/pip.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/pip/pip.wxs @@ -0,0 +1,41 @@ +? + + + + + + + + + + + + + + PYTHON_EXE + + + + + + + + + + + + + + + + + + + (&DefaultFeature=3) AND NOT (!DefaultFeature=3) + (&DefaultFeature=2) AND (!DefaultFeature=3) + + UpdatePip + + + + diff --git a/Tools/msi/pip/pip_en-US.wxl b/Tools/msi/pip/pip_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/pip/pip_en-US.wxl @@ -0,0 +1,6 @@ +? + + pip Bootstrap + pip + No !(loc.ProductName) installation was detected. + diff --git a/Tools/msi/schema.py b/Tools/msi/schema.py deleted file mode 100644 --- a/Tools/msi/schema.py +++ /dev/null @@ -1,1007 +0,0 @@ -from msilib import Table - -_Validation = Table('_Validation') -_Validation.add_field(1,'Table',11552) -_Validation.add_field(2,'Column',11552) -_Validation.add_field(3,'Nullable',3332) -_Validation.add_field(4,'MinValue',4356) -_Validation.add_field(5,'MaxValue',4356) -_Validation.add_field(6,'KeyTable',7679) -_Validation.add_field(7,'KeyColumn',5378) -_Validation.add_field(8,'Category',7456) -_Validation.add_field(9,'Set',7679) -_Validation.add_field(10,'Description',7679) - -ActionText = Table('ActionText') -ActionText.add_field(1,'Action',11592) -ActionText.add_field(2,'Description',7936) -ActionText.add_field(3,'Template',7936) - -AdminExecuteSequence = Table('AdminExecuteSequence') -AdminExecuteSequence.add_field(1,'Action',0x2DFF) -AdminExecuteSequence.add_field(2,'Condition',7679) -AdminExecuteSequence.add_field(3,'Sequence',5378) - -Condition = Table('Condition') -Condition.add_field(1,'Feature_',11558) -Condition.add_field(2,'Level',9474) -Condition.add_field(3,'Condition',7679) - -AdminUISequence = Table('AdminUISequence') -AdminUISequence.add_field(1,'Action',0x2DFF) -AdminUISequence.add_field(2,'Condition',7679) -AdminUISequence.add_field(3,'Sequence',5378) - -AdvtExecuteSequence = Table('AdvtExecuteSequence') -AdvtExecuteSequence.add_field(1,'Action',0x2DFF) -AdvtExecuteSequence.add_field(2,'Condition',7679) -AdvtExecuteSequence.add_field(3,'Sequence',5378) - -AdvtUISequence = Table('AdvtUISequence') -AdvtUISequence.add_field(1,'Action',11592) -AdvtUISequence.add_field(2,'Condition',7679) -AdvtUISequence.add_field(3,'Sequence',5378) - -AppId = Table('AppId') -AppId.add_field(1,'AppId',11558) -AppId.add_field(2,'RemoteServerName',7679) -AppId.add_field(3,'LocalService',7679) -AppId.add_field(4,'ServiceParameters',7679) -AppId.add_field(5,'DllSurrogate',7679) -AppId.add_field(6,'ActivateAtStorage',5378) -AppId.add_field(7,'RunAsInteractiveUser',5378) - -AppSearch = Table('AppSearch') -AppSearch.add_field(1,'Property',11592) -AppSearch.add_field(2,'Signature_',11592) - -Property = Table('Property') -Property.add_field(1,'Property',11592) -Property.add_field(2,'Value',3840) - -BBControl = Table('BBControl') -BBControl.add_field(1,'Billboard_',11570) -BBControl.add_field(2,'BBControl',11570) -BBControl.add_field(3,'Type',3378) -BBControl.add_field(4,'X',1282) -BBControl.add_field(5,'Y',1282) -BBControl.add_field(6,'Width',1282) -BBControl.add_field(7,'Height',1282) -BBControl.add_field(8,'Attributes',4356) -BBControl.add_field(9,'Text',7986) - -Billboard = Table('Billboard') -Billboard.add_field(1,'Billboard',11570) -Billboard.add_field(2,'Feature_',3366) -Billboard.add_field(3,'Action',7474) -Billboard.add_field(4,'Ordering',5378) - -Feature = Table('Feature') -Feature.add_field(1,'Feature',11558) -Feature.add_field(2,'Feature_Parent',7462) -Feature.add_field(3,'Title',8000) -Feature.add_field(4,'Description',8191) -Feature.add_field(5,'Display',5378) -Feature.add_field(6,'Level',1282) -Feature.add_field(7,'Directory_',0x1DFF) -Feature.add_field(8,'Attributes',1282) - -Binary = Table('Binary') -Binary.add_field(1,'Name',11592) -Binary.add_field(2,'Data',2304) - -BindImage = Table('BindImage') -BindImage.add_field(1,'File_',0x2DFF) -BindImage.add_field(2,'Path',7679) - -File = Table('File') -File.add_field(1,'File',0x2DFF) -File.add_field(2,'Component_',0xDFF) -File.add_field(3,'FileName',4095) -File.add_field(4,'FileSize',260) -File.add_field(5,'Version',0x1DFF) -File.add_field(6,'Language',7444) -File.add_field(7,'Attributes',5378) -File.add_field(8,'Sequence',1282) - -CCPSearch = Table('CCPSearch') -CCPSearch.add_field(1,'Signature_',11592) - -CheckBox = Table('CheckBox') -CheckBox.add_field(1,'Property',11592) -CheckBox.add_field(2,'Value',7488) - -Class = Table('Class') -Class.add_field(1,'CLSID',11558) -Class.add_field(2,'Context',11552) -Class.add_field(3,'Component_',0x2DFF) -Class.add_field(4,'ProgId_Default',7679) -Class.add_field(5,'Description',8191) -Class.add_field(6,'AppId_',7462) -Class.add_field(7,'FileTypeMask',7679) -Class.add_field(8,'Icon_',7496) -Class.add_field(9,'IconIndex',5378) -Class.add_field(10,'DefInprocHandler',7456) -Class.add_field(11,'Argument',7679) -Class.add_field(12,'Feature_',3366) -Class.add_field(13,'Attributes',5378) - -Component = Table('Component') -Component.add_field(1,'Component',0x2DFF) -Component.add_field(2,'ComponentId',7462) -Component.add_field(3,'Directory_',0xDFF) -Component.add_field(4,'Attributes',1282) -Component.add_field(5,'Condition',7679) -Component.add_field(6,'KeyPath',0x1DFF) - -Icon = Table('Icon') -Icon.add_field(1,'Name',11592) -Icon.add_field(2,'Data',2304) - -ProgId = Table('ProgId') -ProgId.add_field(1,'ProgId',11775) -ProgId.add_field(2,'ProgId_Parent',7679) -ProgId.add_field(3,'Class_',7462) -ProgId.add_field(4,'Description',8191) -ProgId.add_field(5,'Icon_',7496) -ProgId.add_field(6,'IconIndex',5378) - -ComboBox = Table('ComboBox') -ComboBox.add_field(1,'Property',11592) -ComboBox.add_field(2,'Order',9474) -ComboBox.add_field(3,'Value',3392) -ComboBox.add_field(4,'Text',8000) - -CompLocator = Table('CompLocator') -CompLocator.add_field(1,'Signature_',11592) -CompLocator.add_field(2,'ComponentId',3366) -CompLocator.add_field(3,'Type',5378) - -Complus = Table('Complus') -Complus.add_field(1,'Component_',0x2DFF) -Complus.add_field(2,'ExpType',13570) - -Directory = Table('Directory') -Directory.add_field(1,'Directory',0x2DFF) -Directory.add_field(2,'Directory_Parent',0x1DFF) -Directory.add_field(3,'DefaultDir',4095) - -Control = Table('Control') -Control.add_field(1,'Dialog_',11592) -Control.add_field(2,'Control',11570) -Control.add_field(3,'Type',3348) -Control.add_field(4,'X',1282) -Control.add_field(5,'Y',1282) -Control.add_field(6,'Width',1282) -Control.add_field(7,'Height',1282) -Control.add_field(8,'Attributes',4356) -Control.add_field(9,'Property',7474) -Control.add_field(10,'Text',7936) -Control.add_field(11,'Control_Next',7474) -Control.add_field(12,'Help',7986) - -Dialog = Table('Dialog') -Dialog.add_field(1,'Dialog',11592) -Dialog.add_field(2,'HCentering',1282) -Dialog.add_field(3,'VCentering',1282) -Dialog.add_field(4,'Width',1282) -Dialog.add_field(5,'Height',1282) -Dialog.add_field(6,'Attributes',4356) -Dialog.add_field(7,'Title',8064) -Dialog.add_field(8,'Control_First',3378) -Dialog.add_field(9,'Control_Default',7474) -Dialog.add_field(10,'Control_Cancel',7474) - -ControlCondition = Table('ControlCondition') -ControlCondition.add_field(1,'Dialog_',11592) -ControlCondition.add_field(2,'Control_',11570) -ControlCondition.add_field(3,'Action',11570) -ControlCondition.add_field(4,'Condition',11775) - -ControlEvent = Table('ControlEvent') -ControlEvent.add_field(1,'Dialog_',11592) -ControlEvent.add_field(2,'Control_',11570) -ControlEvent.add_field(3,'Event',11570) -ControlEvent.add_field(4,'Argument',11775) -ControlEvent.add_field(5,'Condition',15871) -ControlEvent.add_field(6,'Ordering',5378) - -CreateFolder = Table('CreateFolder') -CreateFolder.add_field(1,'Directory_',0x2DFF) -CreateFolder.add_field(2,'Component_',0x2DFF) - -CustomAction = Table('CustomAction') -CustomAction.add_field(1,'Action',0x2DFF) -CustomAction.add_field(2,'Type',1282) -CustomAction.add_field(3,'Source',0x1DFF) -CustomAction.add_field(4,'Target',7679) - -DrLocator = Table('DrLocator') -DrLocator.add_field(1,'Signature_',11592) -DrLocator.add_field(2,'Parent',15688) -DrLocator.add_field(3,'Path',15871) -DrLocator.add_field(4,'Depth',5378) - -DuplicateFile = Table('DuplicateFile') -DuplicateFile.add_field(1,'FileKey',11592) -DuplicateFile.add_field(2,'Component_',0xDFF) -DuplicateFile.add_field(3,'File_',0xDFF) -DuplicateFile.add_field(4,'DestName',8191) -DuplicateFile.add_field(5,'DestFolder',7496) - -Environment = Table('Environment') -Environment.add_field(1,'Environment',11592) -Environment.add_field(2,'Name',4095) -Environment.add_field(3,'Value',8191) -Environment.add_field(4,'Component_',0xDFF) - -Error = Table('Error') -Error.add_field(1,'Error',9474) -Error.add_field(2,'Message',7936) - -EventMapping = Table('EventMapping') -EventMapping.add_field(1,'Dialog_',11592) -EventMapping.add_field(2,'Control_',11570) -EventMapping.add_field(3,'Event',11570) -EventMapping.add_field(4,'Attribute',3378) - -Extension = Table('Extension') -Extension.add_field(1,'Extension',11775) -Extension.add_field(2,'Component_',0x2DFF) -Extension.add_field(3,'ProgId_',7679) -Extension.add_field(4,'MIME_',7488) -Extension.add_field(5,'Feature_',3366) - -MIME = Table('MIME') -MIME.add_field(1,'ContentType',11584) -MIME.add_field(2,'Extension_',3583) -MIME.add_field(3,'CLSID',7462) - -FeatureComponents = Table('FeatureComponents') -FeatureComponents.add_field(1,'Feature_',11558) -FeatureComponents.add_field(2,'Component_',0x2DFF) - -FileSFPCatalog = Table('FileSFPCatalog') -FileSFPCatalog.add_field(1,'File_',0x2DFF) -FileSFPCatalog.add_field(2,'SFPCatalog_',11775) - -SFPCatalog = Table('SFPCatalog') -SFPCatalog.add_field(1,'SFPCatalog',11775) -SFPCatalog.add_field(2,'Catalog',2304) -SFPCatalog.add_field(3,'Dependency',7424) - -Font = Table('Font') -Font.add_field(1,'File_',0x2DFF) -Font.add_field(2,'FontTitle',7552) - -IniFile = Table('IniFile') -IniFile.add_field(1,'IniFile',11592) -IniFile.add_field(2,'FileName',4095) -IniFile.add_field(3,'DirProperty',7496) -IniFile.add_field(4,'Section',3936) -IniFile.add_field(5,'Key',3968) -IniFile.add_field(6,'Value',4095) -IniFile.add_field(7,'Action',1282) -IniFile.add_field(8,'Component_',0xDFF) - -IniLocator = Table('IniLocator') -IniLocator.add_field(1,'Signature_',11592) -IniLocator.add_field(2,'FileName',3583) -IniLocator.add_field(3,'Section',3424) -IniLocator.add_field(4,'Key',3456) -IniLocator.add_field(5,'Field',5378) -IniLocator.add_field(6,'Type',5378) - -InstallExecuteSequence = Table('InstallExecuteSequence') -InstallExecuteSequence.add_field(1,'Action',0x2DFF) -InstallExecuteSequence.add_field(2,'Condition',7679) -InstallExecuteSequence.add_field(3,'Sequence',5378) - -InstallUISequence = Table('InstallUISequence') -InstallUISequence.add_field(1,'Action',0x2DFF) -InstallUISequence.add_field(2,'Condition',7679) -InstallUISequence.add_field(3,'Sequence',5378) - -IsolatedComponent = Table('IsolatedComponent') -IsolatedComponent.add_field(1,'Component_Shared',0x2DFF) -IsolatedComponent.add_field(2,'Component_Application',0x2DFF) - -LaunchCondition = Table('LaunchCondition') -LaunchCondition.add_field(1,'Condition',11775) -LaunchCondition.add_field(2,'Description',4095) - -ListBox = Table('ListBox') -ListBox.add_field(1,'Property',11592) -ListBox.add_field(2,'Order',9474) -ListBox.add_field(3,'Value',3392) -ListBox.add_field(4,'Text',8000) - -ListView = Table('ListView') -ListView.add_field(1,'Property',11592) -ListView.add_field(2,'Order',9474) -ListView.add_field(3,'Value',3392) -ListView.add_field(4,'Text',8000) -ListView.add_field(5,'Binary_',7496) - -LockPermissions = Table('LockPermissions') -LockPermissions.add_field(1,'LockObject',11592) -LockPermissions.add_field(2,'Table',11552) -LockPermissions.add_field(3,'Domain',15871) -LockPermissions.add_field(4,'User',11775) -LockPermissions.add_field(5,'Permission',4356) - -Media = Table('Media') -Media.add_field(1,'DiskId',9474) -Media.add_field(2,'LastSequence',1282) -Media.add_field(3,'DiskPrompt',8000) -Media.add_field(4,'Cabinet',7679) -Media.add_field(5,'VolumeLabel',7456) -Media.add_field(6,'Source',7496) - -MoveFile = Table('MoveFile') -MoveFile.add_field(1,'FileKey',11592) -MoveFile.add_field(2,'Component_',0xDFF) -MoveFile.add_field(3,'SourceName',8191) -MoveFile.add_field(4,'DestName',8191) -MoveFile.add_field(5,'SourceFolder',7496) -MoveFile.add_field(6,'DestFolder',3400) -MoveFile.add_field(7,'Options',1282) - -MsiAssembly = Table('MsiAssembly') -MsiAssembly.add_field(1,'Component_',0x2DFF) -MsiAssembly.add_field(2,'Feature_',3366) -MsiAssembly.add_field(3,'File_Manifest',0x1DFF) -MsiAssembly.add_field(4,'File_Application',0x1DFF) -MsiAssembly.add_field(5,'Attributes',5378) - -MsiAssemblyName = Table('MsiAssemblyName') -MsiAssemblyName.add_field(1,'Component_',0x2DFF) -MsiAssemblyName.add_field(2,'Name',11775) -MsiAssemblyName.add_field(3,'Value',3583) - -MsiDigitalCertificate = Table('MsiDigitalCertificate') -MsiDigitalCertificate.add_field(1,'DigitalCertificate',11592) -MsiDigitalCertificate.add_field(2,'CertData',2304) - -MsiDigitalSignature = Table('MsiDigitalSignature') -MsiDigitalSignature.add_field(1,'Table',11552) -MsiDigitalSignature.add_field(2,'SignObject',11592) -MsiDigitalSignature.add_field(3,'DigitalCertificate_',3400) -MsiDigitalSignature.add_field(4,'Hash',6400) - -MsiFileHash = Table('MsiFileHash') -MsiFileHash.add_field(1,'File_',0x2DFF) -MsiFileHash.add_field(2,'Options',1282) -MsiFileHash.add_field(3,'HashPart1',260) -MsiFileHash.add_field(4,'HashPart2',260) -MsiFileHash.add_field(5,'HashPart3',260) -MsiFileHash.add_field(6,'HashPart4',260) - -MsiPatchHeaders = Table('MsiPatchHeaders') -MsiPatchHeaders.add_field(1,'StreamRef',11558) -MsiPatchHeaders.add_field(2,'Header',2304) - -ODBCAttribute = Table('ODBCAttribute') -ODBCAttribute.add_field(1,'Driver_',11592) -ODBCAttribute.add_field(2,'Attribute',11560) -ODBCAttribute.add_field(3,'Value',8191) - -ODBCDriver = Table('ODBCDriver') -ODBCDriver.add_field(1,'Driver',11592) -ODBCDriver.add_field(2,'Component_',0xDFF) -ODBCDriver.add_field(3,'Description',3583) -ODBCDriver.add_field(4,'File_',0xDFF) -ODBCDriver.add_field(5,'File_Setup',0x1DFF) - -ODBCDataSource = Table('ODBCDataSource') -ODBCDataSource.add_field(1,'DataSource',0x2DFF) -ODBCDataSource.add_field(2,'Component_',0xDFF) -ODBCDataSource.add_field(3,'Description',3583) -ODBCDataSource.add_field(4,'DriverDescription',3583) -ODBCDataSource.add_field(5,'Registration',1282) - -ODBCSourceAttribute = Table('ODBCSourceAttribute') -ODBCSourceAttribute.add_field(1,'DataSource_',11592) -ODBCSourceAttribute.add_field(2,'Attribute',11552) -ODBCSourceAttribute.add_field(3,'Value',8191) - -ODBCTranslator = Table('ODBCTranslator') -ODBCTranslator.add_field(1,'Translator',11592) -ODBCTranslator.add_field(2,'Component_',0xDFF) -ODBCTranslator.add_field(3,'Description',3583) -ODBCTranslator.add_field(4,'File_',0xDFF) -ODBCTranslator.add_field(5,'File_Setup',0x1DFF) - -Patch = Table('Patch') -Patch.add_field(1,'File_',11592) -Patch.add_field(2,'Sequence',9474) -Patch.add_field(3,'PatchSize',260) -Patch.add_field(4,'Attributes',1282) -Patch.add_field(5,'Header',6400) -Patch.add_field(6,'StreamRef_',7462) - -PatchPackage = Table('PatchPackage') -PatchPackage.add_field(1,'PatchId',11558) -PatchPackage.add_field(2,'Media_',1282) - -PublishComponent = Table('PublishComponent') -PublishComponent.add_field(1,'ComponentId',11558) -PublishComponent.add_field(2,'Qualifier',11775) -PublishComponent.add_field(3,'Component_',0x2DFF) -PublishComponent.add_field(4,'AppData',8191) -PublishComponent.add_field(5,'Feature_',3366) - -RadioButton = Table('RadioButton') -RadioButton.add_field(1,'Property',11592) -RadioButton.add_field(2,'Order',9474) -RadioButton.add_field(3,'Value',3392) -RadioButton.add_field(4,'X',1282) -RadioButton.add_field(5,'Y',1282) -RadioButton.add_field(6,'Width',1282) -RadioButton.add_field(7,'Height',1282) -RadioButton.add_field(8,'Text',8000) -RadioButton.add_field(9,'Help',7986) - -Registry = Table('Registry') -Registry.add_field(1,'Registry',0x2DFF) -Registry.add_field(2,'Root',1282) -Registry.add_field(3,'Key',4095) -Registry.add_field(4,'Name',8191) -Registry.add_field(5,'Value',7936) -Registry.add_field(6,'Component_',0xDFF) - -RegLocator = Table('RegLocator') -RegLocator.add_field(1,'Signature_',11592) -RegLocator.add_field(2,'Root',1282) -RegLocator.add_field(3,'Key',3583) -RegLocator.add_field(4,'Name',7679) -RegLocator.add_field(5,'Type',5378) - -RemoveFile = Table('RemoveFile') -RemoveFile.add_field(1,'FileKey',11592) -RemoveFile.add_field(2,'Component_',0xDFF) -RemoveFile.add_field(3,'FileName',8191) -RemoveFile.add_field(4,'DirProperty',3400) -RemoveFile.add_field(5,'InstallMode',1282) - -RemoveIniFile = Table('RemoveIniFile') -RemoveIniFile.add_field(1,'RemoveIniFile',11592) -RemoveIniFile.add_field(2,'FileName',4095) -RemoveIniFile.add_field(3,'DirProperty',7496) -RemoveIniFile.add_field(4,'Section',3936) -RemoveIniFile.add_field(5,'Key',3968) -RemoveIniFile.add_field(6,'Value',8191) -RemoveIniFile.add_field(7,'Action',1282) -RemoveIniFile.add_field(8,'Component_',0xDFF) - -RemoveRegistry = Table('RemoveRegistry') -RemoveRegistry.add_field(1,'RemoveRegistry',11592) -RemoveRegistry.add_field(2,'Root',1282) -RemoveRegistry.add_field(3,'Key',4095) -RemoveRegistry.add_field(4,'Name',8191) -RemoveRegistry.add_field(5,'Component_',0xDFF) - -ReserveCost = Table('ReserveCost') -ReserveCost.add_field(1,'ReserveKey',11592) -ReserveCost.add_field(2,'Component_',0xDFF) -ReserveCost.add_field(3,'ReserveFolder',7496) -ReserveCost.add_field(4,'ReserveLocal',260) -ReserveCost.add_field(5,'ReserveSource',260) - -SelfReg = Table('SelfReg') -SelfReg.add_field(1,'File_',0x2DFF) -SelfReg.add_field(2,'Cost',5378) - -ServiceControl = Table('ServiceControl') -ServiceControl.add_field(1,'ServiceControl',11592) -ServiceControl.add_field(2,'Name',4095) -ServiceControl.add_field(3,'Event',1282) -ServiceControl.add_field(4,'Arguments',8191) -ServiceControl.add_field(5,'Wait',5378) -ServiceControl.add_field(6,'Component_',0xDFF) - -ServiceInstall = Table('ServiceInstall') -ServiceInstall.add_field(1,'ServiceInstall',11592) -ServiceInstall.add_field(2,'Name',3583) -ServiceInstall.add_field(3,'DisplayName',8191) -ServiceInstall.add_field(4,'ServiceType',260) -ServiceInstall.add_field(5,'StartType',260) -ServiceInstall.add_field(6,'ErrorControl',260) -ServiceInstall.add_field(7,'LoadOrderGroup',7679) -ServiceInstall.add_field(8,'Dependencies',7679) -ServiceInstall.add_field(9,'StartName',7679) -ServiceInstall.add_field(10,'Password',7679) -ServiceInstall.add_field(11,'Arguments',7679) -ServiceInstall.add_field(12,'Component_',0xDFF) -ServiceInstall.add_field(13,'Description',8191) - -Shortcut = Table('Shortcut') -Shortcut.add_field(1,'Shortcut',11592) -Shortcut.add_field(2,'Directory_',0xDFF) -Shortcut.add_field(3,'Name',3968) -Shortcut.add_field(4,'Component_',0xDFF) -Shortcut.add_field(5,'Target',3400) -Shortcut.add_field(6,'Arguments',7679) -Shortcut.add_field(7,'Description',8191) -Shortcut.add_field(8,'Hotkey',5378) -Shortcut.add_field(9,'Icon_',7496) -Shortcut.add_field(10,'IconIndex',5378) -Shortcut.add_field(11,'ShowCmd',5378) -Shortcut.add_field(12,'WkDir',7496) - -Signature = Table('Signature') -Signature.add_field(1,'Signature',11592) -Signature.add_field(2,'FileName',3583) -Signature.add_field(3,'MinVersion',7444) -Signature.add_field(4,'MaxVersion',7444) -Signature.add_field(5,'MinSize',4356) -Signature.add_field(6,'MaxSize',4356) -Signature.add_field(7,'MinDate',4356) -Signature.add_field(8,'MaxDate',4356) -Signature.add_field(9,'Languages',7679) - -TextStyle = Table('TextStyle') -TextStyle.add_field(1,'TextStyle',11592) -TextStyle.add_field(2,'FaceName',3360) -TextStyle.add_field(3,'Size',1282) -TextStyle.add_field(4,'Color',4356) -TextStyle.add_field(5,'StyleBits',5378) - -TypeLib = Table('TypeLib') -TypeLib.add_field(1,'LibID',11558) -TypeLib.add_field(2,'Language',9474) -TypeLib.add_field(3,'Component_',0x2DFF) -TypeLib.add_field(4,'Version',4356) -TypeLib.add_field(5,'Description',8064) -TypeLib.add_field(6,'Directory_',0x1DFF) -TypeLib.add_field(7,'Feature_',3366) -TypeLib.add_field(8,'Cost',4356) - -UIText = Table('UIText') -UIText.add_field(1,'Key',11592) -UIText.add_field(2,'Text',8191) - -Upgrade = Table('Upgrade') -Upgrade.add_field(1,'UpgradeCode',11558) -Upgrade.add_field(2,'VersionMin',15636) -Upgrade.add_field(3,'VersionMax',15636) -Upgrade.add_field(4,'Language',15871) -Upgrade.add_field(5,'Attributes',8452) -Upgrade.add_field(6,'Remove',7679) -Upgrade.add_field(7,'ActionProperty',3400) - -Verb = Table('Verb') -Verb.add_field(1,'Extension_',11775) -Verb.add_field(2,'Verb',11552) -Verb.add_field(3,'Sequence',5378) -Verb.add_field(4,'Command',8191) -Verb.add_field(5,'Argument',8191) - -tables=[_Validation, ActionText, AdminExecuteSequence, Condition, AdminUISequence, AdvtExecuteSequence, AdvtUISequence, AppId, AppSearch, Property, BBControl, Billboard, Feature, Binary, BindImage, File, CCPSearch, CheckBox, Class, Component, Icon, ProgId, ComboBox, CompLocator, Complus, Directory, Control, Dialog, ControlCondition, ControlEvent, CreateFolder, CustomAction, DrLocator, DuplicateFile, Environment, Error, EventMapping, Extension, MIME, FeatureComponents, FileSFPCatalog, SFPCatalog, Font, IniFile, IniLocator, InstallExecuteSequence, InstallUISequence, IsolatedComponent, LaunchCondition, ListBox, ListView, LockPermissions, Media, MoveFile, MsiAssembly, MsiAssemblyName, MsiDigitalCertificate, MsiDigitalSignature, MsiFileHash, MsiPatchHeaders, ODBCAttribute, ODBCDriver, ODBCDataSource, ODBCSourceAttribute, ODBCTranslator, Patch, PatchPackage, PublishComponent, RadioButton, Registry, RegLocator, RemoveFile, RemoveIniFile, RemoveRegistry, ReserveCost, SelfReg, ServiceControl, ServiceInstall, Shortcut, Signature, TextStyle, TypeLib, UIText, Upgrade, Verb] - -_Validation_records = [ -(u'_Validation',u'Table',u'N',None, None, None, None, u'Identifier',None, u'Name of table',), -(u'_Validation',u'Column',u'N',None, None, None, None, u'Identifier',None, u'Name of column',), -(u'_Validation',u'Description',u'Y',None, None, None, None, u'Text',None, u'Description of column',), -(u'_Validation',u'Set',u'Y',None, None, None, None, u'Text',None, u'Set of values that are permitted',), -(u'_Validation',u'Category',u'Y',None, None, None, None, None, u'Text;Formatted;Template;Condition;Guid;Path;Version;Language;Identifier;Binary;UpperCase;LowerCase;Filename;Paths;AnyPath;WildCardFilename;RegPath;KeyFormatted;CustomSource;Property;Cabinet;Shortcut;URL',u'String category',), -(u'_Validation',u'KeyColumn',u'Y',1,32,None, None, None, None, u'Column to which foreign key connects',), -(u'_Validation',u'KeyTable',u'Y',None, None, None, None, u'Identifier',None, u'For foreign key, Name of table to which data must link',), -(u'_Validation',u'MaxValue',u'Y',-2147483647,2147483647,None, None, None, None, u'Maximum value allowed',), -(u'_Validation',u'MinValue',u'Y',-2147483647,2147483647,None, None, None, None, u'Minimum value allowed',), -(u'_Validation',u'Nullable',u'N',None, None, None, None, None, u'Y;N;@',u'Whether the column is nullable',), -(u'ActionText',u'Description',u'Y',None, None, None, None, u'Text',None, u'Localized description displayed in progress dialog and log when action is executing.',), -(u'ActionText',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to be described.',), -(u'ActionText',u'Template',u'Y',None, None, None, None, u'Template',None, u'Optional localized format template used to format action data records for display during action execution.',), -(u'AdminExecuteSequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), -(u'AdminExecuteSequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), -(u'AdminExecuteSequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), -(u'Condition',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Expression evaluated to determine if Level in the Feature table is to change.',), -(u'Condition',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Reference to a Feature entry in Feature table.',), -(u'Condition',u'Level',u'N',0,32767,None, None, None, None, u'New selection Level to set in Feature table if Condition evaluates to TRUE.',), -(u'AdminUISequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), -(u'AdminUISequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), -(u'AdminUISequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), -(u'AdvtExecuteSequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), -(u'AdvtExecuteSequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), -(u'AdvtExecuteSequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), -(u'AdvtUISequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), -(u'AdvtUISequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), -(u'AdvtUISequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), -(u'AppId',u'AppId',u'N',None, None, None, None, u'Guid',None, None, ), -(u'AppId',u'ActivateAtStorage',u'Y',0,1,None, None, None, None, None, ), -(u'AppId',u'DllSurrogate',u'Y',None, None, None, None, u'Text',None, None, ), -(u'AppId',u'LocalService',u'Y',None, None, None, None, u'Text',None, None, ), -(u'AppId',u'RemoteServerName',u'Y',None, None, None, None, u'Formatted',None, None, ), -(u'AppId',u'RunAsInteractiveUser',u'Y',0,1,None, None, None, None, None, ), -(u'AppId',u'ServiceParameters',u'Y',None, None, None, None, u'Text',None, None, ), -(u'AppSearch',u'Property',u'N',None, None, None, None, u'Identifier',None, u'The property associated with a Signature',), -(u'AppSearch',u'Signature_',u'N',None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator',1,u'Identifier',None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.',), -(u'Property',u'Property',u'N',None, None, None, None, u'Identifier',None, u'Name of property, uppercase if settable by launcher or loader.',), -(u'Property',u'Value',u'N',None, None, None, None, u'Text',None, u'String value for property. Never null or empty.',), -(u'BBControl',u'Type',u'N',None, None, None, None, u'Identifier',None, u'The type of the control.',), -(u'BBControl',u'Y',u'N',0,32767,None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.',), -(u'BBControl',u'Text',u'Y',None, None, None, None, u'Text',None, u'A string used to set the initial text contained within a control (if appropriate).',), -(u'BBControl',u'BBControl',u'N',None, None, None, None, u'Identifier',None, u'Name of the control. This name must be unique within a billboard, but can repeat on different billboard.',), -(u'BBControl',u'Attributes',u'Y',0,2147483647,None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.',), -(u'BBControl',u'Billboard_',u'N',None, None, u'Billboard',1,u'Identifier',None, u'External key to the Billboard table, name of the billboard.',), -(u'BBControl',u'Height',u'N',0,32767,None, None, None, None, u'Height of the bounding rectangle of the control.',), -(u'BBControl',u'Width',u'N',0,32767,None, None, None, None, u'Width of the bounding rectangle of the control.',), -(u'BBControl',u'X',u'N',0,32767,None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.',), -(u'Billboard',u'Action',u'Y',None, None, None, None, u'Identifier',None, u'The name of an action. The billboard is displayed during the progress messages received from this action.',), -(u'Billboard',u'Billboard',u'N',None, None, None, None, u'Identifier',None, u'Name of the billboard.',), -(u'Billboard',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'An external key to the Feature Table. The billboard is shown only if this feature is being installed.',), -(u'Billboard',u'Ordering',u'Y',0,32767,None, None, None, None, u'A positive integer. If there is more than one billboard corresponding to an action they will be shown in the order defined by this column.',), -(u'Feature',u'Description',u'Y',None, None, None, None, u'Text',None, u'Longer descriptive text describing a visible feature item.',), -(u'Feature',u'Attributes',u'N',None, None, None, None, None, u'0;1;2;4;5;6;8;9;10;16;17;18;20;21;22;24;25;26;32;33;34;36;37;38;48;49;50;52;53;54',u'Feature attributes',), -(u'Feature',u'Feature',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular feature record.',), -(u'Feature',u'Directory_',u'Y',None, None, u'Directory',1,u'UpperCase',None, u'The name of the Directory that can be configured by the UI. A non-null value will enable the browse button.',), -(u'Feature',u'Level',u'N',0,32767,None, None, None, None, u'The install level at which record will be initially selected. An install level of 0 will disable an item and prevent its display.',), -(u'Feature',u'Title',u'Y',None, None, None, None, u'Text',None, u'Short text identifying a visible feature item.',), -(u'Feature',u'Display',u'Y',0,32767,None, None, None, None, u'Numeric sort order, used to force a specific display ordering.',), -(u'Feature',u'Feature_Parent',u'Y',None, None, u'Feature',1,u'Identifier',None, u'Optional key of a parent record in the same table. If the parent is not selected, then the record will not be installed. Null indicates a root item.',), -(u'Binary',u'Name',u'N',None, None, None, None, u'Identifier',None, u'Unique key identifying the binary data.',), -(u'Binary',u'Data',u'N',None, None, None, None, u'Binary',None, u'The unformatted binary data.',), -(u'BindImage',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'The index into the File table. This must be an executable file.',), -(u'BindImage',u'Path',u'Y',None, None, None, None, u'Paths',None, u'A list of ; delimited paths that represent the paths to be searched for the import DLLS. The list is usually a list of properties each enclosed within square brackets [] .',), -(u'File',u'Sequence',u'N',1,32767,None, None, None, None, u'Sequence with respect to the media images; order must track cabinet order.',), -(u'File',u'Attributes',u'Y',0,32767,None, None, None, None, u'Integer containing bit flags representing file attributes (with the decimal value of each bit position in parentheses)',), -(u'File',u'File',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token, must match identifier in cabinet. For uncompressed files, this field is ignored.',), -(u'File',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the file.',), -(u'File',u'FileName',u'N',None, None, None, None, u'Filename',None, u'File name used for installation, may be localized. This may contain a "short name|long name" pair.',), -(u'File',u'FileSize',u'N',0,2147483647,None, None, None, None, u'Size of file in bytes (long integer).',), -(u'File',u'Language',u'Y',None, None, None, None, u'Language',None, u'List of decimal language Ids, comma-separated if more than one.',), -(u'File',u'Version',u'Y',None, None, u'File',1,u'Version',None, u'Version string for versioned files; Blank for unversioned files.',), -(u'CCPSearch',u'Signature_',u'N',None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator',1,u'Identifier',None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.',), -(u'CheckBox',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to the item.',), -(u'CheckBox',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The value string associated with the item.',), -(u'Class',u'Description',u'Y',None, None, None, None, u'Text',None, u'Localized description for the Class.',), -(u'Class',u'Attributes',u'Y',None, 32767,None, None, None, None, u'Class registration attributes.',), -(u'Class',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.',), -(u'Class',u'AppId_',u'Y',None, None, u'AppId',1,u'Guid',None, u'Optional AppID containing DCOM information for associated application (string GUID).',), -(u'Class',u'Argument',u'Y',None, None, None, None, u'Formatted',None, u'optional argument for LocalServers.',), -(u'Class',u'CLSID',u'N',None, None, None, None, u'Guid',None, u'The CLSID of an OLE factory.',), -(u'Class',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.',), -(u'Class',u'Context',u'N',None, None, None, None, u'Identifier',None, u'The numeric server context for this server. CLSCTX_xxxx',), -(u'Class',u'DefInprocHandler',u'Y',None, None, None, None, u'Filename',u'1;2;3',u'Optional default inproc handler. Only optionally provided if Context=CLSCTX_LOCAL_SERVER. Typically "ole32.dll" or "mapi32.dll"',), -(u'Class',u'FileTypeMask',u'Y',None, None, None, None, u'Text',None, u'Optional string containing information for the HKCRthis CLSID) key. If multiple patterns exist, they must be delimited by a semicolon, and numeric subkeys will be generated: 0,1,2...',), -(u'Class',u'Icon_',u'Y',None, None, u'Icon',1,u'Identifier',None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this CLSID. Will be written under the DefaultIcon key.',), -(u'Class',u'IconIndex',u'Y',-32767,32767,None, None, None, None, u'Optional icon index.',), -(u'Class',u'ProgId_Default',u'Y',None, None, u'ProgId',1,u'Text',None, u'Optional ProgId associated with this CLSID.',), -(u'Component',u'Condition',u'Y',None, None, None, None, u'Condition',None, u"A conditional statement that will disable this component if the specified condition evaluates to the 'True' state. If a component is disabled, it will not be installed, regardless of the 'Action' state associated with the component.",), -(u'Component',u'Attributes',u'N',None, None, None, None, None, None, u'Remote execution option, one of irsEnum',), -(u'Component',u'Component',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular component record.',), -(u'Component',u'ComponentId',u'Y',None, None, None, None, u'Guid',None, u'A string GUID unique to this component, version, and language.',), -(u'Component',u'Directory_',u'N',None, None, u'Directory',1,u'Identifier',None, u'Required key of a Directory table record. This is actually a property name whose value contains the actual path, set either by the AppSearch action or with the default setting obtained from the Directory table.',), -(u'Component',u'KeyPath',u'Y',None, None, u'File;Registry;ODBCDataSource',1,u'Identifier',None, u'Either the primary key into the File table, Registry table, or ODBCDataSource table. This extract path is stored when the component is installed, and is used to detect the presence of the component and to return the path to it.',), -(u'Icon',u'Name',u'N',None, None, None, None, u'Identifier',None, u'Primary key. Name of the icon file.',), -(u'Icon',u'Data',u'N',None, None, None, None, u'Binary',None, u'Binary stream. The binary icon data in PE (.DLL or .EXE) or icon (.ICO) format.',), -(u'ProgId',u'Description',u'Y',None, None, None, None, u'Text',None, u'Localized description for the Program identifier.',), -(u'ProgId',u'Icon_',u'Y',None, None, u'Icon',1,u'Identifier',None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this ProgId. Will be written under the DefaultIcon key.',), -(u'ProgId',u'IconIndex',u'Y',-32767,32767,None, None, None, None, u'Optional icon index.',), -(u'ProgId',u'ProgId',u'N',None, None, None, None, u'Text',None, u'The Program Identifier. Primary key.',), -(u'ProgId',u'Class_',u'Y',None, None, u'Class',1,u'Guid',None, u'The CLSID of an OLE factory corresponding to the ProgId.',), -(u'ProgId',u'ProgId_Parent',u'Y',None, None, u'ProgId',1,u'Text',None, u'The Parent Program Identifier. If specified, the ProgId column becomes a version independent prog id.',), -(u'ComboBox',u'Text',u'Y',None, None, None, None, u'Formatted',None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.',), -(u'ComboBox',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this item. All the items tied to the same property become part of the same combobox.',), -(u'ComboBox',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value string associated with this item. Selecting the line will set the associated property to this value.',), -(u'ComboBox',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list.\tThe integers do not have to be consecutive.',), -(u'CompLocator',u'Type',u'Y',0,1,None, None, None, None, u'A boolean value that determines if the registry value is a filename or a directory location.',), -(u'CompLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.',), -(u'CompLocator',u'ComponentId',u'N',None, None, None, None, u'Guid',None, u'A string GUID unique to this component, version, and language.',), -(u'Complus',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the ComPlus component.',), -(u'Complus',u'ExpType',u'Y',0,32767,None, None, None, None, u'ComPlus component attributes.',), -(u'Directory',u'Directory',u'N',None, None, None, None, u'Identifier',None, u'Unique identifier for directory entry, primary key. If a property by this name is defined, it contains the full path to the directory.',), -(u'Directory',u'DefaultDir',u'N',None, None, None, None, u'DefaultDir',None, u"The default sub-path under parent's path.",), -(u'Directory',u'Directory_Parent',u'Y',None, None, u'Directory',1,u'Identifier',None, u'Reference to the entry in this table specifying the default parent directory. A record parented to itself or with a Null parent represents a root of the install tree.',), -(u'Control',u'Type',u'N',None, None, None, None, u'Identifier',None, u'The type of the control.',), -(u'Control',u'Y',u'N',0,32767,None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.',), -(u'Control',u'Text',u'Y',None, None, None, None, u'Formatted',None, u'A string used to set the initial text contained within a control (if appropriate).',), -(u'Control',u'Property',u'Y',None, None, None, None, u'Identifier',None, u'The name of a defined property to be linked to this control. ',), -(u'Control',u'Attributes',u'Y',0,2147483647,None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.',), -(u'Control',u'Height',u'N',0,32767,None, None, None, None, u'Height of the bounding rectangle of the control.',), -(u'Control',u'Width',u'N',0,32767,None, None, None, None, u'Width of the bounding rectangle of the control.',), -(u'Control',u'X',u'N',0,32767,None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.',), -(u'Control',u'Control',u'N',None, None, None, None, u'Identifier',None, u'Name of the control. This name must be unique within a dialog, but can repeat on different dialogs. ',), -(u'Control',u'Control_Next',u'Y',None, None, u'Control',2,u'Identifier',None, u'The name of an other control on the same dialog. This link defines the tab order of the controls. The links have to form one or more cycles!',), -(u'Control',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'External key to the Dialog table, name of the dialog.',), -(u'Control',u'Help',u'Y',None, None, None, None, u'Text',None, u'The help strings used with the button. The text is optional. ',), -(u'Dialog',u'Attributes',u'Y',0,2147483647,None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this dialog.',), -(u'Dialog',u'Height',u'N',0,32767,None, None, None, None, u'Height of the bounding rectangle of the dialog.',), -(u'Dialog',u'Width',u'N',0,32767,None, None, None, None, u'Width of the bounding rectangle of the dialog.',), -(u'Dialog',u'Dialog',u'N',None, None, None, None, u'Identifier',None, u'Name of the dialog.',), -(u'Dialog',u'Control_Cancel',u'Y',None, None, u'Control',2,u'Identifier',None, u'Defines the cancel control. Hitting escape or clicking on the close icon on the dialog is equivalent to pushing this button.',), -(u'Dialog',u'Control_Default',u'Y',None, None, u'Control',2,u'Identifier',None, u'Defines the default control. Hitting return is equivalent to pushing this button.',), -(u'Dialog',u'Control_First',u'N',None, None, u'Control',2,u'Identifier',None, u'Defines the control that has the focus when the dialog is created.',), -(u'Dialog',u'HCentering',u'N',0,100,None, None, None, None, u'Horizontal position of the dialog on a 0-100 scale. 0 means left end, 100 means right end of the screen, 50 center.',), -(u'Dialog',u'Title',u'Y',None, None, None, None, u'Formatted',None, u"A text string specifying the title to be displayed in the title bar of the dialog's window.",), -(u'Dialog',u'VCentering',u'N',0,100,None, None, None, None, u'Vertical position of the dialog on a 0-100 scale. 0 means top end, 100 means bottom end of the screen, 50 center.',), -(u'ControlCondition',u'Action',u'N',None, None, None, None, None, u'Default;Disable;Enable;Hide;Show',u'The desired action to be taken on the specified control.',), -(u'ControlCondition',u'Condition',u'N',None, None, None, None, u'Condition',None, u'A standard conditional statement that specifies under which conditions the action should be triggered.',), -(u'ControlCondition',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'A foreign key to the Dialog table, name of the dialog.',), -(u'ControlCondition',u'Control_',u'N',None, None, u'Control',2,u'Identifier',None, u'A foreign key to the Control table, name of the control.',), -(u'ControlEvent',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'A standard conditional statement that specifies under which conditions an event should be triggered.',), -(u'ControlEvent',u'Ordering',u'Y',0,2147483647,None, None, None, None, u'An integer used to order several events tied to the same control. Can be left blank.',), -(u'ControlEvent',u'Argument',u'N',None, None, None, None, u'Formatted',None, u'A value to be used as a modifier when triggering a particular event.',), -(u'ControlEvent',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'A foreign key to the Dialog table, name of the dialog.',), -(u'ControlEvent',u'Control_',u'N',None, None, u'Control',2,u'Identifier',None, u'A foreign key to the Control table, name of the control',), -(u'ControlEvent',u'Event',u'N',None, None, None, None, u'Formatted',None, u'An identifier that specifies the type of the event that should take place when the user interacts with control specified by the first two entries.',), -(u'CreateFolder',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table.',), -(u'CreateFolder',u'Directory_',u'N',None, None, u'Directory',1,u'Identifier',None, u'Primary key, could be foreign key into the Directory table.',), -(u'CustomAction',u'Type',u'N',1,16383,None, None, None, None, u'The numeric custom action type, consisting of source location, code type, entry, option flags.',), -(u'CustomAction',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Primary key, name of action, normally appears in sequence table unless private use.',), -(u'CustomAction',u'Source',u'Y',None, None, None, None, u'CustomSource',None, u'The table reference of the source of the code.',), -(u'CustomAction',u'Target',u'Y',None, None, None, None, u'Formatted',None, u'Excecution parameter, depends on the type of custom action',), -(u'DrLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature table.',), -(u'DrLocator',u'Path',u'Y',None, None, None, None, u'AnyPath',None, u'The path on the user system. This is a either a subpath below the value of the Parent or a full path. The path may contain properties enclosed within [ ] that will be expanded.',), -(u'DrLocator',u'Depth',u'Y',0,32767,None, None, None, None, u'The depth below the path to which the Signature_ is recursively searched. If absent, the depth is assumed to be 0.',), -(u'DrLocator',u'Parent',u'Y',None, None, None, None, u'Identifier',None, u'The parent file signature. It is also a foreign key in the Signature table. If null and the Path column does not expand to a full path, then all the fixed drives of the user system are searched using the Path.',), -(u'DuplicateFile',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Foreign key referencing the source file to be duplicated.',), -(u'DuplicateFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the duplicate file.',), -(u'DuplicateFile',u'DestFolder',u'Y',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full pathname to a destination folder.',), -(u'DuplicateFile',u'DestName',u'Y',None, None, None, None, u'Filename',None, u'Filename to be given to the duplicate file.',), -(u'DuplicateFile',u'FileKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular file entry',), -(u'Environment',u'Name',u'N',None, None, None, None, u'Text',None, u'The name of the environmental value.',), -(u'Environment',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The value to set in the environmental settings.',), -(u'Environment',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the installing of the environmental value.',), -(u'Environment',u'Environment',u'N',None, None, None, None, u'Identifier',None, u'Unique identifier for the environmental variable setting',), -(u'Error',u'Error',u'N',0,32767,None, None, None, None, u'Integer error number, obtained from header file IError(...) macros.',), -(u'Error',u'Message',u'Y',None, None, None, None, u'Template',None, u'Error formatting template, obtained from user ed. or localizers.',), -(u'EventMapping',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'A foreign key to the Dialog table, name of the Dialog.',), -(u'EventMapping',u'Control_',u'N',None, None, u'Control',2,u'Identifier',None, u'A foreign key to the Control table, name of the control.',), -(u'EventMapping',u'Event',u'N',None, None, None, None, u'Identifier',None, u'An identifier that specifies the type of the event that the control subscribes to.',), -(u'EventMapping',u'Attribute',u'N',None, None, None, None, u'Identifier',None, u'The name of the control attribute, that is set when this event is received.',), -(u'Extension',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.',), -(u'Extension',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.',), -(u'Extension',u'Extension',u'N',None, None, None, None, u'Text',None, u'The extension associated with the table row.',), -(u'Extension',u'MIME_',u'Y',None, None, u'MIME',1,u'Text',None, u'Optional Context identifier, typically "type/format" associated with the extension',), -(u'Extension',u'ProgId_',u'Y',None, None, u'ProgId',1,u'Text',None, u'Optional ProgId associated with this extension.',), -(u'MIME',u'CLSID',u'Y',None, None, None, None, u'Guid',None, u'Optional associated CLSID.',), -(u'MIME',u'ContentType',u'N',None, None, None, None, u'Text',None, u'Primary key. Context identifier, typically "type/format".',), -(u'MIME',u'Extension_',u'N',None, None, u'Extension',1,u'Text',None, u'Optional associated extension (without dot)',), -(u'FeatureComponents',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Foreign key into Feature table.',), -(u'FeatureComponents',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into Component table.',), -(u'FileSFPCatalog',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'File associated with the catalog',), -(u'FileSFPCatalog',u'SFPCatalog_',u'N',None, None, u'SFPCatalog',1,u'Filename',None, u'Catalog associated with the file',), -(u'SFPCatalog',u'SFPCatalog',u'N',None, None, None, None, u'Filename',None, u'File name for the catalog.',), -(u'SFPCatalog',u'Catalog',u'N',None, None, None, None, u'Binary',None, u'SFP Catalog',), -(u'SFPCatalog',u'Dependency',u'Y',None, None, None, None, u'Formatted',None, u'Parent catalog - only used by SFP',), -(u'Font',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Primary key, foreign key into File table referencing font file.',), -(u'Font',u'FontTitle',u'Y',None, None, None, None, u'Text',None, u'Font name.',), -(u'IniFile',u'Action',u'N',None, None, None, None, None, u'0;1;3',u'The type of modification to be made, one of iifEnum',), -(u'IniFile',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value to be written.',), -(u'IniFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the installing of the .INI value.',), -(u'IniFile',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The .INI file name in which to write the information',), -(u'IniFile',u'IniFile',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), -(u'IniFile',u'DirProperty',u'Y',None, None, None, None, u'Identifier',None, u'Foreign key into the Directory table denoting the directory where the .INI file is.',), -(u'IniFile',u'Key',u'N',None, None, None, None, u'Formatted',None, u'The .INI file key below Section.',), -(u'IniFile',u'Section',u'N',None, None, None, None, u'Formatted',None, u'The .INI file Section.',), -(u'IniLocator',u'Type',u'Y',0,2,None, None, None, None, u'An integer value that determines if the .INI value read is a filename or a directory location or to be used as is w/o interpretation.',), -(u'IniLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.',), -(u'IniLocator',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The .INI file name.',), -(u'IniLocator',u'Key',u'N',None, None, None, None, u'Text',None, u'Key value (followed by an equals sign in INI file).',), -(u'IniLocator',u'Section',u'N',None, None, None, None, u'Text',None, u'Section name within in file (within square brackets in INI file).',), -(u'IniLocator',u'Field',u'Y',0,32767,None, None, None, None, u'The field in the .INI line. If Field is null or 0 the entire line is read.',), -(u'InstallExecuteSequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), -(u'InstallExecuteSequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), -(u'InstallExecuteSequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), -(u'InstallUISequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), -(u'InstallUISequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), -(u'InstallUISequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), -(u'IsolatedComponent',u'Component_Application',u'N',None, None, u'Component',1,u'Identifier',None, u'Key to Component table item for application',), -(u'IsolatedComponent',u'Component_Shared',u'N',None, None, u'Component',1,u'Identifier',None, u'Key to Component table item to be isolated',), -(u'LaunchCondition',u'Description',u'N',None, None, None, None, u'Formatted',None, u'Localizable text to display when condition fails and install must abort.',), -(u'LaunchCondition',u'Condition',u'N',None, None, None, None, u'Condition',None, u'Expression which must evaluate to TRUE in order for install to commence.',), -(u'ListBox',u'Text',u'Y',None, None, None, None, u'Text',None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.',), -(u'ListBox',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listbox.',), -(u'ListBox',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value string associated with this item. Selecting the line will set the associated property to this value.',), -(u'ListBox',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.',), -(u'ListView',u'Text',u'Y',None, None, None, None, u'Text',None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.',), -(u'ListView',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listview.',), -(u'ListView',u'Value',u'N',None, None, None, None, u'Identifier',None, u'The value string associated with this item. Selecting the line will set the associated property to this value.',), -(u'ListView',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.',), -(u'ListView',u'Binary_',u'Y',None, None, u'Binary',1,u'Identifier',None, u'The name of the icon to be displayed with the icon. The binary information is looked up from the Binary Table.',), -(u'LockPermissions',u'Table',u'N',None, None, None, None, u'Identifier',u'Directory;File;Registry',u'Reference to another table name',), -(u'LockPermissions',u'Domain',u'Y',None, None, None, None, u'Formatted',None, u'Domain name for user whose permissions are being set. (usually a property)',), -(u'LockPermissions',u'LockObject',u'N',None, None, None, None, u'Identifier',None, u'Foreign key into Registry or File table',), -(u'LockPermissions',u'Permission',u'Y',-2147483647,2147483647,None, None, None, None, u'Permission Access mask. Full Control = 268435456 (GENERIC_ALL = 0x10000000)',), -(u'LockPermissions',u'User',u'N',None, None, None, None, u'Formatted',None, u'User for permissions to be set. (usually a property)',), -(u'Media',u'Source',u'Y',None, None, None, None, u'Property',None, u'The property defining the location of the cabinet file.',), -(u'Media',u'Cabinet',u'Y',None, None, None, None, u'Cabinet',None, u'If some or all of the files stored on the media are compressed in a cabinet, the name of that cabinet.',), -(u'Media',u'DiskId',u'N',1,32767,None, None, None, None, u'Primary key, integer to determine sort order for table.',), -(u'Media',u'DiskPrompt',u'Y',None, None, None, None, u'Text',None, u'Disk name: the visible text actually printed on the disk. This will be used to prompt the user when this disk needs to be inserted.',), -(u'Media',u'LastSequence',u'N',0,32767,None, None, None, None, u'File sequence number for the last file for this media.',), -(u'Media',u'VolumeLabel',u'Y',None, None, None, None, u'Text',None, u'The label attributed to the volume.',), -(u'ModuleComponents',u'Component',u'N',None, None, u'Component',1,u'Identifier',None, u'Component contained in the module.',), -(u'ModuleComponents',u'Language',u'N',None, None, u'ModuleSignature',2,None, None, u'Default language ID for module (may be changed by transform).',), -(u'ModuleComponents',u'ModuleID',u'N',None, None, u'ModuleSignature',1,u'Identifier',None, u'Module containing the component.',), -(u'ModuleSignature',u'Language',u'N',None, None, None, None, None, None, u'Default decimal language of module.',), -(u'ModuleSignature',u'Version',u'N',None, None, None, None, u'Version',None, u'Version of the module.',), -(u'ModuleSignature',u'ModuleID',u'N',None, None, None, None, u'Identifier',None, u'Module identifier (String.GUID).',), -(u'ModuleDependency',u'ModuleID',u'N',None, None, u'ModuleSignature',1,u'Identifier',None, u'Module requiring the dependency.',), -(u'ModuleDependency',u'ModuleLanguage',u'N',None, None, u'ModuleSignature',2,None, None, u'Language of module requiring the dependency.',), -(u'ModuleDependency',u'RequiredID',u'N',None, None, None, None, None, None, u'String.GUID of required module.',), -(u'ModuleDependency',u'RequiredLanguage',u'N',None, None, None, None, None, None, u'LanguageID of the required module.',), -(u'ModuleDependency',u'RequiredVersion',u'Y',None, None, None, None, u'Version',None, u'Version of the required version.',), -(u'ModuleExclusion',u'ModuleID',u'N',None, None, u'ModuleSignature',1,u'Identifier',None, u'String.GUID of module with exclusion requirement.',), -(u'ModuleExclusion',u'ModuleLanguage',u'N',None, None, u'ModuleSignature',2,None, None, u'LanguageID of module with exclusion requirement.',), -(u'ModuleExclusion',u'ExcludedID',u'N',None, None, None, None, None, None, u'String.GUID of excluded module.',), -(u'ModuleExclusion',u'ExcludedLanguage',u'N',None, None, None, None, None, None, u'Language of excluded module.',), -(u'ModuleExclusion',u'ExcludedMaxVersion',u'Y',None, None, None, None, u'Version',None, u'Maximum version of excluded module.',), -(u'ModuleExclusion',u'ExcludedMinVersion',u'Y',None, None, None, None, u'Version',None, u'Minimum version of excluded module.',), -(u'MoveFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'If this component is not "selected" for installation or removal, no action will be taken on the associated MoveFile entry',), -(u'MoveFile',u'DestFolder',u'N',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory',), -(u'MoveFile',u'DestName',u'Y',None, None, None, None, u'Filename',None, u'Name to be given to the original file after it is moved or copied. If blank, the destination file will be given the same name as the source file',), -(u'MoveFile',u'FileKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key that uniquely identifies a particular MoveFile record',), -(u'MoveFile',u'Options',u'N',0,1,None, None, None, None, u'Integer value specifying the MoveFile operating mode, one of imfoEnum',), -(u'MoveFile',u'SourceFolder',u'Y',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full path to the source directory',), -(u'MoveFile',u'SourceName',u'Y',None, None, None, None, u'Text',None, u"Name of the source file(s) to be moved or copied. Can contain the '*' or '?' wildcards.",), -(u'MsiAssembly',u'Attributes',u'Y',None, None, None, None, None, None, u'Assembly attributes',), -(u'MsiAssembly',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Foreign key into Feature table.',), -(u'MsiAssembly',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into Component table.',), -(u'MsiAssembly',u'File_Application',u'Y',None, None, u'File',1,u'Identifier',None, u'Foreign key into File table, denoting the application context for private assemblies. Null for global assemblies.',), -(u'MsiAssembly',u'File_Manifest',u'Y',None, None, u'File',1,u'Identifier',None, u'Foreign key into the File table denoting the manifest file for the assembly.',), -(u'MsiAssemblyName',u'Name',u'N',None, None, None, None, u'Text',None, u'The name part of the name-value pairs for the assembly name.',), -(u'MsiAssemblyName',u'Value',u'N',None, None, None, None, u'Text',None, u'The value part of the name-value pairs for the assembly name.',), -(u'MsiAssemblyName',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into Component table.',), -(u'MsiDigitalCertificate',u'CertData',u'N',None, None, None, None, u'Binary',None, u'A certificate context blob for a signer certificate',), -(u'MsiDigitalCertificate',u'DigitalCertificate',u'N',None, None, None, None, u'Identifier',None, u'A unique identifier for the row',), -(u'MsiDigitalSignature',u'Table',u'N',None, None, None, None, None, u'Media',u'Reference to another table name (only Media table is supported)',), -(u'MsiDigitalSignature',u'DigitalCertificate_',u'N',None, None, u'MsiDigitalCertificate',1,u'Identifier',None, u'Foreign key to MsiDigitalCertificate table identifying the signer certificate',), -(u'MsiDigitalSignature',u'Hash',u'Y',None, None, None, None, u'Binary',None, u'The encoded hash blob from the digital signature',), -(u'MsiDigitalSignature',u'SignObject',u'N',None, None, None, None, u'Text',None, u'Foreign key to Media table',), -(u'MsiFileHash',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Primary key, foreign key into File table referencing file with this hash',), -(u'MsiFileHash',u'Options',u'N',0,32767,None, None, None, None, u'Various options and attributes for this hash.',), -(u'MsiFileHash',u'HashPart1',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), -(u'MsiFileHash',u'HashPart2',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), -(u'MsiFileHash',u'HashPart3',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), -(u'MsiFileHash',u'HashPart4',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), -(u'MsiPatchHeaders',u'StreamRef',u'N',None, None, None, None, u'Identifier',None, u'Primary key. A unique identifier for the row.',), -(u'MsiPatchHeaders',u'Header',u'N',None, None, None, None, u'Binary',None, u'Binary stream. The patch header, used for patch validation.',), -(u'ODBCAttribute',u'Value',u'Y',None, None, None, None, u'Text',None, u'Value for ODBC driver attribute',), -(u'ODBCAttribute',u'Attribute',u'N',None, None, None, None, u'Text',None, u'Name of ODBC driver attribute',), -(u'ODBCAttribute',u'Driver_',u'N',None, None, u'ODBCDriver',1,u'Identifier',None, u'Reference to ODBC driver in ODBCDriver table',), -(u'ODBCDriver',u'Description',u'N',None, None, None, None, u'Text',None, u'Text used as registered name for driver, non-localized',), -(u'ODBCDriver',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Reference to key driver file',), -(u'ODBCDriver',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reference to associated component',), -(u'ODBCDriver',u'Driver',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized.internal token for driver',), -(u'ODBCDriver',u'File_Setup',u'Y',None, None, u'File',1,u'Identifier',None, u'Optional reference to key driver setup DLL',), -(u'ODBCDataSource',u'Description',u'N',None, None, None, None, u'Text',None, u'Text used as registered name for data source',), -(u'ODBCDataSource',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reference to associated component',), -(u'ODBCDataSource',u'DataSource',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized.internal token for data source',), -(u'ODBCDataSource',u'DriverDescription',u'N',None, None, None, None, u'Text',None, u'Reference to driver description, may be existing driver',), -(u'ODBCDataSource',u'Registration',u'N',0,1,None, None, None, None, u'Registration option: 0=machine, 1=user, others t.b.d.',), -(u'ODBCSourceAttribute',u'Value',u'Y',None, None, None, None, u'Text',None, u'Value for ODBC data source attribute',), -(u'ODBCSourceAttribute',u'Attribute',u'N',None, None, None, None, u'Text',None, u'Name of ODBC data source attribute',), -(u'ODBCSourceAttribute',u'DataSource_',u'N',None, None, u'ODBCDataSource',1,u'Identifier',None, u'Reference to ODBC data source in ODBCDataSource table',), -(u'ODBCTranslator',u'Description',u'N',None, None, None, None, u'Text',None, u'Text used as registered name for translator',), -(u'ODBCTranslator',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Reference to key translator file',), -(u'ODBCTranslator',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reference to associated component',), -(u'ODBCTranslator',u'File_Setup',u'Y',None, None, u'File',1,u'Identifier',None, u'Optional reference to key translator setup DLL',), -(u'ODBCTranslator',u'Translator',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized.internal token for translator',), -(u'Patch',u'Sequence',u'N',0,32767,None, None, None, None, u'Primary key, sequence with respect to the media images; order must track cabinet order.',), -(u'Patch',u'Attributes',u'N',0,32767,None, None, None, None, u'Integer containing bit flags representing patch attributes',), -(u'Patch',u'File_',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token, foreign key to File table, must match identifier in cabinet.',), -(u'Patch',u'Header',u'Y',None, None, None, None, u'Binary',None, u'Binary stream. The patch header, used for patch validation.',), -(u'Patch',u'PatchSize',u'N',0,2147483647,None, None, None, None, u'Size of patch in bytes (long integer).',), -(u'Patch',u'StreamRef_',u'Y',None, None, None, None, u'Identifier',None, u'Identifier. Foreign key to the StreamRef column of the MsiPatchHeaders table.',), -(u'PatchPackage',u'Media_',u'N',0,32767,None, None, None, None, u'Foreign key to DiskId column of Media table. Indicates the disk containing the patch package.',), -(u'PatchPackage',u'PatchId',u'N',None, None, None, None, u'Guid',None, u'A unique string GUID representing this patch.',), -(u'PublishComponent',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Foreign key into the Feature table.',), -(u'PublishComponent',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table.',), -(u'PublishComponent',u'ComponentId',u'N',None, None, None, None, u'Guid',None, u'A string GUID that represents the component id that will be requested by the alien product.',), -(u'PublishComponent',u'AppData',u'Y',None, None, None, None, u'Text',None, u'This is localisable Application specific data that can be associated with a Qualified Component.',), -(u'PublishComponent',u'Qualifier',u'N',None, None, None, None, u'Text',None, u'This is defined only when the ComponentId column is an Qualified Component Id. This is the Qualifier for ProvideComponentIndirect.',), -(u'RadioButton',u'Y',u'N',0,32767,None, None, None, None, u'The vertical coordinate of the upper left corner of the bounding rectangle of the radio button.',), -(u'RadioButton',u'Text',u'Y',None, None, None, None, u'Text',None, u'The visible title to be assigned to the radio button.',), -(u'RadioButton',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this radio button. All the buttons tied to the same property become part of the same group.',), -(u'RadioButton',u'Height',u'N',0,32767,None, None, None, None, u'The height of the button.',), -(u'RadioButton',u'Width',u'N',0,32767,None, None, None, None, u'The width of the button.',), -(u'RadioButton',u'X',u'N',0,32767,None, None, None, None, u'The horizontal coordinate of the upper left corner of the bounding rectangle of the radio button.',), -(u'RadioButton',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value string associated with this button. Selecting the button will set the associated property to this value.',), -(u'RadioButton',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.',), -(u'RadioButton',u'Help',u'Y',None, None, None, None, u'Text',None, u'The help strings used with the button. The text is optional.',), -(u'Registry',u'Name',u'Y',None, None, None, None, u'Formatted',None, u'The registry value name.',), -(u'Registry',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The registry value.',), -(u'Registry',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the installing of the registry value.',), -(u'Registry',u'Key',u'N',None, None, None, None, u'RegPath',None, u'The key for the registry value.',), -(u'Registry',u'Registry',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), -(u'Registry',u'Root',u'N',-1,3,None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.',), -(u'RegLocator',u'Name',u'Y',None, None, None, None, u'Formatted',None, u'The registry value name.',), -(u'RegLocator',u'Type',u'Y',0,18,None, None, None, None, u'An integer value that determines if the registry value is a filename or a directory location or to be used as is w/o interpretation.',), -(u'RegLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table. If the type is 0, the registry values refers a directory, and _Signature is not a foreign key.',), -(u'RegLocator',u'Key',u'N',None, None, None, None, u'RegPath',None, u'The key for the registry value.',), -(u'RegLocator',u'Root',u'N',0,3,None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.',), -(u'RemoveFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the file to be removed.',), -(u'RemoveFile',u'FileKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular file entry',), -(u'RemoveFile',u'FileName',u'Y',None, None, None, None, u'WildCardFilename',None, u'Name of the file to be removed.',), -(u'RemoveFile',u'DirProperty',u'N',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full pathname to the folder of the file to be removed.',), -(u'RemoveFile',u'InstallMode',u'N',None, None, None, None, None, u'1;2;3',u'Installation option, one of iimEnum.',), -(u'RemoveIniFile',u'Action',u'N',None, None, None, None, None, u'2;4',u'The type of modification to be made, one of iifEnum.',), -(u'RemoveIniFile',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The value to be deleted. The value is required when Action is iifIniRemoveTag',), -(u'RemoveIniFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the deletion of the .INI value.',), -(u'RemoveIniFile',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The .INI file name in which to delete the information',), -(u'RemoveIniFile',u'DirProperty',u'Y',None, None, None, None, u'Identifier',None, u'Foreign key into the Directory table denoting the directory where the .INI file is.',), -(u'RemoveIniFile',u'Key',u'N',None, None, None, None, u'Formatted',None, u'The .INI file key below Section.',), -(u'RemoveIniFile',u'Section',u'N',None, None, None, None, u'Formatted',None, u'The .INI file Section.',), -(u'RemoveIniFile',u'RemoveIniFile',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), -(u'RemoveRegistry',u'Name',u'Y',None, None, None, None, u'Formatted',None, u'The registry value name.',), -(u'RemoveRegistry',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the deletion of the registry value.',), -(u'RemoveRegistry',u'Key',u'N',None, None, None, None, u'RegPath',None, u'The key for the registry value.',), -(u'RemoveRegistry',u'Root',u'N',-1,3,None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum',), -(u'RemoveRegistry',u'RemoveRegistry',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), -(u'ReserveCost',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reserve a specified amount of space if this component is to be installed.',), -(u'ReserveCost',u'ReserveFolder',u'Y',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory',), -(u'ReserveCost',u'ReserveKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key that uniquely identifies a particular ReserveCost record',), -(u'ReserveCost',u'ReserveLocal',u'N',0,2147483647,None, None, None, None, u'Disk space to reserve if linked component is installed locally.',), -(u'ReserveCost',u'ReserveSource',u'N',0,2147483647,None, None, None, None, u'Disk space to reserve if linked component is installed to run from the source location.',), -(u'SelfReg',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Foreign key into the File table denoting the module that needs to be registered.',), -(u'SelfReg',u'Cost',u'Y',0,32767,None, None, None, None, u'The cost of registering the module.',), -(u'ServiceControl',u'Name',u'N',None, None, None, None, u'Formatted',None, u'Name of a service. /, \\, comma and space are invalid',), -(u'ServiceControl',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table that controls the startup of the service',), -(u'ServiceControl',u'Event',u'N',0,187,None, None, None, None, u'Bit field: Install: 0x1 = Start, 0x2 = Stop, 0x8 = Delete, Uninstall: 0x10 = Start, 0x20 = Stop, 0x80 = Delete',), -(u'ServiceControl',u'ServiceControl',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), -(u'ServiceControl',u'Arguments',u'Y',None, None, None, None, u'Formatted',None, u'Arguments for the service. Separate by [~].',), -(u'ServiceControl',u'Wait',u'Y',0,1,None, None, None, None, u'Boolean for whether to wait for the service to fully start',), -(u'ServiceInstall',u'Name',u'N',None, None, None, None, u'Formatted',None, u'Internal Name of the Service',), -(u'ServiceInstall',u'Description',u'Y',None, None, None, None, u'Text',None, u'Description of service.',), -(u'ServiceInstall',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table that controls the startup of the service',), -(u'ServiceInstall',u'Arguments',u'Y',None, None, None, None, u'Formatted',None, u'Arguments to include in every start of the service, passed to WinMain',), -(u'ServiceInstall',u'ServiceInstall',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), -(u'ServiceInstall',u'Dependencies',u'Y',None, None, None, None, u'Formatted',None, u'Other services this depends on to start. Separate by [~], and end with [~][~]',), -(u'ServiceInstall',u'DisplayName',u'Y',None, None, None, None, u'Formatted',None, u'External Name of the Service',), -(u'ServiceInstall',u'ErrorControl',u'N',-2147483647,2147483647,None, None, None, None, u'Severity of error if service fails to start',), -(u'ServiceInstall',u'LoadOrderGroup',u'Y',None, None, None, None, u'Formatted',None, u'LoadOrderGroup',), -(u'ServiceInstall',u'Password',u'Y',None, None, None, None, u'Formatted',None, u'password to run service with. (with StartName)',), -(u'ServiceInstall',u'ServiceType',u'N',-2147483647,2147483647,None, None, None, None, u'Type of the service',), -(u'ServiceInstall',u'StartName',u'Y',None, None, None, None, u'Formatted',None, u'User or object name to run service as',), -(u'ServiceInstall',u'StartType',u'N',0,4,None, None, None, None, u'Type of the service',), -(u'Shortcut',u'Name',u'N',None, None, None, None, u'Filename',None, u'The name of the shortcut to be created.',), -(u'Shortcut',u'Description',u'Y',None, None, None, None, u'Text',None, u'The description for the shortcut.',), -(u'Shortcut',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table denoting the component whose selection gates the shortcut creation/deletion.',), -(u'Shortcut',u'Icon_',u'Y',None, None, u'Icon',1,u'Identifier',None, u'Foreign key into the File table denoting the external icon file for the shortcut.',), -(u'Shortcut',u'IconIndex',u'Y',-32767,32767,None, None, None, None, u'The icon index for the shortcut.',), -(u'Shortcut',u'Directory_',u'N',None, None, u'Directory',1,u'Identifier',None, u'Foreign key into the Directory table denoting the directory where the shortcut file is created.',), -(u'Shortcut',u'Target',u'N',None, None, None, None, u'Shortcut',None, u'The shortcut target. This is usually a property that is expanded to a file or a folder that the shortcut points to.',), -(u'Shortcut',u'Arguments',u'Y',None, None, None, None, u'Formatted',None, u'The command-line arguments for the shortcut.',), -(u'Shortcut',u'Shortcut',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), -(u'Shortcut',u'Hotkey',u'Y',0,32767,None, None, None, None, u'The hotkey for the shortcut. It has the virtual-key code for the key in the low-order byte, and the modifier flags in the high-order byte. ',), -(u'Shortcut',u'ShowCmd',u'Y',None, None, None, None, None, u'1;3;7',u'The show command for the application window.The following values may be used.',), -(u'Shortcut',u'WkDir',u'Y',None, None, None, None, u'Identifier',None, u'Name of property defining location of working directory.',), -(u'Signature',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The name of the file. This may contain a "short name|long name" pair.',), -(u'Signature',u'Signature',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature represents a unique file signature.',), -(u'Signature',u'Languages',u'Y',None, None, None, None, u'Language',None, u'The languages supported by the file.',), -(u'Signature',u'MaxDate',u'Y',0,2147483647,None, None, None, None, u'The maximum creation date of the file.',), -(u'Signature',u'MaxSize',u'Y',0,2147483647,None, None, None, None, u'The maximum size of the file. ',), -(u'Signature',u'MaxVersion',u'Y',None, None, None, None, u'Text',None, u'The maximum version of the file.',), -(u'Signature',u'MinDate',u'Y',0,2147483647,None, None, None, None, u'The minimum creation date of the file.',), -(u'Signature',u'MinSize',u'Y',0,2147483647,None, None, None, None, u'The minimum size of the file.',), -(u'Signature',u'MinVersion',u'Y',None, None, None, None, u'Text',None, u'The minimum version of the file.',), -(u'TextStyle',u'TextStyle',u'N',None, None, None, None, u'Identifier',None, u'Name of the style. The primary key of this table. This name is embedded in the texts to indicate a style change.',), -(u'TextStyle',u'Color',u'Y',0,16777215,None, None, None, None, u'A long integer indicating the color of the string in the RGB format (Red, Green, Blue each 0-255, RGB = R + 256*G + 256^2*B).',), -(u'TextStyle',u'FaceName',u'N',None, None, None, None, u'Text',None, u'A string indicating the name of the font used. Required. The string must be at most 31 characters long.',), -(u'TextStyle',u'Size',u'N',0,32767,None, None, None, None, u'The size of the font used. This size is given in our units (1/12 of the system font height). Assuming that the system font is set to 12 point size, this is equivalent to the point size.',), -(u'TextStyle',u'StyleBits',u'Y',0,15,None, None, None, None, u'A combination of style bits.',), -(u'TypeLib',u'Description',u'Y',None, None, None, None, u'Text',None, None, ), -(u'TypeLib',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the type library to be operational.',), -(u'TypeLib',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.',), -(u'TypeLib',u'Directory_',u'Y',None, None, u'Directory',1,u'Identifier',None, u'Optional. The foreign key into the Directory table denoting the path to the help file for the type library.',), -(u'TypeLib',u'Language',u'N',0,32767,None, None, None, None, u'The language of the library.',), -(u'TypeLib',u'Version',u'Y',0,16777215,None, None, None, None, u'The version of the library. The minor version is in the lower 8 bits of the integer. The major version is in the next 16 bits. ',), -(u'TypeLib',u'Cost',u'Y',0,2147483647,None, None, None, None, u'The cost associated with the registration of the typelib. This column is currently optional.',), -(u'TypeLib',u'LibID',u'N',None, None, None, None, u'Guid',None, u'The GUID that represents the library.',), -(u'UIText',u'Text',u'Y',None, None, None, None, u'Text',None, u'The localized version of the string.',), -(u'UIText',u'Key',u'N',None, None, None, None, u'Identifier',None, u'A unique key that identifies the particular string.',), -(u'Upgrade',u'Attributes',u'N',0,2147483647,None, None, None, None, u'The attributes of this product set.',), -(u'Upgrade',u'Language',u'Y',None, None, None, None, u'Language',None, u'A comma-separated list of languages for either products in this set or products not in this set.',), -(u'Upgrade',u'ActionProperty',u'N',None, None, None, None, u'UpperCase',None, u'The property to set when a product in this set is found.',), -(u'Upgrade',u'Remove',u'Y',None, None, None, None, u'Formatted',None, u'The list of features to remove when uninstalling a product from this set. The default is "ALL".',), -(u'Upgrade',u'UpgradeCode',u'N',None, None, None, None, u'Guid',None, u'The UpgradeCode GUID belonging to the products in this set.',), -(u'Upgrade',u'VersionMax',u'Y',None, None, None, None, u'Text',None, u'The maximum ProductVersion of the products in this set. The set may or may not include products with this particular version.',), -(u'Upgrade',u'VersionMin',u'Y',None, None, None, None, u'Text',None, u'The minimum ProductVersion of the products in this set. The set may or may not include products with this particular version.',), -(u'Verb',u'Sequence',u'Y',0,32767,None, None, None, None, u'Order within the verbs for a particular extension. Also used simply to specify the default verb.',), -(u'Verb',u'Argument',u'Y',None, None, None, None, u'Formatted',None, u'Optional value for the command arguments.',), -(u'Verb',u'Extension_',u'N',None, None, u'Extension',1,u'Text',None, u'The extension associated with the table row.',), -(u'Verb',u'Verb',u'N',None, None, None, None, u'Text',None, u'The verb for the command.',), -(u'Verb',u'Command',u'Y',None, None, None, None, u'Formatted',None, u'The command text.',), -] diff --git a/Tools/msi/sequence.py b/Tools/msi/sequence.py deleted file mode 100644 --- a/Tools/msi/sequence.py +++ /dev/null @@ -1,126 +0,0 @@ -AdminExecuteSequence = [ -(u'InstallInitialize', None, 1500), -(u'InstallFinalize', None, 6600), -(u'InstallFiles', None, 4000), -(u'InstallAdminPackage', None, 3900), -(u'FileCost', None, 900), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'InstallValidate', None, 1400), -] - -AdminUISequence = [ -(u'FileCost', None, 900), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'ExecuteAction', None, 1300), -(u'ExitDialog', None, -1), -(u'FatalError', None, -3), -(u'UserExit', None, -2), -] - -AdvtExecuteSequence = [ -(u'InstallInitialize', None, 1500), -(u'InstallFinalize', None, 6600), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'InstallValidate', None, 1400), -(u'CreateShortcuts', None, 4500), -(u'MsiPublishAssemblies', None, 6250), -(u'PublishComponents', None, 6200), -(u'PublishFeatures', None, 6300), -(u'PublishProduct', None, 6400), -(u'RegisterClassInfo', None, 4600), -(u'RegisterExtensionInfo', None, 4700), -(u'RegisterMIMEInfo', None, 4900), -(u'RegisterProgIdInfo', None, 4800), -] - -InstallExecuteSequence = [ -(u'InstallInitialize', None, 1500), -(u'InstallFinalize', None, 6600), -(u'InstallFiles', None, 4000), -(u'FileCost', None, 900), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'InstallValidate', None, 1400), -(u'CreateShortcuts', None, 4500), -(u'MsiPublishAssemblies', None, 6250), -(u'PublishComponents', None, 6200), -(u'PublishFeatures', None, 6300), -(u'PublishProduct', None, 6400), -(u'RegisterClassInfo', None, 4600), -(u'RegisterExtensionInfo', None, 4700), -(u'RegisterMIMEInfo', None, 4900), -(u'RegisterProgIdInfo', None, 4800), -(u'AllocateRegistrySpace', u'NOT Installed', 1550), -(u'AppSearch', None, 400), -(u'BindImage', None, 4300), -(u'CCPSearch', u'NOT Installed', 500), -(u'CreateFolders', None, 3700), -(u'DeleteServices', u'VersionNT', 2000), -(u'DuplicateFiles', None, 4210), -(u'FindRelatedProducts', None, 200), -(u'InstallODBC', None, 5400), -(u'InstallServices', u'VersionNT', 5800), -(u'IsolateComponents', None, 950), -(u'LaunchConditions', None, 100), -(u'MigrateFeatureStates', None, 1200), -(u'MoveFiles', None, 3800), -(u'PatchFiles', None, 4090), -(u'ProcessComponents', None, 1600), -(u'RegisterComPlus', None, 5700), -(u'RegisterFonts', None, 5300), -(u'RegisterProduct', None, 6100), -(u'RegisterTypeLibraries', None, 5500), -(u'RegisterUser', None, 6000), -(u'RemoveDuplicateFiles', None, 3400), -(u'RemoveEnvironmentStrings', None, 3300), -(u'RemoveExistingProducts', None, 6700), -(u'RemoveFiles', None, 3500), -(u'RemoveFolders', None, 3600), -(u'RemoveIniValues', None, 3100), -(u'RemoveODBC', None, 2400), -(u'RemoveRegistryValues', None, 2600), -(u'RemoveShortcuts', None, 3200), -(u'RMCCPSearch', u'NOT Installed', 600), -(u'SelfRegModules', None, 5600), -(u'SelfUnregModules', None, 2200), -(u'SetODBCFolders', None, 1100), -(u'StartServices', u'VersionNT', 5900), -(u'StopServices', u'VersionNT', 1900), -(u'MsiUnpublishAssemblies', None, 1750), -(u'UnpublishComponents', None, 1700), -(u'UnpublishFeatures', None, 1800), -(u'UnregisterClassInfo', None, 2700), -(u'UnregisterComPlus', None, 2100), -(u'UnregisterExtensionInfo', None, 2800), -(u'UnregisterFonts', None, 2500), -(u'UnregisterMIMEInfo', None, 3000), -(u'UnregisterProgIdInfo', None, 2900), -(u'UnregisterTypeLibraries', None, 2300), -(u'ValidateProductID', None, 700), -(u'WriteEnvironmentStrings', None, 5200), -(u'WriteIniValues', None, 5100), -(u'WriteRegistryValues', None, 5000), -] - -InstallUISequence = [ -(u'FileCost', None, 900), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'ExecuteAction', None, 1300), -(u'ExitDialog', None, -1), -(u'FatalError', None, -3), -(u'UserExit', None, -2), -(u'AppSearch', None, 400), -(u'CCPSearch', u'NOT Installed', 500), -(u'FindRelatedProducts', None, 200), -(u'IsolateComponents', None, 950), -(u'LaunchConditions', None, 100), -(u'MigrateFeatureStates', None, 1200), -(u'RMCCPSearch', u'NOT Installed', 600), -(u'ValidateProductID', None, 700), -] - -tables=['AdminExecuteSequence', 'AdminUISequence', 'AdvtExecuteSequence', 'InstallExecuteSequence', 'InstallUISequence'] diff --git a/Tools/msi/tcltk/tcltk.props b/Tools/msi/tcltk/tcltk.props new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk.props @@ -0,0 +1,49 @@ + + + + + ICE43 + + + + + + + + + + + $(tcltkDir) + !(bindpath.tcltk) + $(tcltkDir)bin + DLLs\ + tcltk_dlls + + + $(tcltkDir) + !(bindpath.tcltk) + $(tcltkDir)bin + DLLs\ + tcltk_dlls_d + + + + $(tcltkDir) + !(bindpath.tcltk) + $(tcltkDir)lib + tcl\ + tcltk_lib + + + + $(PySourcePath) + !(bindpath.src) + $(PySourcePath) + + tkinter_lib + + + + + \ No newline at end of file diff --git a/Tools/msi/tcltk/tcltk.wixproj b/Tools/msi/tcltk/tcltk.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk.wixproj @@ -0,0 +1,11 @@ + + + + {DB350600-186C-4E52-BA98-26A7CECB067F} + 2.0 + tcltk + Package + IncludeDefaultFeature=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/tcltk/tcltk.wxs b/Tools/msi/tcltk/tcltk.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk.wxs @@ -0,0 +1,53 @@ +? + + + + + + + + + + + + + + + PYTHON_EXE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/tcltk/tcltk_d.wixproj b/Tools/msi/tcltk/tcltk_d.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk_d.wixproj @@ -0,0 +1,11 @@ + + + + {EDA1FA5A-E2AA-4EAF-B49B-87D981CD0F16} + 2.0 + tcltk_d + Package + IncludeDebugBinaries=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/tcltk/tcltk_en-US.wxl_template b/Tools/msi/tcltk/tcltk_en-US.wxl_template new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk_en-US.wxl_template @@ -0,0 +1,8 @@ +? + + Tcl/Tk Support + tcltk + No !(loc.ProductName) installation was detected. + IDLE (Python {{ShortVersion}} {{Bitness}}) + Launches IDLE, the interactive environment for !(loc.ProductName). + diff --git a/Tools/msi/tcltk/tcltk_files.wxs b/Tools/msi/tcltk/tcltk_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk_files.wxs @@ -0,0 +1,35 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/tcltk/tcltk_pdb.wixproj b/Tools/msi/tcltk/tcltk_pdb.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk_pdb.wixproj @@ -0,0 +1,11 @@ + + + + {02053AFA-1831-499A-B3EA-D8B223D3C40D} + 2.0 + tcltk_pdb + Package + IncludeSymbols=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/test/test.props b/Tools/msi/test/test.props new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test.props @@ -0,0 +1,22 @@ + + + + + + + + + + + + $(PySourcePath) + !(bindpath.src) + $(PySourcePath) + + test_py + + + + + \ No newline at end of file diff --git a/Tools/msi/test/test.wixproj b/Tools/msi/test/test.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test.wixproj @@ -0,0 +1,11 @@ + + + + {DE0B7CC2-4358-4131-B3F4-C31C7F2CD468} + 2.0 + test + Package + IncludeDefaultFeature=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/test/test.wxs b/Tools/msi/test/test.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test.wxs @@ -0,0 +1,27 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/test/test_d.wixproj b/Tools/msi/test/test_d.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test_d.wixproj @@ -0,0 +1,11 @@ + + + + {41F5AE8D-24CD-4D03-BE75-AA6F7FAB4097} + 2.0 + test_d + Package + IncludeDebugBinaries=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/test/test_en-US.wxl b/Tools/msi/test/test_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test_en-US.wxl @@ -0,0 +1,7 @@ +? + + Test Suite + test + !(loc.FullProductName) native libtest + !(loc.ProductName) Native Test Modules + diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test_files.wxs @@ -0,0 +1,65 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/msi/test/test_pdb.wixproj b/Tools/msi/test/test_pdb.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test_pdb.wixproj @@ -0,0 +1,11 @@ + + + + {7CF48ADD-CFAA-499F-9A05-BA18440A3344} + 2.0 + test_pdb + Package + IncludeSymbols=1;$(DefineConstants) + + + \ No newline at end of file diff --git a/Tools/msi/tools/tools.wixproj b/Tools/msi/tools/tools.wixproj new file mode 100644 --- /dev/null +++ b/Tools/msi/tools/tools.wixproj @@ -0,0 +1,42 @@ + + + + {24CBEB95-BC1E-4EA9-AEA9-33834BCCD0EC} + 2.0 + tools + Package + + + + + + + + + + + + + + $(PySourcePath) + !(bindpath.src) + $(PySourcePath) + + tools_py + + + + + \ No newline at end of file diff --git a/Tools/msi/tools/tools.wxs b/Tools/msi/tools/tools.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/tools/tools.wxs @@ -0,0 +1,14 @@ +? + + + + + + + + + + + + + diff --git a/Tools/msi/tools/tools_en-US.wxl b/Tools/msi/tools/tools_en-US.wxl new file mode 100644 --- /dev/null +++ b/Tools/msi/tools/tools_en-US.wxl @@ -0,0 +1,5 @@ +? + + Utility Scripts + tools + diff --git a/Tools/msi/tools/tools_files.wxs b/Tools/msi/tools/tools_files.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/tools/tools_files.wxs @@ -0,0 +1,16 @@ +? + + + + + + + + + + + + + + + diff --git a/Tools/msi/uisample.py b/Tools/msi/uisample.py deleted file mode 100644 --- a/Tools/msi/uisample.py +++ /dev/null @@ -1,1400 +0,0 @@ - -import msilib,os;dirname=os.path.dirname(__file__) -AdminExecuteSequence = [ -(u'InstallValidate', None, 1400), -(u'InstallInitialize', None, 1500), -(u'InstallFinalize', None, 6600), -(u'InstallFiles', None, 4000), -(u'InstallAdminPackage', None, 3900), -(u'FileCost', None, 900), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -] - -AdminUISequence = [ -(u'AdminWelcomeDlg', None, 1230), -(u'FileCost', None, 900), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'ExecuteAction', None, 1300), -(u'ExitDialog', None, -1), -(u'FatalError', None, -3), -(u'PrepareDlg', None, 140), -(u'ProgressDlg', None, 1280), -(u'UserExit', None, -2), -] - -AdvtExecuteSequence = [ -(u'InstallValidate', None, 1400), -(u'InstallInitialize', None, 1500), -(u'InstallFinalize', None, 6600), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'CreateShortcuts', None, 4500), -(u'PublishComponents', None, 6200), -(u'PublishFeatures', None, 6300), -(u'PublishProduct', None, 6400), -(u'RegisterClassInfo', None, 4600), -(u'RegisterExtensionInfo', None, 4700), -(u'RegisterMIMEInfo', None, 4900), -(u'RegisterProgIdInfo', None, 4800), -] - -BBControl = [ -] - -Billboard = [ -] - -Binary = [ -(u'bannrbmp', msilib.Binary(os.path.join(dirname,"bannrbmp.bin"))), -(u'completi', msilib.Binary(os.path.join(dirname,"completi.bin"))), -(u'custicon', msilib.Binary(os.path.join(dirname,"custicon.bin"))), -(u'dlgbmp', msilib.Binary(os.path.join(dirname,"dlgbmp.bin"))), -(u'exclamic', msilib.Binary(os.path.join(dirname,"exclamic.bin"))), -(u'info', msilib.Binary(os.path.join(dirname,"info.bin"))), -(u'insticon', msilib.Binary(os.path.join(dirname,"insticon.bin"))), -(u'New', msilib.Binary(os.path.join(dirname,"New.bin"))), -(u'removico', msilib.Binary(os.path.join(dirname,"removico.bin"))), -(u'repairic', msilib.Binary(os.path.join(dirname,"repairic.bin"))), -(u'Up', msilib.Binary(os.path.join(dirname,"Up.bin"))), -] - -CheckBox = [ -] - -Property = [ -(u'BannerBitmap', u'bannrbmp'), -(u'IAgree', u'No'), -(u'ProductID', u'none'), -(u'ARPHELPLINK', u'http://www.microsoft.com/management'), -(u'ButtonText_Back', u'< &Back'), -(u'ButtonText_Browse', u'Br&owse'), -(u'ButtonText_Cancel', u'Cancel'), -(u'ButtonText_Exit', u'&Exit'), -(u'ButtonText_Finish', u'&Finish'), -(u'ButtonText_Ignore', u'&Ignore'), -(u'ButtonText_Install', u'&Install'), -(u'ButtonText_Next', u'&Next >'), -(u'ButtonText_No', u'&No'), -(u'ButtonText_OK', u'OK'), -(u'ButtonText_Remove', u'&Remove'), -(u'ButtonText_Repair', u'&Repair'), -(u'ButtonText_Reset', u'&Reset'), -(u'ButtonText_Resume', u'&Resume'), -(u'ButtonText_Retry', u'&Retry'), -(u'ButtonText_Return', u'&Return'), -(u'ButtonText_Yes', u'&Yes'), -(u'CompleteSetupIcon', u'completi'), -(u'ComponentDownload', u'ftp://anonymous at microsoft.com/components/'), -(u'CustomSetupIcon', u'custicon'), -(u'DefaultUIFont', u'DlgFont8'), -(u'DialogBitmap', u'dlgbmp'), -(u'DlgTitleFont', u'{&DlgFontBold8}'), -(u'ErrorDialog', u'ErrorDlg'), -(u'ExclamationIcon', u'exclamic'), -(u'InfoIcon', u'info'), -(u'InstallerIcon', u'insticon'), -(u'INSTALLLEVEL', u'3'), -(u'InstallMode', u'Typical'), -(u'PIDTemplate', u'12345<###-%%%%%%%>@@@@@'), -#(u'ProductLanguage', u'1033'), -(u'Progress1', u'Installing'), -(u'Progress2', u'installs'), -(u'PROMPTROLLBACKCOST', u'P'), -(u'RemoveIcon', u'removico'), -(u'RepairIcon', u'repairic'), -(u'Setup', u'Setup'), -(u'ShowUserRegistrationDlg', u'1'), -(u'Wizard', u'Setup Wizard'), -] - -ComboBox = [ -] - -Control = [ -(u'AdminWelcomeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), -(u'AdminWelcomeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'AdminWelcomeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'AdminWelcomeDlg', u'Description', u'Text', 135, 70, 220, 30, 196611, None, u'The [Wizard] will create a server image of [ProductName], at a specified network location. Click Next to continue or Cancel to exit the [Wizard].', None, None), -(u'AdminWelcomeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), -(u'AdminWelcomeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), -(u'AdminWelcomeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -(u'ExitDialog', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), -(u'ExitDialog', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'ExitDialog', u'Cancel', u'PushButton', 304, 243, 56, 17, 1, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'ExitDialog', u'Description', u'Text', 135, 70, 220, 20, 196611, None, u'Click the Finish button to exit the [Wizard].', None, None), -(u'ExitDialog', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Completing the [ProductName] [Wizard]', None, None), -(u'ExitDialog', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Finish', None), -(u'ExitDialog', u'Finish', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Finish]', u'Cancel', None), -(u'FatalError', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), -(u'FatalError', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'FatalError', u'Cancel', u'PushButton', 304, 243, 56, 17, 1, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'FatalError', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}[ProductName] [Wizard] ended prematurely', None, None), -(u'FatalError', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Finish', None), -(u'FatalError', u'Finish', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Finish]', u'Cancel', None), -(u'FatalError', u'Description1', u'Text', 135, 70, 220, 40, 196611, None, u'[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.', None, None), -(u'FatalError', u'Description2', u'Text', 135, 115, 220, 20, 196611, None, u'Click the Finish button to exit the [Wizard].', None, None), -(u'PrepareDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Cancel', None), -(u'PrepareDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'PrepareDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'PrepareDlg', u'Description', u'Text', 135, 70, 220, 20, 196611, None, u'Please wait while the [Wizard] prepares to guide you through the installation.', None, None), -(u'PrepareDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), -(u'PrepareDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', None, None), -(u'PrepareDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', None, None), -(u'PrepareDlg', u'ActionData', u'Text', 135, 125, 220, 30, 196611, None, None, None, None), -(u'PrepareDlg', u'ActionText', u'Text', 135, 100, 220, 20, 196611, None, None, None, None), -(u'ProgressDlg', u'Text', u'Text', 35, 65, 300, 20, 3, None, u'Please wait while the [Wizard] [Progress2] [ProductName]. This may take several minutes.', None, None), -(u'ProgressDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), -(u'ProgressDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'ProgressDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'ProgressDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'ProgressDlg', u'Title', u'Text', 20, 15, 200, 15, 196611, None, u'[DlgTitleFont][Progress1] [ProductName]', None, None), -(u'ProgressDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), -(u'ProgressDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', u'Cancel', None), -(u'ProgressDlg', u'ActionText', u'Text', 70, 100, 265, 10, 3, None, None, None, None), -(u'ProgressDlg', u'ProgressBar', u'ProgressBar', 35, 115, 300, 10, 65537, None, u'Progress done', None, None), -(u'ProgressDlg', u'StatusLabel', u'Text', 35, 100, 35, 10, 3, None, u'Status:', None, None), -(u'UserExit', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), -(u'UserExit', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'UserExit', u'Cancel', u'PushButton', 304, 243, 56, 17, 1, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'UserExit', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}[ProductName] [Wizard] was interrupted', None, None), -(u'UserExit', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Finish', None), -(u'UserExit', u'Finish', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Finish]', u'Cancel', None), -(u'UserExit', u'Description1', u'Text', 135, 70, 220, 40, 196611, None, u'[ProductName] setup was interrupted. Your system has not been modified. To install this program at a later time, please run the installation again.', None, None), -(u'UserExit', u'Description2', u'Text', 135, 115, 220, 20, 196611, None, u'Click the Finish button to exit the [Wizard].', None, None), -(u'AdminBrowseDlg', u'Up', u'PushButton', 298, 55, 19, 19, 3670019, None, u'Up', u'NewFolder', u'Up One Level|'), -(u'AdminBrowseDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'PathEdit', None), -(u'AdminBrowseDlg', u'PathEdit', u'PathEdit', 84, 202, 261, 17, 3, u'TARGETDIR', None, u'OK', None), -(u'AdminBrowseDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'AdminBrowseDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'AdminBrowseDlg', u'Cancel', u'PushButton', 240, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'ComboLabel', None), -(u'AdminBrowseDlg', u'ComboLabel', u'Text', 25, 58, 44, 10, 3, None, u'&Look in:', u'DirectoryCombo', None), -(u'AdminBrowseDlg', u'DirectoryCombo', u'DirectoryCombo', 70, 55, 220, 80, 458755, u'TARGETDIR', None, u'Up', None), -(u'AdminBrowseDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Browse to the destination folder', None, None), -(u'AdminBrowseDlg', u'DirectoryList', u'DirectoryList', 25, 83, 320, 110, 7, u'TARGETDIR', None, u'PathLabel', None), -(u'AdminBrowseDlg', u'PathLabel', u'Text', 25, 205, 59, 10, 3, None, u'&Folder name:', u'BannerBitmap', None), -(u'AdminBrowseDlg', u'NewFolder', u'PushButton', 325, 55, 19, 19, 3670019, None, u'New', u'DirectoryList', u'Create A New Folder|'), -(u'AdminBrowseDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'Cancel', None), -(u'AdminBrowseDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Change current destination folder', None, None), -(u'AdminInstallPointDlg', u'Text', u'Text', 25, 80, 320, 10, 3, None, u'&Enter a new network location or click Browse to browse to one.', u'PathEdit', None), -(u'AdminInstallPointDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Text', None), -(u'AdminInstallPointDlg', u'PathEdit', u'PathEdit', 25, 93, 320, 18, 3, u'TARGETDIR', None, u'Browse', None), -(u'AdminInstallPointDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'AdminInstallPointDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'AdminInstallPointDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'AdminInstallPointDlg', u'Description', u'Text', 25, 20, 280, 20, 196611, None, u'Please specify a network location for the server image of [ProductName] product', None, None), -(u'AdminInstallPointDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Network Location', None, None), -(u'AdminInstallPointDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), -(u'AdminInstallPointDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -(u'AdminInstallPointDlg', u'Browse', u'PushButton', 289, 119, 56, 17, 3, None, u'[ButtonText_Browse]', u'Back', None), -(u'AdminRegistrationDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'OrganizationLabel', None), -(u'AdminRegistrationDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'AdminRegistrationDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'AdminRegistrationDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'AdminRegistrationDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Please enter your company information', None, None), -(u'AdminRegistrationDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Company Information', None, None), -(u'AdminRegistrationDlg', u'Back', u'PushButton', 180, 243, 56, 17, 65539, None, u'[ButtonText_Back]', u'Next', None), -(u'AdminRegistrationDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -(u'AdminRegistrationDlg', u'OrganizationLabel', u'Text', 45, 71, 285, 30, 3, None, u'&Please enter the name of your organization in the box below. This will be used as default company name for subsequent installations of [ProductName]:', u'OrganizationEdit', None), -(u'AdminRegistrationDlg', u'CDKeyEdit', u'MaskedEdit', 45, 143, 250, 16, 3, u'PIDKEY', u'[PIDTemplate]', u'Back', None), -(u'AdminRegistrationDlg', u'CDKeyLabel', u'Text', 45, 130, 50, 10, 3, None, u'CD &Key:', u'CDKeyEdit', None), -(u'AdminRegistrationDlg', u'OrganizationEdit', u'Edit', 45, 105, 220, 18, 3, u'COMPANYNAME', u'{80}', u'CDKeyLabel', None), -(u'BrowseDlg', u'Up', u'PushButton', 298, 55, 19, 19, 3670019, None, u'Up', u'NewFolder', u'Up One Level|'), -(u'BrowseDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'PathEdit', None), -(u'BrowseDlg', u'PathEdit', u'PathEdit', 84, 202, 261, 18, 11, u'_BrowseProperty', None, u'OK', None), -(u'BrowseDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'BrowseDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'BrowseDlg', u'Cancel', u'PushButton', 240, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'ComboLabel', None), -(u'BrowseDlg', u'ComboLabel', u'Text', 25, 58, 44, 10, 3, None, u'&Look in:', u'DirectoryCombo', None), -(u'BrowseDlg', u'DirectoryCombo', u'DirectoryCombo', 70, 55, 220, 80, 393227, u'_BrowseProperty', None, u'Up', None), -(u'BrowseDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Browse to the destination folder', None, None), -(u'BrowseDlg', u'DirectoryList', u'DirectoryList', 25, 83, 320, 110, 15, u'_BrowseProperty', None, u'PathLabel', None), -(u'BrowseDlg', u'PathLabel', u'Text', 25, 205, 59, 10, 3, None, u'&Folder name:', u'BannerBitmap', None), -(u'BrowseDlg', u'NewFolder', u'PushButton', 325, 55, 19, 19, 3670019, None, u'New', u'DirectoryList', u'Create A New Folder|'), -(u'BrowseDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'Cancel', None), -(u'BrowseDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Change current destination folder', None, None), -(u'CancelDlg', u'Text', u'Text', 48, 15, 194, 30, 3, None, u'Are you sure you want to cancel [ProductName] installation?', None, None), -(u'CancelDlg', u'Icon', u'Icon', 15, 15, 24, 24, 5242881, None, u'[InfoIcon]', None, u'Information icon|'), -(u'CancelDlg', u'No', u'PushButton', 132, 57, 56, 17, 3, None, u'[ButtonText_No]', u'Yes', None), -(u'CancelDlg', u'Yes', u'PushButton', 72, 57, 56, 17, 3, None, u'[ButtonText_Yes]', u'No', None), -(u'CustomizeDlg', u'Text', u'Text', 25, 55, 320, 20, 3, None, u'Click on the icons in the tree below to change the way features will be installed.', None, None), -(u'CustomizeDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Tree', None), -(u'CustomizeDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'CustomizeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'CustomizeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'CustomizeDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Select the way you want features to be installed.', None, None), -(u'CustomizeDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Custom Setup', None, None), -(u'CustomizeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), -(u'CustomizeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -(u'CustomizeDlg', u'Browse', u'PushButton', 304, 200, 56, 17, 3, None, u'[ButtonText_Browse]', u'Reset', None), -(u'CustomizeDlg', u'Tree', u'SelectionTree', 25, 85, 175, 95, 7, u'_BrowseProperty', u'Tree of selections', u'Browse', None), -(u'CustomizeDlg', u'Box', u'GroupBox', 210, 81, 140, 98, 1, None, None, None, None), -(u'CustomizeDlg', u'Reset', u'PushButton', 42, 243, 56, 17, 3, None, u'[ButtonText_Reset]', u'DiskCost', None), -(u'CustomizeDlg', u'DiskCost', u'PushButton', 111, 243, 56, 17, 3, None, u'Disk &Usage', u'Back', None), -(u'CustomizeDlg', u'ItemDescription', u'Text', 215, 90, 131, 30, 3, None, u'Multiline description of the currently selected item.', None, None), -(u'CustomizeDlg', u'ItemSize', u'Text', 215, 130, 131, 45, 3, None, u'The size of the currently selected item.', None, None), -(u'CustomizeDlg', u'Location', u'Text', 75, 200, 215, 20, 3, None, u"", None, None), -(u'CustomizeDlg', u'LocationLabel', u'Text', 25, 200, 50, 10, 3, None, u'Location:', None, None), -(u'DiskCostDlg', u'Text', u'Text', 20, 53, 330, 40, 3, None, u'The highlighted volumes (if any) do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).', None, None), -(u'DiskCostDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'OK', None), -(u'DiskCostDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'DiskCostDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'DiskCostDlg', u'Description', u'Text', 20, 20, 280, 20, 196611, None, u'The disk space required for the installation of the selected features.', None, None), -(u'DiskCostDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'BannerBitmap', None), -(u'DiskCostDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Disk Space Requirements', None, None), -(u'DiskCostDlg', u'VolumeList', u'VolumeCostList', 20, 100, 330, 120, 393223, None, u'{120}{70}{70}{70}{70}', None, None), -(u'ErrorDlg', u'Y', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Yes]', None, None), -(u'ErrorDlg', u'A', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Cancel]', None, None), -(u'ErrorDlg', u'C', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Cancel]', None, None), -(u'ErrorDlg', u'ErrorIcon', u'Icon', 15, 15, 24, 24, 5242881, None, u'[InfoIcon]', None, u'Information icon|'), -(u'ErrorDlg', u'ErrorText', u'Text', 48, 15, 205, 60, 3, None, u'Information text', None, None), -(u'ErrorDlg', u'I', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Ignore]', None, None), -(u'ErrorDlg', u'N', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_No]', None, None), -(u'ErrorDlg', u'O', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_OK]', None, None), -(u'ErrorDlg', u'R', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Retry]', None, None), -(u'FilesInUse', u'Text', u'Text', 20, 55, 330, 30, 3, None, u'The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.', None, None), -(u'FilesInUse', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Retry', None), -(u'FilesInUse', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'FilesInUse', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'FilesInUse', u'Description', u'Text', 20, 23, 280, 20, 196611, None, u'Some files that need to be updated are currently in use.', None, None), -(u'FilesInUse', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Files in Use', None, None), -(u'FilesInUse', u'Retry', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Retry]', u'Ignore', None), -(u'FilesInUse', u'Exit', u'PushButton', 166, 243, 56, 17, 3, None, u'[ButtonText_Exit]', u'BannerBitmap', None), -(u'FilesInUse', u'Ignore', u'PushButton', 235, 243, 56, 17, 3, None, u'[ButtonText_Ignore]', u'Exit', None), -(u'FilesInUse', u'List', u'ListBox', 20, 87, 330, 130, 7, u'FileInUseProcess', None, None, None), -(u'LicenseAgreementDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'AgreementText', None), -(u'LicenseAgreementDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'LicenseAgreementDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'LicenseAgreementDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'LicenseAgreementDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Please read the following license agreement carefully', None, None), -(u'LicenseAgreementDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]End-User License Agreement', None, None), -(u'LicenseAgreementDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), -(u'LicenseAgreementDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -(u'LicenseAgreementDlg', u'AgreementText', u'ScrollableText', 20, 60, 330, 120, 7, None, u'{\\rtf1\\ansi\\ansicpg1252\\deff0\\deftab720{\\fonttbl{\\f0\\froman\\fprq2 Times New Roman;}}{\\colortbl\\red0\\green0\\blue0;} \\deflang1033\\horzdoc{\\*\\fchars }{\\*\\lchars }\\pard\\plain\\f0\\fs20 \\par }', u'Buttons', None), -(u'LicenseAgreementDlg', u'Buttons', u'RadioButtonGroup', 20, 187, 330, 40, 3, u'IAgree', None, u'Back', None), -(u'MaintenanceTypeDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'ChangeLabel', None), -(u'MaintenanceTypeDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'MaintenanceTypeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'MaintenanceTypeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'MaintenanceTypeDlg', u'Description', u'Text', 25, 23, 280, 20, 196611, None, u'Select the operation you wish to perform.', None, None), -(u'MaintenanceTypeDlg', u'Title', u'Text', 15, 6, 240, 15, 196611, None, u'[DlgTitleFont]Modify, Repair or Remove installation', None, None), -(u'MaintenanceTypeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), -(u'MaintenanceTypeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', u'Cancel', None), -(u'MaintenanceTypeDlg', u'ChangeLabel', u'Text', 105, 65, 100, 10, 3, None, u'[DlgTitleFont]&Modify', u'ChangeButton', None), -(u'MaintenanceTypeDlg', u'ChangeButton', u'PushButton', 50, 65, 38, 38, 5767171, None, u'[CustomSetupIcon]', u'RepairLabel', u'Modify Installation|'), -(u'MaintenanceTypeDlg', u'RepairLabel', u'Text', 105, 114, 100, 10, 3, None, u'[DlgTitleFont]Re&pair', u'RepairButton', None), -(u'MaintenanceTypeDlg', u'ChangeText', u'Text', 105, 78, 230, 20, 3, None, u'Allows users to change the way features are installed.', None, None), -(u'MaintenanceTypeDlg', u'RemoveButton', u'PushButton', 50, 163, 38, 38, 5767171, None, u'[RemoveIcon]', u'Back', u'Remove Installation|'), -(u'MaintenanceTypeDlg', u'RemoveLabel', u'Text', 105, 163, 100, 10, 3, None, u'[DlgTitleFont]&Remove', u'RemoveButton', None), -(u'MaintenanceTypeDlg', u'RemoveText', u'Text', 105, 176, 230, 20, 3, None, u'Removes [ProductName] from your computer.', None, None), -(u'MaintenanceTypeDlg', u'RepairButton', u'PushButton', 50, 114, 38, 38, 5767171, None, u'[RepairIcon]', u'RemoveLabel', u'Repair Installation|'), -(u'MaintenanceTypeDlg', u'RepairText', u'Text', 105, 127, 230, 30, 3, None, u'Repairs errors in the most recent installation state - fixes missing or corrupt files, shortcuts and registry entries.', None, None), -(u'MaintenanceWelcomeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), -(u'MaintenanceWelcomeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'MaintenanceWelcomeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'MaintenanceWelcomeDlg', u'Description', u'Text', 135, 70, 220, 60, 196611, None, u'The [Wizard] will allow you to change the way [ProductName] features are installed on your computer or even to remove [ProductName] from your computer. Click Next to continue or Cancel to exit the [Wizard].', None, None), -(u'MaintenanceWelcomeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), -(u'MaintenanceWelcomeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), -(u'MaintenanceWelcomeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -(u'OutOfDiskDlg', u'Text', u'Text', 20, 53, 330, 40, 3, None, u'The highlighted volumes do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).', None, None), -(u'OutOfDiskDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'OK', None), -(u'OutOfDiskDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'OutOfDiskDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'OutOfDiskDlg', u'Description', u'Text', 20, 20, 280, 20, 196611, None, u'Disk space required for the installation exceeds available disk space.', None, None), -(u'OutOfDiskDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'BannerBitmap', None), -(u'OutOfDiskDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Out of Disk Space', None, None), -(u'OutOfDiskDlg', u'VolumeList', u'VolumeCostList', 20, 100, 330, 120, 393223, None, u'{120}{70}{70}{70}{70}', None, None), -(u'OutOfRbDiskDlg', u'Text', u'Text', 20, 53, 330, 40, 3, None, u'The highlighted volumes do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).', None, None), -(u'OutOfRbDiskDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'No', None), -(u'OutOfRbDiskDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'OutOfRbDiskDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'OutOfRbDiskDlg', u'Description', u'Text', 20, 20, 280, 20, 196611, None, u'Disk space required for the installation exceeds available disk space.', None, None), -(u'OutOfRbDiskDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Out of Disk Space', None, None), -(u'OutOfRbDiskDlg', u'No', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_No]', u'Yes', None), -(u'OutOfRbDiskDlg', u'Yes', u'PushButton', 240, 243, 56, 17, 3, None, u'[ButtonText_Yes]', u'BannerBitmap', None), -(u'OutOfRbDiskDlg', u'VolumeList', u'VolumeCostList', 20, 140, 330, 80, 4587527, None, u'{120}{70}{70}{70}{70}', None, None), -(u'OutOfRbDiskDlg', u'Text2', u'Text', 20, 94, 330, 40, 3, None, u"Alternatively, you may choose to disable the installer's rollback functionality. This allows the installer to restore your computer's original state should the installation be interrupted in any way. Click Yes if you wish to take the risk to disable rollback.", None, None), -(u'ResumeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), -(u'ResumeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'ResumeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'ResumeDlg', u'Description', u'Text', 135, 70, 220, 30, 196611, None, u'The [Wizard] will complete the installation of [ProductName] on your computer. Click Install to continue or Cancel to exit the [Wizard].', None, None), -(u'ResumeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Resuming the [ProductName] [Wizard]', None, None), -(u'ResumeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Install', None), -(u'ResumeDlg', u'Install', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Install]', u'Cancel', None), -(u'SetupTypeDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'TypicalLabel', None), -(u'SetupTypeDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'SetupTypeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'SetupTypeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'SetupTypeDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Choose the setup type that best suits your needs', None, None), -(u'SetupTypeDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Choose Setup Type', None, None), -(u'SetupTypeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), -(u'SetupTypeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', u'Cancel', None), -(u'SetupTypeDlg', u'TypicalLabel', u'Text', 105, 65, 100, 10, 3, None, u'[DlgTitleFont]&Typical', u'TypicalButton', None), -(u'SetupTypeDlg', u'CompleteButton', u'PushButton', 50, 171, 38, 38, 5767171, None, u'[CompleteSetupIcon]', u'Back', u'Complete Installation|'), -(u'SetupTypeDlg', u'CompleteLabel', u'Text', 105, 171, 100, 10, 3, None, u'[DlgTitleFont]C&omplete', u'CompleteButton', None), -(u'SetupTypeDlg', u'CompleteText', u'Text', 105, 184, 230, 20, 3, None, u'All program features will be installed. (Requires most disk space)', None, None), -(u'SetupTypeDlg', u'CustomButton', u'PushButton', 50, 118, 38, 38, 5767171, None, u'[CustomSetupIcon]', u'CompleteLabel', u'Custom Installation|'), -(u'SetupTypeDlg', u'CustomLabel', u'Text', 105, 118, 100, 10, 3, None, u'[DlgTitleFont]C&ustom', u'CustomButton', None), -(u'SetupTypeDlg', u'CustomText', u'Text', 105, 131, 230, 30, 3, None, u'Allows users to choose which program features will be installed and where they will be installed. Recommended for advanced users.', None, None), -(u'SetupTypeDlg', u'TypicalButton', u'PushButton', 50, 65, 38, 38, 5767171, None, u'[InstallerIcon]', u'CustomLabel', u'Typical Installation|'), -(u'SetupTypeDlg', u'TypicalText', u'Text', 105, 78, 230, 20, 3, None, u'Installs the most common program features. Recommended for most users.', None, None), -(u'UserRegistrationDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'NameLabel', None), -(u'UserRegistrationDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'UserRegistrationDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'UserRegistrationDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'UserRegistrationDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Please enter your customer information', None, None), -(u'UserRegistrationDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Customer Information', None, None), -(u'UserRegistrationDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), -(u'UserRegistrationDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -(u'UserRegistrationDlg', u'OrganizationLabel', u'Text', 45, 110, 100, 15, 3, None, u'&Organization:', u'OrganizationEdit', None), -(u'UserRegistrationDlg', u'CDKeyEdit', u'MaskedEdit', 45, 159, 250, 16, 3, u'PIDKEY', u'[PIDTemplate]', u'Back', None), -(u'UserRegistrationDlg', u'CDKeyLabel', u'Text', 45, 147, 50, 10, 3, None, u'CD &Key:', u'CDKeyEdit', None), -(u'UserRegistrationDlg', u'OrganizationEdit', u'Edit', 45, 122, 220, 18, 3, u'COMPANYNAME', u'{80}', u'CDKeyLabel', None), -(u'UserRegistrationDlg', u'NameLabel', u'Text', 45, 73, 100, 15, 3, None, u'&User Name:', u'NameEdit', None), -(u'UserRegistrationDlg', u'NameEdit', u'Edit', 45, 85, 220, 18, 3, u'USERNAME', u'{80}', u'OrganizationLabel', None), -(u'VerifyReadyDlg', u'Text', u'Text', 25, 70, 320, 20, 3, None, u'Click Install to begin the installation. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.', None, None), -(u'VerifyReadyDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), -(u'VerifyReadyDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'VerifyReadyDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'VerifyReadyDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'VerifyReadyDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'The [Wizard] is ready to begin the [InstallMode] installation', None, None), -(u'VerifyReadyDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Ready to Install', None, None), -(u'VerifyReadyDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Install', None), -(u'VerifyReadyDlg', u'Install', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Install]', u'Cancel', None), -(u'VerifyRemoveDlg', u'Text', u'Text', 25, 70, 320, 30, 3, None, u'Click Remove to remove [ProductName] from your computer. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.', None, None), -(u'VerifyRemoveDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), -(u'VerifyRemoveDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'VerifyRemoveDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'VerifyRemoveDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'VerifyRemoveDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'You have chosen to remove the program from your computer.', None, None), -(u'VerifyRemoveDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Remove [ProductName]', None, None), -(u'VerifyRemoveDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Remove', None), -(u'VerifyRemoveDlg', u'Remove', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Remove]', u'Cancel', None), -(u'VerifyRepairDlg', u'Text', u'Text', 25, 70, 320, 30, 3, None, u'Click Repair to repair the installation of [ProductName]. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.', None, None), -(u'VerifyRepairDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), -(u'VerifyRepairDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), -(u'VerifyRepairDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'VerifyRepairDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), -(u'VerifyRepairDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'The [Wizard] is ready to begin the repair of [ProductName].', None, None), -(u'VerifyRepairDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Repair [ProductName]', None, None), -(u'VerifyRepairDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Repair', None), -(u'VerifyRepairDlg', u'Repair', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Repair]', u'Cancel', None), -(u'WaitForCostingDlg', u'Text', u'Text', 48, 15, 194, 30, 3, None, u'Please wait while the installer finishes determining your disk space requirements.', None, None), -(u'WaitForCostingDlg', u'Icon', u'Icon', 15, 15, 24, 24, 5242881, None, u'[ExclamationIcon]', None, u'Exclamation icon|'), -(u'WaitForCostingDlg', u'Return', u'PushButton', 102, 57, 56, 17, 3, None, u'[ButtonText_Return]', None, None), -(u'WelcomeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), -(u'WelcomeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), -(u'WelcomeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), -(u'WelcomeDlg', u'Description', u'Text', 135, 70, 220, 30, 196611, None, u'The [Wizard] will install [ProductName] on your computer. Click Next to continue or Cancel to exit the [Wizard].', None, None), -(u'WelcomeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), -(u'WelcomeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), -(u'WelcomeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), -] - -ListBox = [ -] - -ActionText = [ -(u'InstallValidate', u'Validating install', None), -(u'InstallFiles', u'Copying new files', u'File: [1], Directory: [9], Size: [6]'), -(u'InstallAdminPackage', u'Copying network install files', u'File: [1], Directory: [9], Size: [6]'), -(u'FileCost', u'Computing space requirements', None), -(u'CostInitialize', u'Computing space requirements', None), -(u'CostFinalize', u'Computing space requirements', None), -(u'CreateShortcuts', u'Creating shortcuts', u'Shortcut: [1]'), -(u'PublishComponents', u'Publishing Qualified Components', u'Component ID: [1], Qualifier: [2]'), -(u'PublishFeatures', u'Publishing Product Features', u'Feature: [1]'), -(u'PublishProduct', u'Publishing product information', None), -(u'RegisterClassInfo', u'Registering Class servers', u'Class Id: [1]'), -(u'RegisterExtensionInfo', u'Registering extension servers', u'Extension: [1]'), -(u'RegisterMIMEInfo', u'Registering MIME info', u'MIME Content Type: [1], Extension: [2]'), -(u'RegisterProgIdInfo', u'Registering program identifiers', u'ProgId: [1]'), -(u'AllocateRegistrySpace', u'Allocating registry space', u'Free space: [1]'), -(u'AppSearch', u'Searching for installed applications', u'Property: [1], Signature: [2]'), -(u'BindImage', u'Binding executables', u'File: [1]'), -(u'CCPSearch', u'Searching for qualifying products', None), -(u'CreateFolders', u'Creating folders', u'Folder: [1]'), -(u'DeleteServices', u'Deleting services', u'Service: [1]'), -(u'DuplicateFiles', u'Creating duplicate files', u'File: [1], Directory: [9], Size: [6]'), -(u'FindRelatedProducts', u'Searching for related applications', u'Found application: [1]'), -(u'InstallODBC', u'Installing ODBC components', None), -(u'InstallServices', u'Installing new services', u'Service: [2]'), -(u'LaunchConditions', u'Evaluating launch conditions', None), -(u'MigrateFeatureStates', u'Migrating feature states from related applications', u'Application: [1]'), -(u'MoveFiles', u'Moving files', u'File: [1], Directory: [9], Size: [6]'), -(u'PatchFiles', u'Patching files', u'File: [1], Directory: [2], Size: [3]'), -(u'ProcessComponents', u'Updating component registration', None), -(u'RegisterComPlus', u'Registering COM+ Applications and Components', u'AppId: [1]{{, AppType: [2], Users: [3], RSN: [4]}}'), -(u'RegisterFonts', u'Registering fonts', u'Font: [1]'), -(u'RegisterProduct', u'Registering product', u'[1]'), -(u'RegisterTypeLibraries', u'Registering type libraries', u'LibID: [1]'), -(u'RegisterUser', u'Registering user', u'[1]'), -(u'RemoveDuplicateFiles', u'Removing duplicated files', u'File: [1], Directory: [9]'), -(u'RemoveEnvironmentStrings', u'Updating environment strings', u'Name: [1], Value: [2], Action [3]'), -(u'RemoveExistingProducts', u'Removing applications', u'Application: [1], Command line: [2]'), -(u'RemoveFiles', u'Removing files', u'File: [1], Directory: [9]'), -(u'RemoveFolders', u'Removing folders', u'Folder: [1]'), -(u'RemoveIniValues', u'Removing INI files entries', u'File: [1], Section: [2], Key: [3], Value: [4]'), -(u'RemoveODBC', u'Removing ODBC components', None), -(u'RemoveRegistryValues', u'Removing system registry values', u'Key: [1], Name: [2]'), -(u'RemoveShortcuts', u'Removing shortcuts', u'Shortcut: [1]'), -(u'RMCCPSearch', u'Searching for qualifying products', None), -(u'SelfRegModules', u'Registering modules', u'File: [1], Folder: [2]'), -(u'SelfUnregModules', u'Unregistering modules', u'File: [1], Folder: [2]'), -(u'SetODBCFolders', u'Initializing ODBC directories', None), -(u'StartServices', u'Starting services', u'Service: [1]'), -(u'StopServices', u'Stopping services', u'Service: [1]'), -(u'UnpublishComponents', u'Unpublishing Qualified Components', u'Component ID: [1], Qualifier: [2]'), -(u'UnpublishFeatures', u'Unpublishing Product Features', u'Feature: [1]'), -(u'UnregisterClassInfo', u'Unregister Class servers', u'Class Id: [1]'), -(u'UnregisterComPlus', u'Unregistering COM+ Applications and Components', u'AppId: [1]{{, AppType: [2]}}'), -(u'UnregisterExtensionInfo', u'Unregistering extension servers', u'Extension: [1]'), -(u'UnregisterFonts', u'Unregistering fonts', u'Font: [1]'), -(u'UnregisterMIMEInfo', u'Unregistering MIME info', u'MIME Content Type: [1], Extension: [2]'), -(u'UnregisterProgIdInfo', u'Unregistering program identifiers', u'ProgId: [1]'), -(u'UnregisterTypeLibraries', u'Unregistering type libraries', u'LibID: [1]'), -(u'WriteEnvironmentStrings', u'Updating environment strings', u'Name: [1], Value: [2], Action [3]'), -(u'WriteIniValues', u'Writing INI files values', u'File: [1], Section: [2], Key: [3], Value: [4]'), -(u'WriteRegistryValues', u'Writing system registry values', u'Key: [1], Name: [2], Value: [3]'), -(u'Advertise', u'Advertising application', None), -(u'GenerateScript', u'Generating script operations for action:', u'[1]'), -(u'InstallSFPCatalogFile', u'Installing system catalog', u'File: [1], Dependencies: [2]'), -(u'MsiPublishAssemblies', u'Publishing assembly information', u'Application Context:[1], Assembly Name:[2]'), -(u'MsiUnpublishAssemblies', u'Unpublishing assembly information', u'Application Context:[1], Assembly Name:[2]'), -(u'Rollback', u'Rolling back action:', u'[1]'), -(u'RollbackCleanup', u'Removing backup files', u'File: [1]'), -(u'UnmoveFiles', u'Removing moved files', u'File: [1], Directory: [9]'), -(u'UnpublishProduct', u'Unpublishing product information', None), -] - -ControlCondition = [ -(u'CustomizeDlg', u'Browse', u'Hide', u'Installed'), -(u'CustomizeDlg', u'Location', u'Hide', u'Installed'), -(u'CustomizeDlg', u'LocationLabel', u'Hide', u'Installed'), -(u'LicenseAgreementDlg', u'Next', u'Disable', u'IAgree <> "Yes"'), -(u'LicenseAgreementDlg', u'Next', u'Enable', u'IAgree = "Yes"'), -] - -ControlEvent = [ -(u'AdminWelcomeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'AdminWelcomeDlg', u'Next', u'NewDialog', u'AdminRegistrationDlg', u'1', 2), -(u'AdminWelcomeDlg', u'Next', u'[InstallMode]', u'Server Image', u'1', 1), -(u'ExitDialog', u'Finish', u'EndDialog', u'Return', u'1', None), -(u'FatalError', u'Finish', u'EndDialog', u'Exit', u'1', None), -(u'PrepareDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'ProgressDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'UserExit', u'Finish', u'EndDialog', u'Exit', u'1', None), -(u'AdminBrowseDlg', u'Up', u'DirectoryListUp', u'0', u'1', None), -(u'AdminBrowseDlg', u'Cancel', u'Reset', u'0', u'1', 1), -(u'AdminBrowseDlg', u'Cancel', u'EndDialog', u'Return', u'1', 2), -(u'AdminBrowseDlg', u'NewFolder', u'DirectoryListNew', u'0', u'1', None), -(u'AdminBrowseDlg', u'OK', u'EndDialog', u'Return', u'1', 2), -(u'AdminBrowseDlg', u'OK', u'SetTargetPath', u'TARGETDIR', u'1', 1), -(u'AdminInstallPointDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'AdminInstallPointDlg', u'Back', u'NewDialog', u'AdminRegistrationDlg', u'1', None), -(u'AdminInstallPointDlg', u'Next', u'SetTargetPath', u'TARGETDIR', u'1', 1), -(u'AdminInstallPointDlg', u'Next', u'NewDialog', u'VerifyReadyDlg', u'1', 2), -(u'AdminInstallPointDlg', u'Browse', u'SpawnDialog', u'AdminBrowseDlg', u'1', None), -(u'AdminRegistrationDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'AdminRegistrationDlg', u'Back', u'NewDialog', u'AdminWelcomeDlg', u'1', None), -(u'AdminRegistrationDlg', u'Next', u'NewDialog', u'AdminInstallPointDlg', u'ProductID', 2), -(u'AdminRegistrationDlg', u'Next', u'ValidateProductID', u'0', u'0', 1), -(u'BrowseDlg', u'Up', u'DirectoryListUp', u'0', u'1', None), -(u'BrowseDlg', u'Cancel', u'Reset', u'0', u'1', 1), -(u'BrowseDlg', u'Cancel', u'EndDialog', u'Return', u'1', 2), -(u'BrowseDlg', u'NewFolder', u'DirectoryListNew', u'0', u'1', None), -(u'BrowseDlg', u'OK', u'EndDialog', u'Return', u'1', 2), -(u'BrowseDlg', u'OK', u'SetTargetPath', u'[_BrowseProperty]', u'1', 1), -(u'CancelDlg', u'No', u'EndDialog', u'Return', u'1', None), -(u'CancelDlg', u'Yes', u'EndDialog', u'Exit', u'1', None), -(u'CustomizeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'CustomizeDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'InstallMode = "Change"', None), -(u'CustomizeDlg', u'Back', u'NewDialog', u'SetupTypeDlg', u'InstallMode = "Custom"', None), -(u'CustomizeDlg', u'Next', u'NewDialog', u'VerifyReadyDlg', u'1', None), -(u'CustomizeDlg', u'Browse', u'SelectionBrowse', u'BrowseDlg', u'1', None), -(u'CustomizeDlg', u'Reset', u'Reset', u'0', u'1', None), -(u'CustomizeDlg', u'DiskCost', u'SpawnDialog', u'DiskCostDlg', u'1', 2), -(u'DiskCostDlg', u'OK', u'EndDialog', u'Return', u'1', None), -(u'ErrorDlg', u'Y', u'EndDialog', u'ErrorYes', u'1', None), -(u'ErrorDlg', u'A', u'EndDialog', u'ErrorAbort', u'1', None), -(u'ErrorDlg', u'C', u'EndDialog', u'ErrorCancel', u'1', None), -(u'ErrorDlg', u'I', u'EndDialog', u'ErrorIgnore', u'1', None), -(u'ErrorDlg', u'N', u'EndDialog', u'ErrorNo', u'1', None), -(u'ErrorDlg', u'O', u'EndDialog', u'ErrorOk', u'1', None), -(u'ErrorDlg', u'R', u'EndDialog', u'ErrorRetry', u'1', None), -(u'FilesInUse', u'Retry', u'EndDialog', u'Retry', u'1', None), -(u'FilesInUse', u'Exit', u'EndDialog', u'Exit', u'1', None), -(u'FilesInUse', u'Ignore', u'EndDialog', u'Ignore', u'1', None), -(u'LicenseAgreementDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'LicenseAgreementDlg', u'Back', u'NewDialog', u'WelcomeDlg', u'1', None), -(u'LicenseAgreementDlg', u'Next', u'NewDialog', u'SetupTypeDlg', u'IAgree = "Yes" AND ShowUserRegistrationDlg <> 1', 3), -(u'LicenseAgreementDlg', u'Next', u'NewDialog', u'UserRegistrationDlg', u'IAgree = "Yes" AND ShowUserRegistrationDlg = 1', 1), -(u'LicenseAgreementDlg', u'Next', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 2), -(u'MaintenanceTypeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'MaintenanceTypeDlg', u'Back', u'NewDialog', u'MaintenanceWelcomeDlg', u'1', None), -(u'MaintenanceTypeDlg', u'ChangeButton', u'NewDialog', u'CustomizeDlg', u'1', 4), -(u'MaintenanceTypeDlg', u'ChangeButton', u'[InstallMode]', u'Change', u'1', 1), -(u'MaintenanceTypeDlg', u'ChangeButton', u'[Progress1]', u'Changing', u'1', 2), -(u'MaintenanceTypeDlg', u'ChangeButton', u'[Progress2]', u'changes', u'1', 3), -(u'MaintenanceTypeDlg', u'RemoveButton', u'NewDialog', u'VerifyRemoveDlg', u'1', 4), -(u'MaintenanceTypeDlg', u'RemoveButton', u'[InstallMode]', u'Remove', u'1', 1), -(u'MaintenanceTypeDlg', u'RemoveButton', u'[Progress1]', u'Removing', u'1', 2), -(u'MaintenanceTypeDlg', u'RemoveButton', u'[Progress2]', u'removes', u'1', 3), -(u'MaintenanceTypeDlg', u'RepairButton', u'NewDialog', u'VerifyRepairDlg', u'1', 4), -(u'MaintenanceTypeDlg', u'RepairButton', u'[InstallMode]', u'Repair', u'1', 1), -(u'MaintenanceTypeDlg', u'RepairButton', u'[Progress1]', u'Repairing', u'1', 2), -(u'MaintenanceTypeDlg', u'RepairButton', u'[Progress2]', u'repairs', u'1', 3), -(u'MaintenanceWelcomeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'MaintenanceWelcomeDlg', u'Next', u'NewDialog', u'MaintenanceTypeDlg', u'1', 2), -(u'MaintenanceWelcomeDlg', u'Next', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 1), -(u'OutOfDiskDlg', u'OK', u'EndDialog', u'Return', u'1', None), -(u'OutOfRbDiskDlg', u'No', u'EndDialog', u'Return', u'1', None), -(u'OutOfRbDiskDlg', u'Yes', u'EndDialog', u'Return', u'1', 2), -(u'OutOfRbDiskDlg', u'Yes', u'EnableRollback', u'False', u'1', 1), -(u'ResumeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'ResumeDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 4), -(u'ResumeDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 2), -(u'ResumeDlg', u'Install', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 6), -(u'ResumeDlg', u'Install', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 3), -(u'ResumeDlg', u'Install', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 1), -(u'ResumeDlg', u'Install', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 5), -(u'SetupTypeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'SetupTypeDlg', u'Back', u'NewDialog', u'LicenseAgreementDlg', u'ShowUserRegistrationDlg <> 1', None), -(u'SetupTypeDlg', u'Back', u'NewDialog', u'UserRegistrationDlg', u'ShowUserRegistrationDlg = 1', None), -(u'SetupTypeDlg', u'CompleteButton', u'NewDialog', u'VerifyReadyDlg', u'1', 3), -(u'SetupTypeDlg', u'CompleteButton', u'[InstallMode]', u'Complete', u'1', 1), -(u'SetupTypeDlg', u'CompleteButton', u'SetInstallLevel', u'1000', u'1', 2), -(u'SetupTypeDlg', u'CustomButton', u'NewDialog', u'CustomizeDlg', u'1', 2), -(u'SetupTypeDlg', u'CustomButton', u'[InstallMode]', u'Custom', u'1', 1), -(u'SetupTypeDlg', u'TypicalButton', u'NewDialog', u'VerifyReadyDlg', u'1', 3), -(u'SetupTypeDlg', u'TypicalButton', u'[InstallMode]', u'Typical', u'1', 1), -(u'SetupTypeDlg', u'TypicalButton', u'SetInstallLevel', u'3', u'1', 2), -(u'UserRegistrationDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'UserRegistrationDlg', u'Back', u'NewDialog', u'LicenseAgreementDlg', u'1', None), -(u'UserRegistrationDlg', u'Next', u'NewDialog', u'SetupTypeDlg', u'ProductID', 3), -(u'UserRegistrationDlg', u'Next', u'ValidateProductID', u'0', u'0', 1), -(u'UserRegistrationDlg', u'Next', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 2), -(u'VerifyReadyDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'VerifyReadyDlg', u'Back', u'NewDialog', u'AdminInstallPointDlg', u'InstallMode = "Server Image"', None), -(u'VerifyReadyDlg', u'Back', u'NewDialog', u'CustomizeDlg', u'InstallMode = "Custom" OR InstallMode = "Change"', None), -(u'VerifyReadyDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'InstallMode = "Repair"', None), -(u'VerifyReadyDlg', u'Back', u'NewDialog', u'SetupTypeDlg', u'InstallMode = "Typical" OR InstallMode = "Complete"', None), -(u'VerifyReadyDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 3), -(u'VerifyReadyDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 1), -(u'VerifyReadyDlg', u'Install', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 5), -(u'VerifyReadyDlg', u'Install', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 2), -(u'VerifyReadyDlg', u'Install', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 4), -(u'VerifyRemoveDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'VerifyRemoveDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'1', None), -(u'VerifyRemoveDlg', u'Remove', u'Remove', u'All', u'OutOfDiskSpace <> 1', 1), -(u'VerifyRemoveDlg', u'Remove', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 4), -(u'VerifyRemoveDlg', u'Remove', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 2), -(u'VerifyRemoveDlg', u'Remove', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 6), -(u'VerifyRemoveDlg', u'Remove', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 3), -(u'VerifyRemoveDlg', u'Remove', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 5), -(u'VerifyRepairDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'VerifyRepairDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'1', None), -(u'VerifyRepairDlg', u'Repair', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 5), -(u'VerifyRepairDlg', u'Repair', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 3), -(u'VerifyRepairDlg', u'Repair', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 7), -(u'VerifyRepairDlg', u'Repair', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 4), -(u'VerifyRepairDlg', u'Repair', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 6), -(u'VerifyRepairDlg', u'Repair', u'Reinstall', u'All', u'OutOfDiskSpace <> 1', 2), -(u'VerifyRepairDlg', u'Repair', u'ReinstallMode', u'ecmus', u'OutOfDiskSpace <> 1', 1), -(u'WaitForCostingDlg', u'Return', u'EndDialog', u'Exit', u'1', None), -(u'WelcomeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), -(u'WelcomeDlg', u'Next', u'NewDialog', u'LicenseAgreementDlg', u'1', None), -] - -Dialog = [ -(u'AdminWelcomeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Next', u'Next', u'Cancel'), -(u'ExitDialog', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Finish', u'Finish', u'Finish'), -(u'FatalError', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Finish', u'Finish', u'Finish'), -(u'PrepareDlg', 50, 50, 370, 270, 1, u'[ProductName] [Setup]', u'Cancel', u'Cancel', u'Cancel'), -(u'ProgressDlg', 50, 50, 370, 270, 1, u'[ProductName] [Setup]', u'Cancel', u'Cancel', u'Cancel'), -(u'UserExit', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Finish', u'Finish', u'Finish'), -(u'AdminBrowseDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'PathEdit', u'OK', u'Cancel'), -(u'AdminInstallPointDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Text', u'Next', u'Cancel'), -(u'AdminRegistrationDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'OrganizationLabel', u'Next', u'Cancel'), -(u'BrowseDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'PathEdit', u'OK', u'Cancel'), -(u'CancelDlg', 50, 10, 260, 85, 3, u'[ProductName] [Setup]', u'No', u'No', u'No'), -(u'CustomizeDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Tree', u'Next', u'Cancel'), -(u'DiskCostDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'OK', u'OK', u'OK'), -(u'ErrorDlg', 50, 10, 270, 105, 65539, u'Installer Information', u'ErrorText', None, None), -(u'FilesInUse', 50, 50, 370, 270, 19, u'[ProductName] [Setup]', u'Retry', u'Retry', u'Retry'), -(u'LicenseAgreementDlg', 50, 50, 370, 270, 3, u'[ProductName] License Agreement', u'Buttons', u'Next', u'Cancel'), -(u'MaintenanceTypeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'ChangeLabel', u'ChangeButton', u'Cancel'), -(u'MaintenanceWelcomeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Next', u'Next', u'Cancel'), -(u'OutOfDiskDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'OK', u'OK', u'OK'), -(u'OutOfRbDiskDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'No', u'No', u'No'), -(u'ResumeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Install', u'Install', u'Cancel'), -(u'SetupTypeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'TypicalLabel', u'TypicalButton', u'Cancel'), -(u'UserRegistrationDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'NameLabel', u'Next', u'Cancel'), -(u'VerifyReadyDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Install', u'Install', u'Cancel'), -(u'VerifyRemoveDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Back', u'Back', u'Cancel'), -(u'VerifyRepairDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Repair', u'Repair', u'Cancel'), -(u'WaitForCostingDlg', 50, 10, 260, 85, 3, u'[ProductName] [Setup]', u'Return', u'Return', u'Return'), -(u'WelcomeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Next', u'Next', u'Cancel'), -] - -EventMapping = [ -(u'PrepareDlg', u'ActionData', u'ActionData', u'Text'), -(u'PrepareDlg', u'ActionText', u'ActionText', u'Text'), -(u'ProgressDlg', u'ActionText', u'ActionText', u'Text'), -(u'ProgressDlg', u'ProgressBar', u'SetProgress', u'Progress'), -(u'AdminBrowseDlg', u'DirectoryCombo', u'IgnoreChange', u'IgnoreChange'), -(u'BrowseDlg', u'DirectoryCombo', u'IgnoreChange', u'IgnoreChange'), -(u'CustomizeDlg', u'Next', u'SelectionNoItems', u'Enabled'), -(u'CustomizeDlg', u'Reset', u'SelectionNoItems', u'Enabled'), -(u'CustomizeDlg', u'DiskCost', u'SelectionNoItems', u'Enabled'), -(u'CustomizeDlg', u'ItemDescription', u'SelectionDescription', u'Text'), -(u'CustomizeDlg', u'ItemSize', u'SelectionSize', u'Text'), -(u'CustomizeDlg', u'Location', u'SelectionPath', u'Text'), -(u'CustomizeDlg', u'Location', u'SelectionPathOn', u'Visible'), -(u'CustomizeDlg', u'LocationLabel', u'SelectionPathOn', u'Visible'), -] - -InstallExecuteSequence = [ -(u'InstallValidate', None, 1400), -(u'InstallInitialize', None, 1500), -(u'InstallFinalize', None, 6600), -(u'InstallFiles', None, 4000), -(u'FileCost', None, 900), -(u'CostInitialize', None, 800), -(u'CostFinalize', None, 1000), -(u'CreateShortcuts', None, 4500), -(u'PublishComponents', None, 6200), -(u'PublishFeatures', None, 6300), -(u'PublishProduct', None, 6400), -(u'RegisterClassInfo', None, 4600), -(u'RegisterExtensionInfo', None, 4700), -(u'RegisterMIMEInfo', None, 4900), -(u'RegisterProgIdInfo', None, 4800), -(u'ValidateProductID', None, 700), -(u'AllocateRegistrySpace', u'NOT Installed', 1550), -(u'AppSearch', None, 400), -(u'BindImage', None, 4300), -(u'CCPSearch', u'NOT Installed', 500), -(u'CreateFolders', None, 3700), -(u'DeleteServices', u'VersionNT', 2000), -(u'DuplicateFiles', None, 4210), -(u'FindRelatedProducts', None, 200), -(u'InstallODBC', None, 5400), -(u'InstallServices', u'VersionNT', 5800), -(u'LaunchConditions', None, 100), -(u'MigrateFeatureStates', None, 1200), -(u'MoveFiles', None, 3800), -(u'PatchFiles', None, 4090), -(u'ProcessComponents', None, 1600), -(u'RegisterComPlus', None, 5700), -(u'RegisterFonts', None, 5300), -(u'RegisterProduct', None, 6100), -(u'RegisterTypeLibraries', None, 5500), -(u'RegisterUser', None, 6000), -(u'RemoveDuplicateFiles', None, 3400), -(u'RemoveEnvironmentStrings', None, 3300), -(u'RemoveExistingProducts', None, 6700), -(u'RemoveFiles', None, 3500), -(u'RemoveFolders', None, 3600), -(u'RemoveIniValues', None, 3100), -(u'RemoveODBC', None, 2400), -(u'RemoveRegistryValues', None, 2600), -(u'RemoveShortcuts', None, 3200), -(u'RMCCPSearch', u'NOT Installed', 600), -(u'SelfRegModules', None, 5600), -(u'SelfUnregModules', None, 2200), -(u'SetODBCFolders', None, 1100), -(u'StartServices', u'VersionNT', 5900), -(u'StopServices', u'VersionNT', 1900), -(u'UnpublishComponents', None, 1700), -(u'UnpublishFeatures', None, 1800), -(u'UnregisterClassInfo', None, 2700), -(u'UnregisterComPlus', None, 2100), -(u'UnregisterExtensionInfo', None, 2800), -(u'UnregisterFonts', None, 2500), -(u'UnregisterMIMEInfo', None, 3000), -(u'UnregisterProgIdInfo', None, 2900), -(u'UnregisterTypeLibraries', None, 2300), -(u'WriteEnvironmentStrings', None, 5200), -(u'WriteIniValues', None, 5100), -(u'WriteRegistryValues', None, 5000), -] - -InstallUISequence = [ -#(u'FileCost', None, 900), -#(u'CostInitialize', None, 800), -#(u'CostFinalize', None, 1000), -#(u'ExecuteAction', None, 1300), -#(u'ExitDialog', None, -1), -#(u'FatalError', None, -3), -(u'PrepareDlg', None, 140), -(u'ProgressDlg', None, 1280), -#(u'UserExit', None, -2), -(u'MaintenanceWelcomeDlg', u'Installed AND NOT RESUME AND NOT Preselected', 1250), -(u'ResumeDlg', u'Installed AND (RESUME OR Preselected)', 1240), -(u'WelcomeDlg', u'NOT Installed', 1230), -#(u'AppSearch', None, 400), -#(u'CCPSearch', u'NOT Installed', 500), -#(u'FindRelatedProducts', None, 200), -#(u'LaunchConditions', None, 100), -#(u'MigrateFeatureStates', None, 1200), -#(u'RMCCPSearch', u'NOT Installed', 600), -] - -ListView = [ -] - -RadioButton = [ -(u'IAgree', 1, u'Yes', 5, 0, 250, 15, u'{\\DlgFont8}I &accept the terms in the License Agreement', None), -(u'IAgree', 2, u'No', 5, 20, 250, 15, u'{\\DlgFont8}I &do not accept the terms in the License Agreement', None), -] - -TextStyle = [ -(u'DlgFont8', u'Tahoma', 8, None, 0), -(u'DlgFontBold8', u'Tahoma', 8, None, 1), -(u'VerdanaBold13', u'Verdana', 13, None, 1), -] - -UIText = [ -(u'AbsentPath', None), -(u'bytes', u'bytes'), -(u'GB', u'GB'), -(u'KB', u'KB'), -(u'MB', u'MB'), -(u'MenuAbsent', u'Entire feature will be unavailable'), -(u'MenuAdvertise', u'Feature will be installed when required'), -(u'MenuAllCD', u'Entire feature will be installed to run from CD'), -(u'MenuAllLocal', u'Entire feature will be installed on local hard drive'), -(u'MenuAllNetwork', u'Entire feature will be installed to run from network'), -(u'MenuCD', u'Will be installed to run from CD'), -(u'MenuLocal', u'Will be installed on local hard drive'), -(u'MenuNetwork', u'Will be installed to run from network'), -(u'ScriptInProgress', u'Gathering required information...'), -(u'SelAbsentAbsent', u'This feature will remain uninstalled'), -(u'SelAbsentAdvertise', u'This feature will be set to be installed when required'), -(u'SelAbsentCD', u'This feature will be installed to run from CD'), -(u'SelAbsentLocal', u'This feature will be installed on the local hard drive'), -(u'SelAbsentNetwork', u'This feature will be installed to run from the network'), -(u'SelAdvertiseAbsent', u'This feature will become unavailable'), -(u'SelAdvertiseAdvertise', u'Will be installed when required'), -(u'SelAdvertiseCD', u'This feature will be available to run from CD'), -(u'SelAdvertiseLocal', u'This feature will be installed on your local hard drive'), -(u'SelAdvertiseNetwork', u'This feature will be available to run from the network'), -(u'SelCDAbsent', u"This feature will be uninstalled completely, you won't be able to run it from CD"), -(u'SelCDAdvertise', u'This feature will change from run from CD state to set to be installed when required'), -(u'SelCDCD', u'This feature will remain to be run from CD'), -(u'SelCDLocal', u'This feature will change from run from CD state to be installed on the local hard drive'), -(u'SelChildCostNeg', u'This feature frees up [1] on your hard drive.'), -(u'SelChildCostPos', u'This feature requires [1] on your hard drive.'), -(u'SelCostPending', u'Compiling cost for this feature...'), -(u'SelLocalAbsent', u'This feature will be completely removed'), -(u'SelLocalAdvertise', u'This feature will be removed from your local hard drive, but will be set to be installed when required'), -(u'SelLocalCD', u'This feature will be removed from your local hard drive, but will be still available to run from CD'), -(u'SelLocalLocal', u'This feature will remain on you local hard drive'), -(u'SelLocalNetwork', u'This feature will be removed from your local hard drive, but will be still available to run from the network'), -(u'SelNetworkAbsent', u"This feature will be uninstalled completely, you won't be able to run it from the network"), -(u'SelNetworkAdvertise', u'This feature will change from run from network state to set to be installed when required'), -(u'SelNetworkLocal', u'This feature will change from run from network state to be installed on the local hard drive'), -(u'SelNetworkNetwork', u'This feature will remain to be run from the network'), -(u'SelParentCostNegNeg', u'This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.'), -(u'SelParentCostNegPos', u'This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.'), -(u'SelParentCostPosNeg', u'This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.'), -(u'SelParentCostPosPos', u'This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.'), -(u'TimeRemaining', u'Time remaining: {[1] minutes }{[2] seconds}'), -(u'VolumeCostAvailable', u'Available'), -(u'VolumeCostDifference', u'Difference'), -(u'VolumeCostRequired', u'Required'), -(u'VolumeCostSize', u'Disk Size'), -(u'VolumeCostVolume', u'Volume'), -] - -_Validation = [ -(u'AdminExecuteSequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), -(u'AdminExecuteSequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), -(u'AdminExecuteSequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), -(u'AdminUISequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), -(u'AdminUISequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), -(u'AdminUISequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), -(u'Condition', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Expression evaluated to determine if Level in the Feature table is to change.'), -(u'Condition', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Reference to a Feature entry in Feature table.'), -(u'Condition', u'Level', u'N', 0, 32767, None, None, None, None, u'New selection Level to set in Feature table if Condition evaluates to TRUE.'), -(u'AdvtExecuteSequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), -(u'AdvtExecuteSequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), -(u'AdvtExecuteSequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), -(u'BBControl', u'Type', u'N', None, None, None, None, u'Identifier', None, u'The type of the control.'), -(u'BBControl', u'BBControl', u'N', None, None, None, None, u'Identifier', None, u'Name of the control. This name must be unique within a billboard, but can repeat on different billboard.'), -(u'BBControl', u'Billboard_', u'N', None, None, u'Billboard', 1, u'Identifier', None, u'External key to the Billboard table, name of the billboard.'), -(u'BBControl', u'X', u'N', 0, 32767, None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.'), -(u'BBControl', u'Y', u'N', 0, 32767, None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.'), -(u'BBControl', u'Width', u'N', 0, 32767, None, None, None, None, u'Width of the bounding rectangle of the control.'), -(u'BBControl', u'Height', u'N', 0, 32767, None, None, None, None, u'Height of the bounding rectangle of the control.'), -(u'BBControl', u'Attributes', u'Y', 0, 2147483647, None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.'), -(u'BBControl', u'Text', u'Y', None, None, None, None, u'Text', None, u'A string used to set the initial text contained within a control (if appropriate).'), -(u'Billboard', u'Action', u'Y', None, None, None, None, u'Identifier', None, u'The name of an action. The billboard is displayed during the progress messages received from this action.'), -(u'Billboard', u'Billboard', u'N', None, None, None, None, u'Identifier', None, u'Name of the billboard.'), -(u'Billboard', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'An external key to the Feature Table. The billboard is shown only if this feature is being installed.'), -(u'Billboard', u'Ordering', u'Y', 0, 32767, None, None, None, None, u'A positive integer. If there is more than one billboard corresponding to an action they will be shown in the order defined by this column.'), -(u'Binary', u'Name', u'N', None, None, None, None, u'Identifier', None, u'Unique key identifying the binary data.'), -(u'Binary', u'Data', u'N', None, None, None, None, u'Binary', None, u'The unformatted binary data.'), -(u'CheckBox', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to the item.'), -(u'CheckBox', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The value string associated with the item.'), -(u'Property', u'Property', u'N', None, None, None, None, u'Identifier', None, u'Name of property, uppercase if settable by launcher or loader.'), -(u'Property', u'Value', u'N', None, None, None, None, u'Text', None, u'String value for property. Never null or empty.'), -(u'ComboBox', u'Text', u'Y', None, None, None, None, u'Formatted', None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.'), -(u'ComboBox', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this item. All the items tied to the same property become part of the same combobox.'), -(u'ComboBox', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value string associated with this item. Selecting the line will set the associated property to this value.'), -(u'ComboBox', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list.\tThe integers do not have to be consecutive.'), -(u'Control', u'Type', u'N', None, None, None, None, u'Identifier', None, u'The type of the control.'), -(u'Control', u'X', u'N', 0, 32767, None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.'), -(u'Control', u'Y', u'N', 0, 32767, None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.'), -(u'Control', u'Width', u'N', 0, 32767, None, None, None, None, u'Width of the bounding rectangle of the control.'), -(u'Control', u'Height', u'N', 0, 32767, None, None, None, None, u'Height of the bounding rectangle of the control.'), -(u'Control', u'Attributes', u'Y', 0, 2147483647, None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.'), -(u'Control', u'Text', u'Y', None, None, None, None, u'Formatted', None, u'A string used to set the initial text contained within a control (if appropriate).'), -(u'Control', u'Property', u'Y', None, None, None, None, u'Identifier', None, u'The name of a defined property to be linked to this control. '), -(u'Control', u'Control', u'N', None, None, None, None, u'Identifier', None, u'Name of the control. This name must be unique within a dialog, but can repeat on different dialogs. '), -(u'Control', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'External key to the Dialog table, name of the dialog.'), -(u'Control', u'Control_Next', u'Y', None, None, u'Control', 2, u'Identifier', None, u'The name of an other control on the same dialog. This link defines the tab order of the controls. The links have to form one or more cycles!'), -(u'Control', u'Help', u'Y', None, None, None, None, u'Text', None, u'The help strings used with the button. The text is optional. '), -(u'Icon', u'Name', u'N', None, None, None, None, u'Identifier', None, u'Primary key. Name of the icon file.'), -(u'Icon', u'Data', u'N', None, None, None, None, u'Binary', None, u'Binary stream. The binary icon data in PE (.DLL or .EXE) or icon (.ICO) format.'), -(u'ListBox', u'Text', u'Y', None, None, None, None, u'Text', None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.'), -(u'ListBox', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listbox.'), -(u'ListBox', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value string associated with this item. Selecting the line will set the associated property to this value.'), -(u'ListBox', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.'), -(u'ActionText', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to be described.'), -(u'ActionText', u'Description', u'Y', None, None, None, None, u'Text', None, u'Localized description displayed in progress dialog and log when action is executing.'), -(u'ActionText', u'Template', u'Y', None, None, None, None, u'Template', None, u'Optional localized format template used to format action data records for display during action execution.'), -(u'ControlCondition', u'Action', u'N', None, None, None, None, None, u'Default;Disable;Enable;Hide;Show', u'The desired action to be taken on the specified control.'), -(u'ControlCondition', u'Condition', u'N', None, None, None, None, u'Condition', None, u'A standard conditional statement that specifies under which conditions the action should be triggered.'), -(u'ControlCondition', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'A foreign key to the Dialog table, name of the dialog.'), -(u'ControlCondition', u'Control_', u'N', None, None, u'Control', 2, u'Identifier', None, u'A foreign key to the Control table, name of the control.'), -(u'ControlEvent', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'A standard conditional statement that specifies under which conditions an event should be triggered.'), -(u'ControlEvent', u'Ordering', u'Y', 0, 2147483647, None, None, None, None, u'An integer used to order several events tied to the same control. Can be left blank.'), -(u'ControlEvent', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'A foreign key to the Dialog table, name of the dialog.'), -(u'ControlEvent', u'Control_', u'N', None, None, u'Control', 2, u'Identifier', None, u'A foreign key to the Control table, name of the control'), -(u'ControlEvent', u'Event', u'N', None, None, None, None, u'Formatted', None, u'An identifier that specifies the type of the event that should take place when the user interacts with control specified by the first two entries.'), -(u'ControlEvent', u'Argument', u'N', None, None, None, None, u'Formatted', None, u'A value to be used as a modifier when triggering a particular event.'), -(u'Dialog', u'Width', u'N', 0, 32767, None, None, None, None, u'Width of the bounding rectangle of the dialog.'), -(u'Dialog', u'Height', u'N', 0, 32767, None, None, None, None, u'Height of the bounding rectangle of the dialog.'), -(u'Dialog', u'Attributes', u'Y', 0, 2147483647, None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this dialog.'), -(u'Dialog', u'Title', u'Y', None, None, None, None, u'Formatted', None, u"A text string specifying the title to be displayed in the title bar of the dialog's window."), -(u'Dialog', u'Dialog', u'N', None, None, None, None, u'Identifier', None, u'Name of the dialog.'), -(u'Dialog', u'HCentering', u'N', 0, 100, None, None, None, None, u'Horizontal position of the dialog on a 0-100 scale. 0 means left end, 100 means right end of the screen, 50 center.'), -(u'Dialog', u'VCentering', u'N', 0, 100, None, None, None, None, u'Vertical position of the dialog on a 0-100 scale. 0 means top end, 100 means bottom end of the screen, 50 center.'), -(u'Dialog', u'Control_First', u'N', None, None, u'Control', 2, u'Identifier', None, u'Defines the control that has the focus when the dialog is created.'), -(u'Dialog', u'Control_Default', u'Y', None, None, u'Control', 2, u'Identifier', None, u'Defines the default control. Hitting return is equivalent to pushing this button.'), -(u'Dialog', u'Control_Cancel', u'Y', None, None, u'Control', 2, u'Identifier', None, u'Defines the cancel control. Hitting escape or clicking on the close icon on the dialog is equivalent to pushing this button.'), -(u'EventMapping', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'A foreign key to the Dialog table, name of the Dialog.'), -(u'EventMapping', u'Control_', u'N', None, None, u'Control', 2, u'Identifier', None, u'A foreign key to the Control table, name of the control.'), -(u'EventMapping', u'Event', u'N', None, None, None, None, u'Identifier', None, u'An identifier that specifies the type of the event that the control subscribes to.'), -(u'EventMapping', u'Attribute', u'N', None, None, None, None, u'Identifier', None, u'The name of the control attribute, that is set when this event is received.'), -(u'InstallExecuteSequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), -(u'InstallExecuteSequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), -(u'InstallExecuteSequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), -(u'AppSearch', u'Property', u'N', None, None, None, None, u'Identifier', None, u'The property associated with a Signature'), -(u'AppSearch', u'Signature_', u'N', None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator', 1, u'Identifier', None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.'), -(u'BindImage', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'The index into the File table. This must be an executable file.'), -(u'BindImage', u'Path', u'Y', None, None, None, None, u'Paths', None, u'A list of ; delimited paths that represent the paths to be searched for the import DLLS. The list is usually a list of properties each enclosed within square brackets [] .'), -(u'CCPSearch', u'Signature_', u'N', None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator', 1, u'Identifier', None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.'), -(u'InstallUISequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), -(u'InstallUISequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), -(u'InstallUISequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), -(u'ListView', u'Text', u'Y', None, None, None, None, u'Text', None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.'), -(u'ListView', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listview.'), -(u'ListView', u'Value', u'N', None, None, None, None, u'Identifier', None, u'The value string associated with this item. Selecting the line will set the associated property to this value.'), -(u'ListView', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.'), -(u'ListView', u'Binary_', u'Y', None, None, u'Binary', 1, u'Identifier', None, u'The name of the icon to be displayed with the icon. The binary information is looked up from the Binary Table.'), -(u'RadioButton', u'X', u'N', 0, 32767, None, None, None, None, u'The horizontal coordinate of the upper left corner of the bounding rectangle of the radio button.'), -(u'RadioButton', u'Y', u'N', 0, 32767, None, None, None, None, u'The vertical coordinate of the upper left corner of the bounding rectangle of the radio button.'), -(u'RadioButton', u'Width', u'N', 0, 32767, None, None, None, None, u'The width of the button.'), -(u'RadioButton', u'Height', u'N', 0, 32767, None, None, None, None, u'The height of the button.'), -(u'RadioButton', u'Text', u'Y', None, None, None, None, u'Text', None, u'The visible title to be assigned to the radio button.'), -(u'RadioButton', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this radio button. All the buttons tied to the same property become part of the same group.'), -(u'RadioButton', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value string associated with this button. Selecting the button will set the associated property to this value.'), -(u'RadioButton', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.'), -(u'RadioButton', u'Help', u'Y', None, None, None, None, u'Text', None, u'The help strings used with the button. The text is optional.'), -(u'TextStyle', u'TextStyle', u'N', None, None, None, None, u'Identifier', None, u'Name of the style. The primary key of this table. This name is embedded in the texts to indicate a style change.'), -(u'TextStyle', u'FaceName', u'N', None, None, None, None, u'Text', None, u'A string indicating the name of the font used. Required. The string must be at most 31 characters long.'), -(u'TextStyle', u'Size', u'N', 0, 32767, None, None, None, None, u'The size of the font used. This size is given in our units (1/12 of the system font height). Assuming that the system font is set to 12 point size, this is equivalent to the point size.'), -(u'TextStyle', u'Color', u'Y', 0, 16777215, None, None, None, None, u'A long integer indicating the color of the string in the RGB format (Red, Green, Blue each 0-255, RGB = R + 256*G + 256^2*B).'), -(u'TextStyle', u'StyleBits', u'Y', 0, 15, None, None, None, None, u'A combination of style bits.'), -(u'UIText', u'Text', u'Y', None, None, None, None, u'Text', None, u'The localized version of the string.'), -(u'UIText', u'Key', u'N', None, None, None, None, u'Identifier', None, u'A unique key that identifies the particular string.'), -(u'_Validation', u'Table', u'N', None, None, None, None, u'Identifier', None, u'Name of table'), -(u'_Validation', u'Description', u'Y', None, None, None, None, u'Text', None, u'Description of column'), -(u'_Validation', u'Column', u'N', None, None, None, None, u'Identifier', None, u'Name of column'), -(u'_Validation', u'Nullable', u'N', None, None, None, None, None, u'Y;N;@', u'Whether the column is nullable'), -(u'_Validation', u'MinValue', u'Y', -2147483647, 2147483647, None, None, None, None, u'Minimum value allowed'), -(u'_Validation', u'MaxValue', u'Y', -2147483647, 2147483647, None, None, None, None, u'Maximum value allowed'), -(u'_Validation', u'KeyTable', u'Y', None, None, None, None, u'Identifier', None, u'For foreign key, Name of table to which data must link'), -(u'_Validation', u'KeyColumn', u'Y', 1, 32, None, None, None, None, u'Column to which foreign key connects'), -(u'_Validation', u'Category', u'Y', None, None, None, None, None, u'Text;Formatted;Template;Condition;Guid;Path;Version;Language;Identifier;Binary;UpperCase;LowerCase;Filename;Paths;AnyPath;WildCardFilename;RegPath;KeyFormatted;CustomSource;Property;Cabinet;Shortcut;URL', u'String category'), -(u'_Validation', u'Set', u'Y', None, None, None, None, u'Text', None, u'Set of values that are permitted'), -(u'AdvtUISequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), -(u'AdvtUISequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), -(u'AdvtUISequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), -(u'AppId', u'AppId', u'N', None, None, None, None, u'Guid', None, None), -(u'AppId', u'ActivateAtStorage', u'Y', 0, 1, None, None, None, None, None), -(u'AppId', u'DllSurrogate', u'Y', None, None, None, None, u'Text', None, None), -(u'AppId', u'LocalService', u'Y', None, None, None, None, u'Text', None, None), -(u'AppId', u'RemoteServerName', u'Y', None, None, None, None, u'Formatted', None, None), -(u'AppId', u'RunAsInteractiveUser', u'Y', 0, 1, None, None, None, None, None), -(u'AppId', u'ServiceParameters', u'Y', None, None, None, None, u'Text', None, None), -(u'Feature', u'Attributes', u'N', None, None, None, None, None, u'0;1;2;4;5;6;8;9;10;16;17;18;20;21;22;24;25;26;32;33;34;36;37;38;48;49;50;52;53;54', u'Feature attributes'), -(u'Feature', u'Description', u'Y', None, None, None, None, u'Text', None, u'Longer descriptive text describing a visible feature item.'), -(u'Feature', u'Title', u'Y', None, None, None, None, u'Text', None, u'Short text identifying a visible feature item.'), -(u'Feature', u'Feature', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular feature record.'), -(u'Feature', u'Directory_', u'Y', None, None, u'Directory', 1, u'UpperCase', None, u'The name of the Directory that can be configured by the UI. A non-null value will enable the browse button.'), -(u'Feature', u'Level', u'N', 0, 32767, None, None, None, None, u'The install level at which record will be initially selected. An install level of 0 will disable an item and prevent its display.'), -(u'Feature', u'Display', u'Y', 0, 32767, None, None, None, None, u'Numeric sort order, used to force a specific display ordering.'), -(u'Feature', u'Feature_Parent', u'Y', None, None, u'Feature', 1, u'Identifier', None, u'Optional key of a parent record in the same table. If the parent is not selected, then the record will not be installed. Null indicates a root item.'), -(u'File', u'Sequence', u'N', 1, 32767, None, None, None, None, u'Sequence with respect to the media images; order must track cabinet order.'), -(u'File', u'Attributes', u'Y', 0, 32767, None, None, None, None, u'Integer containing bit flags representing file attributes (with the decimal value of each bit position in parentheses)'), -(u'File', u'File', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token, must match identifier in cabinet. For uncompressed files, this field is ignored.'), -(u'File', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the file.'), -(u'File', u'FileName', u'N', None, None, None, None, u'Filename', None, u'File name used for installation, may be localized. This may contain a "short name|long name" pair.'), -(u'File', u'FileSize', u'N', 0, 2147483647, None, None, None, None, u'Size of file in bytes (long integer).'), -(u'File', u'Language', u'Y', None, None, None, None, u'Language', None, u'List of decimal language Ids, comma-separated if more than one.'), -(u'File', u'Version', u'Y', None, None, u'File', 1, u'Version', None, u'Version string for versioned files; Blank for unversioned files.'), -(u'Class', u'Attributes', u'Y', None, 32767, None, None, None, None, u'Class registration attributes.'), -(u'Class', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.'), -(u'Class', u'Description', u'Y', None, None, None, None, u'Text', None, u'Localized description for the Class.'), -(u'Class', u'Argument', u'Y', None, None, None, None, u'Formatted', None, u'optional argument for LocalServers.'), -(u'Class', u'AppId_', u'Y', None, None, u'AppId', 1, u'Guid', None, u'Optional AppID containing DCOM information for associated application (string GUID).'), -(u'Class', u'CLSID', u'N', None, None, None, None, u'Guid', None, u'The CLSID of an OLE factory.'), -(u'Class', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.'), -(u'Class', u'Context', u'N', None, None, None, None, u'Identifier', None, u'The numeric server context for this server. CLSCTX_xxxx'), -(u'Class', u'DefInprocHandler', u'Y', None, None, None, None, u'Filename', u'1;2;3', u'Optional default inproc handler. Only optionally provided if Context=CLSCTX_LOCAL_SERVER. Typically "ole32.dll" or "mapi32.dll"'), -(u'Class', u'FileTypeMask', u'Y', None, None, None, None, u'Text', None, u'Optional string containing information for the HKCRthis CLSID) key. If multiple patterns exist, they must be delimited by a semicolon, and numeric subkeys will be generated: 0,1,2...'), -(u'Class', u'Icon_', u'Y', None, None, u'Icon', 1, u'Identifier', None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this CLSID. Will be written under the DefaultIcon key.'), -(u'Class', u'IconIndex', u'Y', -32767, 32767, None, None, None, None, u'Optional icon index.'), -(u'Class', u'ProgId_Default', u'Y', None, None, u'ProgId', 1, u'Text', None, u'Optional ProgId associated with this CLSID.'), -(u'Component', u'Condition', u'Y', None, None, None, None, u'Condition', None, u"A conditional statement that will disable this component if the specified condition evaluates to the 'True' state. If a component is disabled, it will not be installed, regardless of the 'Action' state associated with the component."), -(u'Component', u'Attributes', u'N', None, None, None, None, None, None, u'Remote execution option, one of irsEnum'), -(u'Component', u'Component', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular component record.'), -(u'Component', u'ComponentId', u'Y', None, None, None, None, u'Guid', None, u'A string GUID unique to this component, version, and language.'), -(u'Component', u'Directory_', u'N', None, None, u'Directory', 1, u'Identifier', None, u'Required key of a Directory table record. This is actually a property name whose value contains the actual path, set either by the AppSearch action or with the default setting obtained from the Directory table.'), -(u'Component', u'KeyPath', u'Y', None, None, u'File;Registry;ODBCDataSource', 1, u'Identifier', None, u'Either the primary key into the File table, Registry table, or ODBCDataSource table. This extract path is stored when the component is installed, and is used to detect the presence of the component and to return the path to it.'), -(u'ProgId', u'Description', u'Y', None, None, None, None, u'Text', None, u'Localized description for the Program identifier.'), -(u'ProgId', u'Icon_', u'Y', None, None, u'Icon', 1, u'Identifier', None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this ProgId. Will be written under the DefaultIcon key.'), -(u'ProgId', u'IconIndex', u'Y', -32767, 32767, None, None, None, None, u'Optional icon index.'), -(u'ProgId', u'ProgId', u'N', None, None, None, None, u'Text', None, u'The Program Identifier. Primary key.'), -(u'ProgId', u'Class_', u'Y', None, None, u'Class', 1, u'Guid', None, u'The CLSID of an OLE factory corresponding to the ProgId.'), -(u'ProgId', u'ProgId_Parent', u'Y', None, None, u'ProgId', 1, u'Text', None, u'The Parent Program Identifier. If specified, the ProgId column becomes a version independent prog id.'), -(u'CompLocator', u'Type', u'Y', 0, 1, None, None, None, None, u'A boolean value that determines if the registry value is a filename or a directory location.'), -(u'CompLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.'), -(u'CompLocator', u'ComponentId', u'N', None, None, None, None, u'Guid', None, u'A string GUID unique to this component, version, and language.'), -(u'Complus', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the ComPlus component.'), -(u'Complus', u'ExpType', u'Y', 0, 32767, None, None, None, None, u'ComPlus component attributes.'), -(u'Directory', u'Directory', u'N', None, None, None, None, u'Identifier', None, u'Unique identifier for directory entry, primary key. If a property by this name is defined, it contains the full path to the directory.'), -(u'Directory', u'DefaultDir', u'N', None, None, None, None, u'DefaultDir', None, u"The default sub-path under parent's path."), -(u'Directory', u'Directory_Parent', u'Y', None, None, u'Directory', 1, u'Identifier', None, u'Reference to the entry in this table specifying the default parent directory. A record parented to itself or with a Null parent represents a root of the install tree.'), -(u'CreateFolder', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table.'), -(u'CreateFolder', u'Directory_', u'N', None, None, u'Directory', 1, u'Identifier', None, u'Primary key, could be foreign key into the Directory table.'), -(u'CustomAction', u'Type', u'N', 1, 16383, None, None, None, None, u'The numeric custom action type, consisting of source location, code type, entry, option flags.'), -(u'CustomAction', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Primary key, name of action, normally appears in sequence table unless private use.'), -(u'CustomAction', u'Source', u'Y', None, None, None, None, u'CustomSource', None, u'The table reference of the source of the code.'), -(u'CustomAction', u'Target', u'Y', None, None, None, None, u'Formatted', None, u'Excecution parameter, depends on the type of custom action'), -(u'DrLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature table.'), -(u'DrLocator', u'Path', u'Y', None, None, None, None, u'AnyPath', None, u'The path on the user system. This is a either a subpath below the value of the Parent or a full path. The path may contain properties enclosed within [ ] that will be expanded.'), -(u'DrLocator', u'Depth', u'Y', 0, 32767, None, None, None, None, u'The depth below the path to which the Signature_ is recursively searched. If absent, the depth is assumed to be 0.'), -(u'DrLocator', u'Parent', u'Y', None, None, None, None, u'Identifier', None, u'The parent file signature. It is also a foreign key in the Signature table. If null and the Path column does not expand to a full path, then all the fixed drives of the user system are searched using the Path.'), -(u'DuplicateFile', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Foreign key referencing the source file to be duplicated.'), -(u'DuplicateFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the duplicate file.'), -(u'DuplicateFile', u'DestFolder', u'Y', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full pathname to a destination folder.'), -(u'DuplicateFile', u'DestName', u'Y', None, None, None, None, u'Filename', None, u'Filename to be given to the duplicate file.'), -(u'DuplicateFile', u'FileKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular file entry'), -(u'Environment', u'Name', u'N', None, None, None, None, u'Text', None, u'The name of the environmental value.'), -(u'Environment', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The value to set in the environmental settings.'), -(u'Environment', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the installing of the environmental value.'), -(u'Environment', u'Environment', u'N', None, None, None, None, u'Identifier', None, u'Unique identifier for the environmental variable setting'), -(u'Error', u'Error', u'N', 0, 32767, None, None, None, None, u'Integer error number, obtained from header file IError(...) macros.'), -(u'Error', u'Message', u'Y', None, None, None, None, u'Template', None, u'Error formatting template, obtained from user ed. or localizers.'), -(u'Extension', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.'), -(u'Extension', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.'), -(u'Extension', u'Extension', u'N', None, None, None, None, u'Text', None, u'The extension associated with the table row.'), -(u'Extension', u'MIME_', u'Y', None, None, u'MIME', 1, u'Text', None, u'Optional Context identifier, typically "type/format" associated with the extension'), -(u'Extension', u'ProgId_', u'Y', None, None, u'ProgId', 1, u'Text', None, u'Optional ProgId associated with this extension.'), -(u'MIME', u'CLSID', u'Y', None, None, None, None, u'Guid', None, u'Optional associated CLSID.'), -(u'MIME', u'ContentType', u'N', None, None, None, None, u'Text', None, u'Primary key. Context identifier, typically "type/format".'), -(u'MIME', u'Extension_', u'N', None, None, u'Extension', 1, u'Text', None, u'Optional associated extension (without dot)'), -(u'FeatureComponents', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Foreign key into Feature table.'), -(u'FeatureComponents', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into Component table.'), -(u'FileSFPCatalog', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'File associated with the catalog'), -(u'FileSFPCatalog', u'SFPCatalog_', u'N', None, None, u'SFPCatalog', 1, u'Filename', None, u'Catalog associated with the file'), -(u'SFPCatalog', u'SFPCatalog', u'N', None, None, None, None, u'Filename', None, u'File name for the catalog.'), -(u'SFPCatalog', u'Catalog', u'N', None, None, None, None, u'Binary', None, u'SFP Catalog'), -(u'SFPCatalog', u'Dependency', u'Y', None, None, None, None, u'Formatted', None, u'Parent catalog - only used by SFP'), -(u'Font', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Primary key, foreign key into File table referencing font file.'), -(u'Font', u'FontTitle', u'Y', None, None, None, None, u'Text', None, u'Font name.'), -(u'IniFile', u'Action', u'N', None, None, None, None, None, u'0;1;3', u'The type of modification to be made, one of iifEnum'), -(u'IniFile', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value to be written.'), -(u'IniFile', u'Key', u'N', None, None, None, None, u'Formatted', None, u'The .INI file key below Section.'), -(u'IniFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the installing of the .INI value.'), -(u'IniFile', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The .INI file name in which to write the information'), -(u'IniFile', u'IniFile', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), -(u'IniFile', u'DirProperty', u'Y', None, None, None, None, u'Identifier', None, u'Foreign key into the Directory table denoting the directory where the .INI file is.'), -(u'IniFile', u'Section', u'N', None, None, None, None, u'Formatted', None, u'The .INI file Section.'), -(u'IniLocator', u'Type', u'Y', 0, 2, None, None, None, None, u'An integer value that determines if the .INI value read is a filename or a directory location or to be used as is w/o interpretation.'), -(u'IniLocator', u'Key', u'N', None, None, None, None, u'Text', None, u'Key value (followed by an equals sign in INI file).'), -(u'IniLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.'), -(u'IniLocator', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The .INI file name.'), -(u'IniLocator', u'Section', u'N', None, None, None, None, u'Text', None, u'Section name within in file (within square brackets in INI file).'), -(u'IniLocator', u'Field', u'Y', 0, 32767, None, None, None, None, u'The field in the .INI line. If Field is null or 0 the entire line is read.'), -(u'IsolatedComponent', u'Component_Application', u'N', None, None, u'Component', 1, u'Identifier', None, u'Key to Component table item for application'), -(u'IsolatedComponent', u'Component_Shared', u'N', None, None, u'Component', 1, u'Identifier', None, u'Key to Component table item to be isolated'), -(u'LaunchCondition', u'Condition', u'N', None, None, None, None, u'Condition', None, u'Expression which must evaluate to TRUE in order for install to commence.'), -(u'LaunchCondition', u'Description', u'N', None, None, None, None, u'Formatted', None, u'Localizable text to display when condition fails and install must abort.'), -(u'LockPermissions', u'Table', u'N', None, None, None, None, u'Identifier', u'Directory;File;Registry', u'Reference to another table name'), -(u'LockPermissions', u'Domain', u'Y', None, None, None, None, u'Formatted', None, u'Domain name for user whose permissions are being set. (usually a property)'), -(u'LockPermissions', u'LockObject', u'N', None, None, None, None, u'Identifier', None, u'Foreign key into Registry or File table'), -(u'LockPermissions', u'Permission', u'Y', -2147483647, 2147483647, None, None, None, None, u'Permission Access mask. Full Control = 268435456 (GENERIC_ALL = 0x10000000)'), -(u'LockPermissions', u'User', u'N', None, None, None, None, u'Formatted', None, u'User for permissions to be set. (usually a property)'), -(u'Media', u'Source', u'Y', None, None, None, None, u'Property', None, u'The property defining the location of the cabinet file.'), -(u'Media', u'Cabinet', u'Y', None, None, None, None, u'Cabinet', None, u'If some or all of the files stored on the media are compressed in a cabinet, the name of that cabinet.'), -(u'Media', u'DiskId', u'N', 1, 32767, None, None, None, None, u'Primary key, integer to determine sort order for table.'), -(u'Media', u'DiskPrompt', u'Y', None, None, None, None, u'Text', None, u'Disk name: the visible text actually printed on the disk. This will be used to prompt the user when this disk needs to be inserted.'), -(u'Media', u'LastSequence', u'N', 0, 32767, None, None, None, None, u'File sequence number for the last file for this media.'), -(u'Media', u'VolumeLabel', u'Y', None, None, None, None, u'Text', None, u'The label attributed to the volume.'), -(u'ModuleComponents', u'Component', u'N', None, None, u'Component', 1, u'Identifier', None, u'Component contained in the module.'), -(u'ModuleComponents', u'Language', u'N', None, None, u'ModuleSignature', 2, None, None, u'Default language ID for module (may be changed by transform).'), -(u'ModuleComponents', u'ModuleID', u'N', None, None, u'ModuleSignature', 1, u'Identifier', None, u'Module containing the component.'), -(u'ModuleSignature', u'Language', u'N', None, None, None, None, None, None, u'Default decimal language of module.'), -(u'ModuleSignature', u'Version', u'N', None, None, None, None, u'Version', None, u'Version of the module.'), -(u'ModuleSignature', u'ModuleID', u'N', None, None, None, None, u'Identifier', None, u'Module identifier (String.GUID).'), -(u'ModuleDependency', u'ModuleID', u'N', None, None, u'ModuleSignature', 1, u'Identifier', None, u'Module requiring the dependency.'), -(u'ModuleDependency', u'ModuleLanguage', u'N', None, None, u'ModuleSignature', 2, None, None, u'Language of module requiring the dependency.'), -(u'ModuleDependency', u'RequiredID', u'N', None, None, None, None, None, None, u'String.GUID of required module.'), -(u'ModuleDependency', u'RequiredLanguage', u'N', None, None, None, None, None, None, u'LanguageID of the required module.'), -(u'ModuleDependency', u'RequiredVersion', u'Y', None, None, None, None, u'Version', None, u'Version of the required version.'), -(u'ModuleExclusion', u'ModuleID', u'N', None, None, u'ModuleSignature', 1, u'Identifier', None, u'String.GUID of module with exclusion requirement.'), -(u'ModuleExclusion', u'ModuleLanguage', u'N', None, None, u'ModuleSignature', 2, None, None, u'LanguageID of module with exclusion requirement.'), -(u'ModuleExclusion', u'ExcludedID', u'N', None, None, None, None, None, None, u'String.GUID of excluded module.'), -(u'ModuleExclusion', u'ExcludedLanguage', u'N', None, None, None, None, None, None, u'Language of excluded module.'), -(u'ModuleExclusion', u'ExcludedMaxVersion', u'Y', None, None, None, None, u'Version', None, u'Maximum version of excluded module.'), -(u'ModuleExclusion', u'ExcludedMinVersion', u'Y', None, None, None, None, u'Version', None, u'Minimum version of excluded module.'), -(u'MoveFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'If this component is not "selected" for installation or removal, no action will be taken on the associated MoveFile entry'), -(u'MoveFile', u'DestFolder', u'N', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory'), -(u'MoveFile', u'DestName', u'Y', None, None, None, None, u'Filename', None, u'Name to be given to the original file after it is moved or copied. If blank, the destination file will be given the same name as the source file'), -(u'MoveFile', u'FileKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key that uniquely identifies a particular MoveFile record'), -(u'MoveFile', u'Options', u'N', 0, 1, None, None, None, None, u'Integer value specifying the MoveFile operating mode, one of imfoEnum'), -(u'MoveFile', u'SourceFolder', u'Y', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full path to the source directory'), -(u'MoveFile', u'SourceName', u'Y', None, None, None, None, u'Text', None, u"Name of the source file(s) to be moved or copied. Can contain the '*' or '?' wildcards."), -(u'MsiAssembly', u'Attributes', u'Y', None, None, None, None, None, None, u'Assembly attributes'), -(u'MsiAssembly', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Foreign key into Feature table.'), -(u'MsiAssembly', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into Component table.'), -(u'MsiAssembly', u'File_Application', u'Y', None, None, u'File', 1, u'Identifier', None, u'Foreign key into File table, denoting the application context for private assemblies. Null for global assemblies.'), -(u'MsiAssembly', u'File_Manifest', u'Y', None, None, u'File', 1, u'Identifier', None, u'Foreign key into the File table denoting the manifest file for the assembly.'), -(u'MsiAssemblyName', u'Name', u'N', None, None, None, None, u'Text', None, u'The name part of the name-value pairs for the assembly name.'), -(u'MsiAssemblyName', u'Value', u'N', None, None, None, None, u'Text', None, u'The value part of the name-value pairs for the assembly name.'), -(u'MsiAssemblyName', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into Component table.'), -(u'MsiDigitalCertificate', u'CertData', u'N', None, None, None, None, u'Binary', None, u'A certificate context blob for a signer certificate'), -(u'MsiDigitalCertificate', u'DigitalCertificate', u'N', None, None, None, None, u'Identifier', None, u'A unique identifier for the row'), -(u'MsiDigitalSignature', u'Table', u'N', None, None, None, None, None, u'Media', u'Reference to another table name (only Media table is supported)'), -(u'MsiDigitalSignature', u'DigitalCertificate_', u'N', None, None, u'MsiDigitalCertificate', 1, u'Identifier', None, u'Foreign key to MsiDigitalCertificate table identifying the signer certificate'), -(u'MsiDigitalSignature', u'Hash', u'Y', None, None, None, None, u'Binary', None, u'The encoded hash blob from the digital signature'), -(u'MsiDigitalSignature', u'SignObject', u'N', None, None, None, None, u'Text', None, u'Foreign key to Media table'), -(u'MsiFileHash', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Primary key, foreign key into File table referencing file with this hash'), -(u'MsiFileHash', u'Options', u'N', 0, 32767, None, None, None, None, u'Various options and attributes for this hash.'), -(u'MsiFileHash', u'HashPart1', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), -(u'MsiFileHash', u'HashPart2', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), -(u'MsiFileHash', u'HashPart3', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), -(u'MsiFileHash', u'HashPart4', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), -(u'MsiPatchHeaders', u'StreamRef', u'N', None, None, None, None, u'Identifier', None, u'Primary key. A unique identifier for the row.'), -(u'MsiPatchHeaders', u'Header', u'N', None, None, None, None, u'Binary', None, u'Binary stream. The patch header, used for patch validation.'), -(u'ODBCAttribute', u'Value', u'Y', None, None, None, None, u'Text', None, u'Value for ODBC driver attribute'), -(u'ODBCAttribute', u'Attribute', u'N', None, None, None, None, u'Text', None, u'Name of ODBC driver attribute'), -(u'ODBCAttribute', u'Driver_', u'N', None, None, u'ODBCDriver', 1, u'Identifier', None, u'Reference to ODBC driver in ODBCDriver table'), -(u'ODBCDriver', u'Description', u'N', None, None, None, None, u'Text', None, u'Text used as registered name for driver, non-localized'), -(u'ODBCDriver', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Reference to key driver file'), -(u'ODBCDriver', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reference to associated component'), -(u'ODBCDriver', u'Driver', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized.internal token for driver'), -(u'ODBCDriver', u'File_Setup', u'Y', None, None, u'File', 1, u'Identifier', None, u'Optional reference to key driver setup DLL'), -(u'ODBCDataSource', u'Description', u'N', None, None, None, None, u'Text', None, u'Text used as registered name for data source'), -(u'ODBCDataSource', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reference to associated component'), -(u'ODBCDataSource', u'DataSource', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized.internal token for data source'), -(u'ODBCDataSource', u'DriverDescription', u'N', None, None, None, None, u'Text', None, u'Reference to driver description, may be existing driver'), -(u'ODBCDataSource', u'Registration', u'N', 0, 1, None, None, None, None, u'Registration option: 0=machine, 1=user, others t.b.d.'), -(u'ODBCSourceAttribute', u'Value', u'Y', None, None, None, None, u'Text', None, u'Value for ODBC data source attribute'), -(u'ODBCSourceAttribute', u'Attribute', u'N', None, None, None, None, u'Text', None, u'Name of ODBC data source attribute'), -(u'ODBCSourceAttribute', u'DataSource_', u'N', None, None, u'ODBCDataSource', 1, u'Identifier', None, u'Reference to ODBC data source in ODBCDataSource table'), -(u'ODBCTranslator', u'Description', u'N', None, None, None, None, u'Text', None, u'Text used as registered name for translator'), -(u'ODBCTranslator', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Reference to key translator file'), -(u'ODBCTranslator', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reference to associated component'), -(u'ODBCTranslator', u'File_Setup', u'Y', None, None, u'File', 1, u'Identifier', None, u'Optional reference to key translator setup DLL'), -(u'ODBCTranslator', u'Translator', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized.internal token for translator'), -(u'Patch', u'Sequence', u'N', 0, 32767, None, None, None, None, u'Primary key, sequence with respect to the media images; order must track cabinet order.'), -(u'Patch', u'Attributes', u'N', 0, 32767, None, None, None, None, u'Integer containing bit flags representing patch attributes'), -(u'Patch', u'File_', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token, foreign key to File table, must match identifier in cabinet.'), -(u'Patch', u'Header', u'Y', None, None, None, None, u'Binary', None, u'Binary stream. The patch header, used for patch validation.'), -(u'Patch', u'PatchSize', u'N', 0, 2147483647, None, None, None, None, u'Size of patch in bytes (long integer).'), -(u'Patch', u'StreamRef_', u'Y', None, None, None, None, u'Identifier', None, u'Identifier. Foreign key to the StreamRef column of the MsiPatchHeaders table.'), -(u'PatchPackage', u'Media_', u'N', 0, 32767, None, None, None, None, u'Foreign key to DiskId column of Media table. Indicates the disk containing the patch package.'), -(u'PatchPackage', u'PatchId', u'N', None, None, None, None, u'Guid', None, u'A unique string GUID representing this patch.'), -(u'PublishComponent', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Foreign key into the Feature table.'), -(u'PublishComponent', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table.'), -(u'PublishComponent', u'ComponentId', u'N', None, None, None, None, u'Guid', None, u'A string GUID that represents the component id that will be requested by the alien product.'), -(u'PublishComponent', u'AppData', u'Y', None, None, None, None, u'Text', None, u'This is localisable Application specific data that can be associated with a Qualified Component.'), -(u'PublishComponent', u'Qualifier', u'N', None, None, None, None, u'Text', None, u'This is defined only when the ComponentId column is an Qualified Component Id. This is the Qualifier for ProvideComponentIndirect.'), -(u'Registry', u'Name', u'Y', None, None, None, None, u'Formatted', None, u'The registry value name.'), -(u'Registry', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The registry value.'), -(u'Registry', u'Key', u'N', None, None, None, None, u'RegPath', None, u'The key for the registry value.'), -(u'Registry', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the installing of the registry value.'), -(u'Registry', u'Registry', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), -(u'Registry', u'Root', u'N', -1, 3, None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.'), -(u'RegLocator', u'Name', u'Y', None, None, None, None, u'Formatted', None, u'The registry value name.'), -(u'RegLocator', u'Type', u'Y', 0, 18, None, None, None, None, u'An integer value that determines if the registry value is a filename or a directory location or to be used as is w/o interpretation.'), -(u'RegLocator', u'Key', u'N', None, None, None, None, u'RegPath', None, u'The key for the registry value.'), -(u'RegLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table. If the type is 0, the registry values refers a directory, and _Signature is not a foreign key.'), -(u'RegLocator', u'Root', u'N', 0, 3, None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.'), -(u'RemoveFile', u'InstallMode', u'N', None, None, None, None, None, u'1;2;3', u'Installation option, one of iimEnum.'), -(u'RemoveFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the file to be removed.'), -(u'RemoveFile', u'FileKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular file entry'), -(u'RemoveFile', u'FileName', u'Y', None, None, None, None, u'WildCardFilename', None, u'Name of the file to be removed.'), -(u'RemoveFile', u'DirProperty', u'N', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full pathname to the folder of the file to be removed.'), -(u'RemoveIniFile', u'Action', u'N', None, None, None, None, None, u'2;4', u'The type of modification to be made, one of iifEnum.'), -(u'RemoveIniFile', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The value to be deleted. The value is required when Action is iifIniRemoveTag'), -(u'RemoveIniFile', u'Key', u'N', None, None, None, None, u'Formatted', None, u'The .INI file key below Section.'), -(u'RemoveIniFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the deletion of the .INI value.'), -(u'RemoveIniFile', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The .INI file name in which to delete the information'), -(u'RemoveIniFile', u'DirProperty', u'Y', None, None, None, None, u'Identifier', None, u'Foreign key into the Directory table denoting the directory where the .INI file is.'), -(u'RemoveIniFile', u'Section', u'N', None, None, None, None, u'Formatted', None, u'The .INI file Section.'), -(u'RemoveIniFile', u'RemoveIniFile', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), -(u'RemoveRegistry', u'Name', u'Y', None, None, None, None, u'Formatted', None, u'The registry value name.'), -(u'RemoveRegistry', u'Key', u'N', None, None, None, None, u'RegPath', None, u'The key for the registry value.'), -(u'RemoveRegistry', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the deletion of the registry value.'), -(u'RemoveRegistry', u'Root', u'N', -1, 3, None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum'), -(u'RemoveRegistry', u'RemoveRegistry', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), -(u'ReserveCost', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reserve a specified amount of space if this component is to be installed.'), -(u'ReserveCost', u'ReserveFolder', u'Y', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory'), -(u'ReserveCost', u'ReserveKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key that uniquely identifies a particular ReserveCost record'), -(u'ReserveCost', u'ReserveLocal', u'N', 0, 2147483647, None, None, None, None, u'Disk space to reserve if linked component is installed locally.'), -(u'ReserveCost', u'ReserveSource', u'N', 0, 2147483647, None, None, None, None, u'Disk space to reserve if linked component is installed to run from the source location.'), -(u'SelfReg', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Foreign key into the File table denoting the module that needs to be registered.'), -(u'SelfReg', u'Cost', u'Y', 0, 32767, None, None, None, None, u'The cost of registering the module.'), -(u'ServiceControl', u'Name', u'N', None, None, None, None, u'Formatted', None, u'Name of a service. /, \\, comma and space are invalid'), -(u'ServiceControl', u'Event', u'N', 0, 187, None, None, None, None, u'Bit field: Install: 0x1 = Start, 0x2 = Stop, 0x8 = Delete, Uninstall: 0x10 = Start, 0x20 = Stop, 0x80 = Delete'), -(u'ServiceControl', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table that controls the startup of the service'), -(u'ServiceControl', u'ServiceControl', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), -(u'ServiceControl', u'Arguments', u'Y', None, None, None, None, u'Formatted', None, u'Arguments for the service. Separate by [~].'), -(u'ServiceControl', u'Wait', u'Y', 0, 1, None, None, None, None, u'Boolean for whether to wait for the service to fully start'), -(u'ServiceInstall', u'Name', u'N', None, None, None, None, u'Formatted', None, u'Internal Name of the Service'), -(u'ServiceInstall', u'Description', u'Y', None, None, None, None, u'Text', None, u'Description of service.'), -(u'ServiceInstall', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table that controls the startup of the service'), -(u'ServiceInstall', u'Arguments', u'Y', None, None, None, None, u'Formatted', None, u'Arguments to include in every start of the service, passed to WinMain'), -(u'ServiceInstall', u'ServiceInstall', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), -(u'ServiceInstall', u'Dependencies', u'Y', None, None, None, None, u'Formatted', None, u'Other services this depends on to start. Separate by [~], and end with [~][~]'), -(u'ServiceInstall', u'DisplayName', u'Y', None, None, None, None, u'Formatted', None, u'External Name of the Service'), -(u'ServiceInstall', u'ErrorControl', u'N', -2147483647, 2147483647, None, None, None, None, u'Severity of error if service fails to start'), -(u'ServiceInstall', u'LoadOrderGroup', u'Y', None, None, None, None, u'Formatted', None, u'LoadOrderGroup'), -(u'ServiceInstall', u'Password', u'Y', None, None, None, None, u'Formatted', None, u'password to run service with. (with StartName)'), -(u'ServiceInstall', u'ServiceType', u'N', -2147483647, 2147483647, None, None, None, None, u'Type of the service'), -(u'ServiceInstall', u'StartName', u'Y', None, None, None, None, u'Formatted', None, u'User or object name to run service as'), -(u'ServiceInstall', u'StartType', u'N', 0, 4, None, None, None, None, u'Type of the service'), -(u'Shortcut', u'Name', u'N', None, None, None, None, u'Filename', None, u'The name of the shortcut to be created.'), -(u'Shortcut', u'Description', u'Y', None, None, None, None, u'Text', None, u'The description for the shortcut.'), -(u'Shortcut', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table denoting the component whose selection gates the shortcut creation/deletion.'), -(u'Shortcut', u'Icon_', u'Y', None, None, u'Icon', 1, u'Identifier', None, u'Foreign key into the File table denoting the external icon file for the shortcut.'), -(u'Shortcut', u'IconIndex', u'Y', -32767, 32767, None, None, None, None, u'The icon index for the shortcut.'), -(u'Shortcut', u'Directory_', u'N', None, None, u'Directory', 1, u'Identifier', None, u'Foreign key into the Directory table denoting the directory where the shortcut file is created.'), -(u'Shortcut', u'Target', u'N', None, None, None, None, u'Shortcut', None, u'The shortcut target. This is usually a property that is expanded to a file or a folder that the shortcut points to.'), -(u'Shortcut', u'Arguments', u'Y', None, None, None, None, u'Formatted', None, u'The command-line arguments for the shortcut.'), -(u'Shortcut', u'Shortcut', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), -(u'Shortcut', u'Hotkey', u'Y', 0, 32767, None, None, None, None, u'The hotkey for the shortcut. It has the virtual-key code for the key in the low-order byte, and the modifier flags in the high-order byte. '), -(u'Shortcut', u'ShowCmd', u'Y', None, None, None, None, None, u'1;3;7', u'The show command for the application window.The following values may be used.'), -(u'Shortcut', u'WkDir', u'Y', None, None, None, None, u'Identifier', None, u'Name of property defining location of working directory.'), -(u'Signature', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The name of the file. This may contain a "short name|long name" pair.'), -(u'Signature', u'Signature', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature represents a unique file signature.'), -(u'Signature', u'Languages', u'Y', None, None, None, None, u'Language', None, u'The languages supported by the file.'), -(u'Signature', u'MaxDate', u'Y', 0, 2147483647, None, None, None, None, u'The maximum creation date of the file.'), -(u'Signature', u'MaxSize', u'Y', 0, 2147483647, None, None, None, None, u'The maximum size of the file. '), -(u'Signature', u'MaxVersion', u'Y', None, None, None, None, u'Text', None, u'The maximum version of the file.'), -(u'Signature', u'MinDate', u'Y', 0, 2147483647, None, None, None, None, u'The minimum creation date of the file.'), -(u'Signature', u'MinSize', u'Y', 0, 2147483647, None, None, None, None, u'The minimum size of the file.'), -(u'Signature', u'MinVersion', u'Y', None, None, None, None, u'Text', None, u'The minimum version of the file.'), -(u'TypeLib', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the type library to be operational.'), -(u'TypeLib', u'Description', u'Y', None, None, None, None, u'Text', None, None), -(u'TypeLib', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.'), -(u'TypeLib', u'Directory_', u'Y', None, None, u'Directory', 1, u'Identifier', None, u'Optional. The foreign key into the Directory table denoting the path to the help file for the type library.'), -(u'TypeLib', u'Language', u'N', 0, 32767, None, None, None, None, u'The language of the library.'), -(u'TypeLib', u'Version', u'Y', 0, 16777215, None, None, None, None, u'The version of the library. The minor version is in the lower 8 bits of the integer. The major version is in the next 16 bits. '), -(u'TypeLib', u'Cost', u'Y', 0, 2147483647, None, None, None, None, u'The cost associated with the registration of the typelib. This column is currently optional.'), -(u'TypeLib', u'LibID', u'N', None, None, None, None, u'Guid', None, u'The GUID that represents the library.'), -(u'Upgrade', u'Attributes', u'N', 0, 2147483647, None, None, None, None, u'The attributes of this product set.'), -(u'Upgrade', u'Remove', u'Y', None, None, None, None, u'Formatted', None, u'The list of features to remove when uninstalling a product from this set. The default is "ALL".'), -(u'Upgrade', u'Language', u'Y', None, None, None, None, u'Language', None, u'A comma-separated list of languages for either products in this set or products not in this set.'), -(u'Upgrade', u'ActionProperty', u'N', None, None, None, None, u'UpperCase', None, u'The property to set when a product in this set is found.'), -(u'Upgrade', u'UpgradeCode', u'N', None, None, None, None, u'Guid', None, u'The UpgradeCode GUID belonging to the products in this set.'), -(u'Upgrade', u'VersionMax', u'Y', None, None, None, None, u'Text', None, u'The maximum ProductVersion of the products in this set. The set may or may not include products with this particular version.'), -(u'Upgrade', u'VersionMin', u'Y', None, None, None, None, u'Text', None, u'The minimum ProductVersion of the products in this set. The set may or may not include products with this particular version.'), -(u'Verb', u'Sequence', u'Y', 0, 32767, None, None, None, None, u'Order within the verbs for a particular extension. Also used simply to specify the default verb.'), -(u'Verb', u'Argument', u'Y', None, None, None, None, u'Formatted', None, u'Optional value for the command arguments.'), -(u'Verb', u'Extension_', u'N', None, None, u'Extension', 1, u'Text', None, u'The extension associated with the table row.'), -(u'Verb', u'Verb', u'N', None, None, None, None, u'Text', None, u'The verb for the command.'), -(u'Verb', u'Command', u'Y', None, None, None, None, u'Formatted', None, u'The command text.'), -] - -Error = [ -(0, u'{{Fatal error: }}'), -(1, u'{{Error [1]. }}'), -(2, u'Warning [1]. '), -(3, None), -(4, u'Info [1]. '), -(5, u'The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is [1]. {{The arguments are: [2], [3], [4]}}'), -(6, None), -(7, u'{{Disk full: }}'), -(8, u'Action [Time]: [1]. [2]'), -(9, u'[ProductName]'), -(10, u'{[2]}{, [3]}{, [4]}'), -(11, u'Message type: [1], Argument: [2]'), -(12, u'=== Logging started: [Date] [Time] ==='), -(13, u'=== Logging stopped: [Date] [Time] ==='), -(14, u'Action start [Time]: [1].'), -(15, u'Action ended [Time]: [1]. Return value [2].'), -(16, u'Time remaining: {[1] minutes }{[2] seconds}'), -(17, u'Out of memory. Shut down other applications before retrying.'), -(18, u'Installer is no longer responding.'), -(19, u'Installer stopped prematurely.'), -(20, u'Please wait while Windows configures [ProductName]'), -(21, u'Gathering required information...'), -(22, u'Removing older versions of this application...'), -(23, u'Preparing to remove older versions of this application...'), -(32, u'{[ProductName] }Setup completed successfully.'), -(33, u'{[ProductName] }Setup failed.'), -(1101, u'Error reading from file: [2]. {{ System error [3].}} Verify that the file exists and that you can access it.'), -(1301, u"Cannot create the file '[2]'. A directory with this name already exists. Cancel the install and try installing to a different location."), -(1302, u'Please insert the disk: [2]'), -(1303, u'The installer has insufficient privileges to access this directory: [2]. The installation cannot continue. Log on as administrator or contact your system administrator.'), -(1304, u'Error writing to file: [2]. Verify that you have access to that directory.'), -(1305, u'Error reading from file [2]. {{ System error [3].}} Verify that the file exists and that you can access it.'), -(1306, u"Another application has exclusive access to the file '[2]'. Please shut down all other applications, then click Retry."), -(1307, u'There is not enough disk space to install this file: [2]. Free some disk space and click Retry, or click Cancel to exit.'), -(1308, u'Source file not found: [2]. Verify that the file exists and that you can access it.'), -(1309, u'Error reading from file: [3]. {{ System error [2].}} Verify that the file exists and that you can access it.'), -(1310, u'Error writing to file: [3]. {{ System error [2].}} Verify that you have access to that directory.'), -(1311, u'Source file not found{{(cabinet)}}: [2]. Verify that the file exists and that you can access it.'), -(1312, u"Cannot create the directory '[2]'. A file with this name already exists. Please rename or remove the file and click retry, or click Cancel to exit."), -(1313, u'The volume [2] is currently unavailable. Please select another.'), -(1314, u"The specified path '[2]' is unavailable."), -(1315, u'Unable to write to the specified folder: [2].'), -(1316, u'A network error occurred while attempting to read from the file: [2]'), -(1317, u'An error occurred while attempting to create the directory: [2]'), -(1318, u'A network error occurred while attempting to create the directory: [2]'), -(1319, u'A network error occurred while attempting to open the source file cabinet: [2]'), -(1320, u'The specified path is too long: [2]'), -(1321, u'The Installer has insufficient privileges to modify this file: [2].'), -(1322, u"A portion of the folder path '[2]' is invalid. It is either empty or exceeds the length allowed by the system."), -(1323, u"The folder path '[2]' contains words that are not valid in folder paths."), -(1324, u"The folder path '[2]' contains an invalid character."), -(1325, u"'[2]' is not a valid short file name."), -(1326, u'Error getting file security: [3] GetLastError: [2]'), -(1327, u'Invalid Drive: [2]'), -(1328, u'Error applying patch to file [2]. It has probably been updated by other means, and can no longer be modified by this patch. For more information contact your patch vendor. {{System Error: [3]}}'), -(1329, u'A file that is required cannot be installed because the cabinet file [2] is not digitally signed. This may indicate that the cabinet file is corrupt.'), -(1330, u'A file that is required cannot be installed because the cabinet file [2] has an invalid digital signature. This may indicate that the cabinet file is corrupt.{{ Error [3] was returned by WinVerifyTrust.}}'), -(1331, u'Failed to correctly copy [2] file: CRC error.'), -(1332, u'Failed to correctly move [2] file: CRC error.'), -(1333, u'Failed to correctly patch [2] file: CRC error.'), -(1334, u"The file '[2]' cannot be installed because the file cannot be found in cabinet file '[3]'. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package."), -(1335, u"The cabinet file '[2]' required for this installation is corrupt and cannot be used. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package."), -(1336, u'There was an error creating a temporary file that is needed to complete this installation.{{ Folder: [3]. System error code: [2]}}'), -(1401, u'Could not create key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. '), -(1402, u'Could not open key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. '), -(1403, u'Could not delete value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. '), -(1404, u'Could not delete key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. '), -(1405, u'Could not read value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. '), -(1406, u'Could not write value [2] to key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel.'), -(1407, u'Could not get value names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.'), -(1408, u'Could not get sub key names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.'), -(1409, u'Could not read security information for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.'), -(1410, u'Could not increase the available registry space. [2] KB of free registry space is required for the installation of this application.'), -(1500, u'Another installation is in progress. You must complete that installation before continuing this one.'), -(1501, u'Error accessing secured data. Please make sure the Windows Installer is configured properly and try the install again.'), -(1502, u"User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product. Your current install will now continue."), -(1503, u"User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product."), -(1601, u"Out of disk space -- Volume: '[2]'; required space: [3] KB; available space: [4] KB. Free some disk space and retry."), -(1602, u'Are you sure you want to cancel?'), -(1603, u"The file [2][3] is being held in use{ by the following process: Name: [4], Id: [5], Window Title: '[6]'}. Close that application and retry."), -(1604, u"The product '[2]' is already installed, preventing the installation of this product. The two products are incompatible."), -(1605, u"There is not enough disk space on the volume '[2]' to continue the install with recovery enabled. [3] KB are required, but only [4] KB are available. Click Ignore to continue the install without saving recovery information, click Retry to check for available space again, or click Cancel to quit the installation."), -(1606, u'Could not access network location [2].'), -(1607, u'The following applications should be closed before continuing the install:'), -(1608, u'Could not find any previously installed compliant products on the machine for installing this product.'), -(1609, u"An error occurred while applying security settings. [2] is not a valid user or group. This could be a problem with the package, or a problem connecting to a domain controller on the network. Check your network connection and click Retry, or Cancel to end the install. {{Unable to locate the user's SID, system error [3]}}"), -(1701, u'The key [2] is not valid. Verify that you entered the correct key.'), -(1702, u'The installer must restart your system before configuration of [2] can continue. Click Yes to restart now or No if you plan to manually restart later.'), -(1703, u'You must restart your system for the configuration changes made to [2] to take effect. Click Yes to restart now or No if you plan to manually restart later.'), -(1704, u'An installation for [2] is currently suspended. You must undo the changes made by that installation to continue. Do you want to undo those changes?'), -(1705, u'A previous installation for this product is in progress. You must undo the changes made by that installation to continue. Do you want to undo those changes?'), -(1706, u"An installation package for the product [2] cannot be found. Try the installation again using a valid copy of the installation package '[3]'."), -(1707, u'Installation completed successfully.'), -(1708, u'Installation failed.'), -(1709, u'Product: [2] -- [3]'), -(1710, u'You may either restore your computer to its previous state or continue the install later. Would you like to restore?'), -(1711, u'An error occurred while writing installation information to disk. Check to make sure enough disk space is available, and click Retry, or Cancel to end the install.'), -(1712, u'One or more of the files required to restore your computer to its previous state could not be found. Restoration will not be possible.'), -(1713, u'[2] cannot install one of its required products. Contact your technical support group. {{System Error: [3].}}'), -(1714, u'The older version of [2] cannot be removed. Contact your technical support group. {{System Error [3].}}'), -(1715, u'Installed [2]'), -(1716, u'Configured [2]'), -(1717, u'Removed [2]'), -(1718, u'File [2] was rejected by digital signature policy.'), -(1719, u'The Windows Installer Service could not be accessed. This can occur if you are running Windows in safe mode, or if the Windows Installer is not correctly installed. Contact your support personnel for assistance.'), -(1720, u'There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor. {{Custom action [2] script error [3], [4]: [5] Line [6], Column [7], [8] }}'), -(1721, u'There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action: [2], location: [3], command: [4] }}'), -(1722, u'There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. {{Action [2], location: [3], command: [4] }}'), -(1723, u'There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action [2], entry: [3], library: [4] }}'), -(1724, u'Removal completed successfully.'), -(1725, u'Removal failed.'), -(1726, u'Advertisement completed successfully.'), -(1727, u'Advertisement failed.'), -(1728, u'Configuration completed successfully.'), -(1729, u'Configuration failed.'), -(1730, u'You must be an Administrator to remove this application. To remove this application, you can log on as an Administrator, or contact your technical support group for assistance.'), -(1801, u'The path [2] is not valid. Please specify a valid path.'), -(1802, u'Out of memory. Shut down other applications before retrying.'), -(1803, u'There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to go back to the previously selected volume.'), -(1804, u'There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to return to the browse dialog and select a different volume.'), -(1805, u'The folder [2] does not exist. Please enter a path to an existing folder.'), -(1806, u'You have insufficient privileges to read this folder.'), -(1807, u'A valid destination folder for the install could not be determined.'), -(1901, u'Error attempting to read from the source install database: [2].'), -(1902, u'Scheduling reboot operation: Renaming file [2] to [3]. Must reboot to complete operation.'), -(1903, u'Scheduling reboot operation: Deleting file [2]. Must reboot to complete operation.'), -(1904, u'Module [2] failed to register. HRESULT [3]. Contact your support personnel.'), -(1905, u'Module [2] failed to unregister. HRESULT [3]. Contact your support personnel.'), -(1906, u'Failed to cache package [2]. Error: [3]. Contact your support personnel.'), -(1907, u'Could not register font [2]. Verify that you have sufficient permissions to install fonts, and that the system supports this font.'), -(1908, u'Could not unregister font [2]. Verify that you that you have sufficient permissions to remove fonts.'), -(1909, u'Could not create Shortcut [2]. Verify that the destination folder exists and that you can access it.'), -(1910, u'Could not remove Shortcut [2]. Verify that the shortcut file exists and that you can access it.'), -(1911, u'Could not register type library for file [2]. Contact your support personnel.'), -(1912, u'Could not unregister type library for file [2]. Contact your support personnel.'), -(1913, u'Could not update the ini file [2][3]. Verify that the file exists and that you can access it.'), -(1914, u'Could not schedule file [2] to replace file [3] on reboot. Verify that you have write permissions to file [3].'), -(1915, u'Error removing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.'), -(1916, u'Error installing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.'), -(1917, u'Error removing ODBC driver: [4], ODBC error [2]: [3]. Verify that you have sufficient privileges to remove ODBC drivers.'), -(1918, u'Error installing ODBC driver: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.'), -(1919, u'Error configuring ODBC data source: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.'), -(1920, u"Service '[2]' ([3]) failed to start. Verify that you have sufficient privileges to start system services."), -(1921, u"Service '[2]' ([3]) could not be stopped. Verify that you have sufficient privileges to stop system services."), -(1922, u"Service '[2]' ([3]) could not be deleted. Verify that you have sufficient privileges to remove system services."), -(1923, u"Service '[2]' ([3]) could not be installed. Verify that you have sufficient privileges to install system services."), -(1924, u"Could not update environment variable '[2]'. Verify that you have sufficient privileges to modify environment variables."), -(1925, u'You do not have sufficient privileges to complete this installation for all users of the machine. Log on as administrator and then retry this installation.'), -(1926, u"Could not set file security for file '[3]'. Error: [2]. Verify that you have sufficient privileges to modify the security permissions for this file."), -(1927, u'Component Services (COM+ 1.0) are not installed on this computer. This installation requires Component Services in order to complete successfully. Component Services are available on Windows 2000.'), -(1928, u'Error registering COM+ Application. Contact your support personnel for more information.'), -(1929, u'Error unregistering COM+ Application. Contact your support personnel for more information.'), -(1930, u"The description for service '[2]' ([3]) could not be changed."), -(1931, u'The Windows Installer service cannot update the system file [2] because the file is protected by Windows. You may need to update your operating system for this program to work correctly. {{Package version: [3], OS Protected version: [4]}}'), -(1932, u'The Windows Installer service cannot update the protected Windows file [2]. {{Package version: [3], OS Protected version: [4], SFP Error: [5]}}'), -(1933, u'The Windows Installer service cannot update one or more protected Windows files. {{SFP Error: [2]. List of protected files:\\r\\n[3]}}'), -(1934, u'User installations are disabled via policy on the machine.'), -(1935, u'An error occurred during the installation of assembly component [2]. HRESULT: [3]. {{assembly interface: [4], function: [5], assembly name: [6]}}'), -] - -tables=['AdminExecuteSequence', 'AdminUISequence', 'AdvtExecuteSequence', 'BBControl', 'Billboard', 'Binary', 'CheckBox', 'Property', 'ComboBox', 'Control', 'ListBox', 'ActionText', 'ControlCondition', 'ControlEvent', 'Dialog', 'EventMapping', 'InstallExecuteSequence', 'InstallUISequence', 'ListView', 'RadioButton', 'TextStyle', 'UIText', '_Validation', 'Error'] diff --git a/Tools/msi/wix.props b/Tools/msi/wix.props new file mode 100644 --- /dev/null +++ b/Tools/msi/wix.props @@ -0,0 +1,12 @@ + + + + + + $(MSBuildThisFileDirectory)\Wix\ + $(ExternalsDir)\Wix\ + $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Installer XML\3.9 at InstallRoot) + $(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows Installer XML\3.9 at InstallRoot) + $(WixInstallPath)\Wix.targets + + \ No newline at end of file -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 08:01:45 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 06 Feb 2015 07:01:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323881=3A_Only_use_entry-values_with_gdb_7=2E4_i?= =?utf-8?q?n_tests=2E?= Message-ID: <20150206070143.96090.9651@psf.io> https://hg.python.org/cpython/rev/981e108039f1 changeset: 94533:981e108039f1 parent: 94531:e7dbef447157 parent: 94532:30e6c8caa5b9 user: Serhiy Storchaka date: Fri Feb 06 08:35:54 2015 +0200 summary: Issue #23881: Only use entry-values with gdb 7.4 in tests. Fixes a regression in issue #22765. Patch by Vinson Lee. files: Lib/test/test_gdb.py | 18 ++++++++++-------- 1 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -124,14 +124,6 @@ commands = ['set breakpoint pending yes', 'break %s' % breakpoint, - # GDB as of 7.4 (?) onwards can distinguish between the - # value of a variable at entry vs current value: - # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html - # which leads to the selftests failing with errors like this: - # AssertionError: 'v at entry=()' != '()' - # Disable this: - 'set print entry-values no', - # The tests assume that the first frame of printed # backtrace will not contain program counter, # that is however not guaranteed by gdb @@ -143,6 +135,16 @@ 'set print address off', 'run'] + + # GDB as of 7.4 onwards can distinguish between the + # value of a variable at entry vs current value: + # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html + # which leads to the selftests failing with errors like this: + # AssertionError: 'v at entry=()' != '()' + # Disable this: + if (gdb_major_version, gdb_minor_version) >= (7, 4): + commands += ['set print entry-values no'] + if cmds_after_breakpoint: commands += cmds_after_breakpoint else: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 08:01:45 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 06 Feb 2015 07:01:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzMzky?= =?utf-8?q?=3A_Added_tests_for_marshal_C_API_that_works_with_FILE*=2E?= Message-ID: <20150206070143.34388.97776@psf.io> https://hg.python.org/cpython/rev/e55f955659bc changeset: 94535:e55f955659bc branch: 2.7 user: Serhiy Storchaka date: Fri Feb 06 08:56:33 2015 +0200 summary: Issue #23392: Added tests for marshal C API that works with FILE*. files: Lib/test/test_marshal.py | 65 ++++++++++ Misc/NEWS | 2 + Modules/_testcapimodule.c | 166 ++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -6,6 +6,11 @@ import unittest import os +try: + import _testcapi +except ImportError: + _testcapi = None + class IntTestCase(unittest.TestCase): def test_ints(self): # Test the full range of Python ints. @@ -316,6 +321,65 @@ self.check_unmarshallable(bytearray(size)) + at test_support.cpython_only + at unittest.skipUnless(_testcapi, 'requires _testcapi') +class CAPI_TestCase(unittest.TestCase): + + def test_write_long_to_file(self): + for v in range(marshal.version + 1): + _testcapi.pymarshal_write_long_to_file(0x12345678, test_support.TESTFN, v) + with open(test_support.TESTFN, 'rb') as f: + data = f.read() + test_support.unlink(test_support.TESTFN) + self.assertEqual(data, b'\x78\x56\x34\x12') + + def test_write_object_to_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000) + for v in range(marshal.version + 1): + _testcapi.pymarshal_write_object_to_file(obj, test_support.TESTFN, v) + with open(test_support.TESTFN, 'rb') as f: + data = f.read() + test_support.unlink(test_support.TESTFN) + self.assertEqual(marshal.loads(data), obj) + + def test_read_short_from_file(self): + with open(test_support.TESTFN, 'wb') as f: + f.write(b'\x34\x12xxxx') + r, p = _testcapi.pymarshal_read_short_from_file(test_support.TESTFN) + test_support.unlink(test_support.TESTFN) + self.assertEqual(r, 0x1234) + self.assertEqual(p, 2) + + def test_read_long_from_file(self): + with open(test_support.TESTFN, 'wb') as f: + f.write(b'\x78\x56\x34\x12xxxx') + r, p = _testcapi.pymarshal_read_long_from_file(test_support.TESTFN) + test_support.unlink(test_support.TESTFN) + self.assertEqual(r, 0x12345678) + self.assertEqual(p, 4) + + def test_read_last_object_from_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j) + for v in range(marshal.version + 1): + data = marshal.dumps(obj, v) + with open(test_support.TESTFN, 'wb') as f: + f.write(data + b'xxxx') + r, p = _testcapi.pymarshal_read_last_object_from_file(test_support.TESTFN) + test_support.unlink(test_support.TESTFN) + self.assertEqual(r, obj) + + def test_read_object_from_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j) + for v in range(marshal.version + 1): + data = marshal.dumps(obj, v) + with open(test_support.TESTFN, 'wb') as f: + f.write(data + b'xxxx') + r, p = _testcapi.pymarshal_read_object_from_file(test_support.TESTFN) + test_support.unlink(test_support.TESTFN) + self.assertEqual(r, obj) + self.assertEqual(p, len(data)) + + def test_main(): test_support.run_unittest(IntTestCase, FloatTestCase, @@ -325,6 +389,7 @@ ExceptionTestCase, BugsTestCase, LargeValuesTestCase, + CAPI_TestCase, ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,8 @@ Tests ----- +- Issue #23392: Added tests for marshal C API that works with FILE*. + - Issue #18982: Add tests for CLI of the calendar module. - Issue #19949: The test_xpickle test now tests compatibility with installed diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -9,6 +9,7 @@ #include #include "structmember.h" #include "datetime.h" +#include "marshal.h" #ifdef WITH_THREAD #include "pythread.h" @@ -1875,6 +1876,159 @@ } #endif /* WITH_THREAD */ +/* marshal */ + +static PyObject* +pymarshal_write_long_to_file(PyObject* self, PyObject *args) +{ + long value; + char *filename; + int version; + FILE *fp; + + if (!PyArg_ParseTuple(args, "lsi:pymarshal_write_long_to_file", + &value, &filename, &version)) + return NULL; + + fp = fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + PyMarshal_WriteLongToFile(value, fp, version); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +static PyObject* +pymarshal_write_object_to_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + char *filename; + int version; + FILE *fp; + + if (!PyArg_ParseTuple(args, "Osi:pymarshal_write_object_to_file", + &obj, &filename, &version)) + return NULL; + + fp = fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + PyMarshal_WriteObjectToFile(obj, fp, version); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +static PyObject* +pymarshal_read_short_from_file(PyObject* self, PyObject *args) +{ + int value; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_short_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + value = PyMarshal_ReadShortFromFile(fp); + pos = ftell(fp); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + return Py_BuildValue("il", value, pos); +} + +static PyObject* +pymarshal_read_long_from_file(PyObject* self, PyObject *args) +{ + long value, pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_long_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + value = PyMarshal_ReadLongFromFile(fp); + pos = ftell(fp); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + return Py_BuildValue("ll", value, pos); +} + +static PyObject* +pymarshal_read_last_object_from_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_last_object_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + obj = PyMarshal_ReadLastObjectFromFile(fp); + pos = ftell(fp); + + fclose(fp); + return Py_BuildValue("Nl", obj, pos); +} + +static PyObject* +pymarshal_read_object_from_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_object_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + obj = PyMarshal_ReadObjectFromFile(fp); + pos = ftell(fp); + + fclose(fp); + return Py_BuildValue("Nl", obj, pos); +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, @@ -1940,6 +2094,18 @@ {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O, PyDoc_STR("set_error_class(error_class) -> None")}, #endif + {"pymarshal_write_long_to_file", + pymarshal_write_long_to_file, METH_VARARGS}, + {"pymarshal_write_object_to_file", + pymarshal_write_object_to_file, METH_VARARGS}, + {"pymarshal_read_short_from_file", + pymarshal_read_short_from_file, METH_VARARGS}, + {"pymarshal_read_long_from_file", + pymarshal_read_long_from_file, METH_VARARGS}, + {"pymarshal_read_last_object_from_file", + pymarshal_read_last_object_from_file, METH_VARARGS}, + {"pymarshal_read_object_from_file", + pymarshal_read_object_from_file, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 08:01:45 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 06 Feb 2015 07:01:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzky?= =?utf-8?q?=3A_Added_tests_for_marshal_C_API_that_works_with_FILE*=2E?= Message-ID: <20150206070144.106307.37418@psf.io> https://hg.python.org/cpython/rev/05153851d1d6 changeset: 94536:05153851d1d6 branch: 3.4 parent: 94532:30e6c8caa5b9 user: Serhiy Storchaka date: Fri Feb 06 08:58:56 2015 +0200 summary: Issue #23392: Added tests for marshal C API that works with FILE*. files: Lib/test/test_marshal.py | 99 +++++++++++++- Misc/NEWS | 2 + Modules/_testcapimodule.c | 166 ++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -7,6 +7,11 @@ import os import types +try: + import _testcapi +except ImportError: + _testcapi = None + class HelperMixin: def helper(self, sample, *extra): new = marshal.loads(marshal.dumps(sample, *extra)) @@ -434,18 +439,88 @@ s2 = sys.intern(s) self.assertNotEqual(id(s2), id(s)) + at support.cpython_only + at unittest.skipUnless(_testcapi, 'requires _testcapi') +class CAPI_TestCase(unittest.TestCase, HelperMixin): -def test_main(): - support.run_unittest(IntTestCase, - FloatTestCase, - StringTestCase, - CodeTestCase, - ContainerTestCase, - ExceptionTestCase, - BufferTestCase, - BugsTestCase, - LargeValuesTestCase, - ) + def test_write_long_to_file(self): + for v in range(marshal.version + 1): + _testcapi.pymarshal_write_long_to_file(0x12345678, support.TESTFN, v) + with open(support.TESTFN, 'rb') as f: + data = f.read() + support.unlink(support.TESTFN) + self.assertEqual(data, b'\x78\x56\x34\x12') + + def test_write_object_to_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000) + for v in range(marshal.version + 1): + _testcapi.pymarshal_write_object_to_file(obj, support.TESTFN, v) + with open(support.TESTFN, 'rb') as f: + data = f.read() + support.unlink(support.TESTFN) + self.assertEqual(marshal.loads(data), obj) + + def test_read_short_from_file(self): + with open(support.TESTFN, 'wb') as f: + f.write(b'\x34\x12xxxx') + r, p = _testcapi.pymarshal_read_short_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, 0x1234) + self.assertEqual(p, 2) + + with open(support.TESTFN, 'wb') as f: + f.write(b'\x12') + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_short_from_file(support.TESTFN) + support.unlink(support.TESTFN) + + def test_read_long_from_file(self): + with open(support.TESTFN, 'wb') as f: + f.write(b'\x78\x56\x34\x12xxxx') + r, p = _testcapi.pymarshal_read_long_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, 0x12345678) + self.assertEqual(p, 4) + + with open(support.TESTFN, 'wb') as f: + f.write(b'\x56\x34\x12') + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_long_from_file(support.TESTFN) + support.unlink(support.TESTFN) + + def test_read_last_object_from_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j) + for v in range(marshal.version + 1): + data = marshal.dumps(obj, v) + with open(support.TESTFN, 'wb') as f: + f.write(data + b'xxxx') + r, p = _testcapi.pymarshal_read_last_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, obj) + + with open(support.TESTFN, 'wb') as f: + f.write(data[:1]) + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_last_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + + def test_read_object_from_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j) + for v in range(marshal.version + 1): + data = marshal.dumps(obj, v) + with open(support.TESTFN, 'wb') as f: + f.write(data + b'xxxx') + r, p = _testcapi.pymarshal_read_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, obj) + self.assertEqual(p, len(data)) + + with open(support.TESTFN, 'wb') as f: + f.write(data[:1]) + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + if __name__ == "__main__": - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -326,6 +326,8 @@ Tests ----- +- Issue #23392: Added tests for marshal C API that works with FILE*. + - Issue #18982: Add tests for CLI of the calendar module. - Issue #19548: Added some additional checks to test_codecs to ensure that diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -11,6 +11,7 @@ #include #include "structmember.h" #include "datetime.h" +#include "marshal.h" #ifdef WITH_THREAD #include "pythread.h" @@ -3050,6 +3051,159 @@ } #endif /* WITH_THREAD */ +/* marshal */ + +static PyObject* +pymarshal_write_long_to_file(PyObject* self, PyObject *args) +{ + long value; + char *filename; + int version; + FILE *fp; + + if (!PyArg_ParseTuple(args, "lsi:pymarshal_write_long_to_file", + &value, &filename, &version)) + return NULL; + + fp = fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + PyMarshal_WriteLongToFile(value, fp, version); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +static PyObject* +pymarshal_write_object_to_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + char *filename; + int version; + FILE *fp; + + if (!PyArg_ParseTuple(args, "Osi:pymarshal_write_object_to_file", + &obj, &filename, &version)) + return NULL; + + fp = fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + PyMarshal_WriteObjectToFile(obj, fp, version); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +static PyObject* +pymarshal_read_short_from_file(PyObject* self, PyObject *args) +{ + int value; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_short_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + value = PyMarshal_ReadShortFromFile(fp); + pos = ftell(fp); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + return Py_BuildValue("il", value, pos); +} + +static PyObject* +pymarshal_read_long_from_file(PyObject* self, PyObject *args) +{ + long value, pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_long_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + value = PyMarshal_ReadLongFromFile(fp); + pos = ftell(fp); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + return Py_BuildValue("ll", value, pos); +} + +static PyObject* +pymarshal_read_last_object_from_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_last_object_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + obj = PyMarshal_ReadLastObjectFromFile(fp); + pos = ftell(fp); + + fclose(fp); + return Py_BuildValue("Nl", obj, pos); +} + +static PyObject* +pymarshal_read_object_from_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_object_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + obj = PyMarshal_ReadObjectFromFile(fp); + pos = ftell(fp); + + fclose(fp); + return Py_BuildValue("Nl", obj, pos); +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, @@ -3190,6 +3344,18 @@ {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O, PyDoc_STR("set_error_class(error_class) -> None")}, #endif + {"pymarshal_write_long_to_file", + pymarshal_write_long_to_file, METH_VARARGS}, + {"pymarshal_write_object_to_file", + pymarshal_write_object_to_file, METH_VARARGS}, + {"pymarshal_read_short_from_file", + pymarshal_read_short_from_file, METH_VARARGS}, + {"pymarshal_read_long_from_file", + pymarshal_read_long_from_file, METH_VARARGS}, + {"pymarshal_read_last_object_from_file", + pymarshal_read_last_object_from_file, METH_VARARGS}, + {"pymarshal_read_object_from_file", + pymarshal_read_object_from_file, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 08:01:45 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 06 Feb 2015 07:01:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323392=3A_Added_tests_for_marshal_C_API_that_wor?= =?utf-8?q?ks_with_FILE*=2E?= Message-ID: <20150206070144.25867.90407@psf.io> https://hg.python.org/cpython/rev/7f22813496de changeset: 94537:7f22813496de parent: 94533:981e108039f1 parent: 94536:05153851d1d6 user: Serhiy Storchaka date: Fri Feb 06 09:00:44 2015 +0200 summary: Issue #23392: Added tests for marshal C API that works with FILE*. files: Lib/test/test_marshal.py | 99 +++++++++++++- Misc/NEWS | 2 + Modules/_testcapimodule.c | 166 ++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -7,6 +7,11 @@ import os import types +try: + import _testcapi +except ImportError: + _testcapi = None + class HelperMixin: def helper(self, sample, *extra): new = marshal.loads(marshal.dumps(sample, *extra)) @@ -434,18 +439,88 @@ s2 = sys.intern(s) self.assertNotEqual(id(s2), id(s)) + at support.cpython_only + at unittest.skipUnless(_testcapi, 'requires _testcapi') +class CAPI_TestCase(unittest.TestCase, HelperMixin): -def test_main(): - support.run_unittest(IntTestCase, - FloatTestCase, - StringTestCase, - CodeTestCase, - ContainerTestCase, - ExceptionTestCase, - BufferTestCase, - BugsTestCase, - LargeValuesTestCase, - ) + def test_write_long_to_file(self): + for v in range(marshal.version + 1): + _testcapi.pymarshal_write_long_to_file(0x12345678, support.TESTFN, v) + with open(support.TESTFN, 'rb') as f: + data = f.read() + support.unlink(support.TESTFN) + self.assertEqual(data, b'\x78\x56\x34\x12') + + def test_write_object_to_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000) + for v in range(marshal.version + 1): + _testcapi.pymarshal_write_object_to_file(obj, support.TESTFN, v) + with open(support.TESTFN, 'rb') as f: + data = f.read() + support.unlink(support.TESTFN) + self.assertEqual(marshal.loads(data), obj) + + def test_read_short_from_file(self): + with open(support.TESTFN, 'wb') as f: + f.write(b'\x34\x12xxxx') + r, p = _testcapi.pymarshal_read_short_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, 0x1234) + self.assertEqual(p, 2) + + with open(support.TESTFN, 'wb') as f: + f.write(b'\x12') + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_short_from_file(support.TESTFN) + support.unlink(support.TESTFN) + + def test_read_long_from_file(self): + with open(support.TESTFN, 'wb') as f: + f.write(b'\x78\x56\x34\x12xxxx') + r, p = _testcapi.pymarshal_read_long_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, 0x12345678) + self.assertEqual(p, 4) + + with open(support.TESTFN, 'wb') as f: + f.write(b'\x56\x34\x12') + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_long_from_file(support.TESTFN) + support.unlink(support.TESTFN) + + def test_read_last_object_from_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j) + for v in range(marshal.version + 1): + data = marshal.dumps(obj, v) + with open(support.TESTFN, 'wb') as f: + f.write(data + b'xxxx') + r, p = _testcapi.pymarshal_read_last_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, obj) + + with open(support.TESTFN, 'wb') as f: + f.write(data[:1]) + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_last_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + + def test_read_object_from_file(self): + obj = ('\u20ac', b'abc', 123, 45.6, 7+8j) + for v in range(marshal.version + 1): + data = marshal.dumps(obj, v) + with open(support.TESTFN, 'wb') as f: + f.write(data + b'xxxx') + r, p = _testcapi.pymarshal_read_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + self.assertEqual(r, obj) + self.assertEqual(p, len(data)) + + with open(support.TESTFN, 'wb') as f: + f.write(data[:1]) + with self.assertRaises(EOFError): + _testcapi.pymarshal_read_object_from_file(support.TESTFN) + support.unlink(support.TESTFN) + if __name__ == "__main__": - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -613,6 +613,8 @@ - Issue #17442: InteractiveInterpreter now displays the full chained traceback in its showtraceback method, to match the built in interactive interpreter. +- Issue #23392: Added tests for marshal C API that works with FILE*. + - Issue #10510: distutils register and upload methods now use HTML standards compliant CRLF line endings. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -11,6 +11,7 @@ #include #include "structmember.h" #include "datetime.h" +#include "marshal.h" #include #ifdef WITH_THREAD @@ -3199,6 +3200,159 @@ Py_RETURN_NONE; } +/* marshal */ + +static PyObject* +pymarshal_write_long_to_file(PyObject* self, PyObject *args) +{ + long value; + char *filename; + int version; + FILE *fp; + + if (!PyArg_ParseTuple(args, "lsi:pymarshal_write_long_to_file", + &value, &filename, &version)) + return NULL; + + fp = fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + PyMarshal_WriteLongToFile(value, fp, version); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +static PyObject* +pymarshal_write_object_to_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + char *filename; + int version; + FILE *fp; + + if (!PyArg_ParseTuple(args, "Osi:pymarshal_write_object_to_file", + &obj, &filename, &version)) + return NULL; + + fp = fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + PyMarshal_WriteObjectToFile(obj, fp, version); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +static PyObject* +pymarshal_read_short_from_file(PyObject* self, PyObject *args) +{ + int value; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_short_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + value = PyMarshal_ReadShortFromFile(fp); + pos = ftell(fp); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + return Py_BuildValue("il", value, pos); +} + +static PyObject* +pymarshal_read_long_from_file(PyObject* self, PyObject *args) +{ + long value, pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_long_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + value = PyMarshal_ReadLongFromFile(fp); + pos = ftell(fp); + + fclose(fp); + if (PyErr_Occurred()) + return NULL; + return Py_BuildValue("ll", value, pos); +} + +static PyObject* +pymarshal_read_last_object_from_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_last_object_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + obj = PyMarshal_ReadLastObjectFromFile(fp); + pos = ftell(fp); + + fclose(fp); + return Py_BuildValue("Nl", obj, pos); +} + +static PyObject* +pymarshal_read_object_from_file(PyObject* self, PyObject *args) +{ + PyObject *obj; + long pos; + char *filename; + FILE *fp; + + if (!PyArg_ParseTuple(args, "s:pymarshal_read_object_from_file", &filename)) + return NULL; + + fp = fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + obj = PyMarshal_ReadObjectFromFile(fp); + pos = ftell(fp); + + fclose(fp); + return Py_BuildValue("Nl", obj, pos); +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, @@ -3346,6 +3500,18 @@ {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O, PyDoc_STR("set_error_class(error_class) -> None")}, #endif + {"pymarshal_write_long_to_file", + pymarshal_write_long_to_file, METH_VARARGS}, + {"pymarshal_write_object_to_file", + pymarshal_write_object_to_file, METH_VARARGS}, + {"pymarshal_read_short_from_file", + pymarshal_read_short_from_file, METH_VARARGS}, + {"pymarshal_read_long_from_file", + pymarshal_read_long_from_file, METH_VARARGS}, + {"pymarshal_read_last_object_from_file", + pymarshal_read_last_object_from_file, METH_VARARGS}, + {"pymarshal_read_object_from_file", + pymarshal_read_object_from_file, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 08:01:45 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 06 Feb 2015 07:01:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzODgx?= =?utf-8?q?=3A_Only_use_entry-values_with_gdb_7=2E4_in_tests=2E?= Message-ID: <20150206070143.106346.47984@psf.io> https://hg.python.org/cpython/rev/30e6c8caa5b9 changeset: 94532:30e6c8caa5b9 branch: 3.4 parent: 94529:b8078220a6b8 user: Serhiy Storchaka date: Fri Feb 06 08:35:20 2015 +0200 summary: Issue #23881: Only use entry-values with gdb 7.4 in tests. Fixes a regression in issue #22765. Patch by Vinson Lee. files: Lib/test/test_gdb.py | 18 ++++++++++-------- 1 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -124,14 +124,6 @@ commands = ['set breakpoint pending yes', 'break %s' % breakpoint, - # GDB as of 7.4 (?) onwards can distinguish between the - # value of a variable at entry vs current value: - # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html - # which leads to the selftests failing with errors like this: - # AssertionError: 'v at entry=()' != '()' - # Disable this: - 'set print entry-values no', - # The tests assume that the first frame of printed # backtrace will not contain program counter, # that is however not guaranteed by gdb @@ -143,6 +135,16 @@ 'set print address off', 'run'] + + # GDB as of 7.4 onwards can distinguish between the + # value of a variable at entry vs current value: + # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html + # which leads to the selftests failing with errors like this: + # AssertionError: 'v at entry=()' != '()' + # Disable this: + if (gdb_major_version, gdb_minor_version) >= (7, 4): + commands += ['set print entry-values no'] + if cmds_after_breakpoint: commands += cmds_after_breakpoint else: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 08:01:45 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 06 Feb 2015 07:01:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzODgx?= =?utf-8?q?=3A_Only_use_entry-values_with_gdb_7=2E4_in_tests=2E?= Message-ID: <20150206070143.39296.91039@psf.io> https://hg.python.org/cpython/rev/cee39701b280 changeset: 94534:cee39701b280 branch: 2.7 parent: 94528:b3df5bb1cd14 user: Serhiy Storchaka date: Fri Feb 06 08:36:14 2015 +0200 summary: Issue #23881: Only use entry-values with gdb 7.4 in tests. Fixes a regression in issue #22765. Patch by Vinson Lee. files: Lib/test/test_gdb.py | 18 ++++++++++-------- 1 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -119,14 +119,6 @@ commands = ['set breakpoint pending yes', 'break %s' % breakpoint, - # GDB as of 7.4 (?) onwards can distinguish between the - # value of a variable at entry vs current value: - # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html - # which leads to the selftests failing with errors like this: - # AssertionError: 'v at entry=()' != '()' - # Disable this: - 'set print entry-values no', - # The tests assume that the first frame of printed # backtrace will not contain program counter, # that is however not guaranteed by gdb @@ -138,6 +130,16 @@ 'set print address off', 'run'] + + # GDB as of 7.4 onwards can distinguish between the + # value of a variable at entry vs current value: + # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html + # which leads to the selftests failing with errors like this: + # AssertionError: 'v at entry=()' != '()' + # Disable this: + if (gdb_major_version, gdb_minor_version) >= (7, 4): + commands += ['set print entry-values no'] + if cmds_after_breakpoint: commands += cmds_after_breakpoint else: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 09:17:46 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 06 Feb 2015 08:17:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_typos_in_Doc/whatsnew/?= =?utf-8?b?My41LnJzdC4=?= Message-ID: <20150206081726.39282.70712@psf.io> https://hg.python.org/cpython/rev/5aa4870c4d1e changeset: 94538:5aa4870c4d1e user: Berker Peksag date: Fri Feb 06 10:17:49 2015 +0200 summary: Fix typos in Doc/whatsnew/3.5.rst. files: Doc/whatsnew/3.5.rst | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -141,7 +141,7 @@ * The :func:`code.InteractiveInterpreter.showtraceback` method now prints the full chained traceback, just like the interactive interpreter. - (Contributed by Claudiu.Popa in :issue:`17442`.) + (Contributed by Claudiu Popa in :issue:`17442`.) compileall ---------- @@ -192,7 +192,7 @@ ------ * :func:`~imghdr.what` now recognizes the `OpenEXR `_ - format. (Contributed by Martin vignali and Cladui Popa in :issue:`20295`.) + format. (Contributed by Martin Vignali and Claudiu Popa in :issue:`20295`.) importlib --------- @@ -472,10 +472,10 @@ **without** caching ``None`` in :data:`sys.path_importer_cache` which is different than the typical case (:issue:`22834`). -* HTTP status code and messages from `http.client` and `http.server` were - refactored into a common :class:`~http.HTTPStatus` enum. The values in - `http.client` and `http.server` remain available for backwards compatibility. - (Contributed by Demian Brecht in :issue:`21793`.) +* HTTP status code and messages from :mod:`http.client` and :mod:`http.server` + were refactored into a common :class:`~http.HTTPStatus` enum. The values in + :mod:`http.client` and :mod:`http.server` remain available for backwards + compatibility. (Contributed by Demian Brecht in :issue:`21793`.) * When an import loader defines :meth:`~importlib.machinery.Loader.exec_module` it is now expected to also define -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 09:22:43 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 06 Feb 2015 08:22:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320289=3A_cgi=2EFi?= =?utf-8?q?eldStorage=28=29_now_supports_the_context_management_protocol?= =?utf-8?q?=2E?= Message-ID: <20150206082114.39270.81922@psf.io> https://hg.python.org/cpython/rev/367f5e98ffbb changeset: 94539:367f5e98ffbb user: Berker Peksag date: Fri Feb 06 10:21:37 2015 +0200 summary: Issue #20289: cgi.FieldStorage() now supports the context management protocol. files: Doc/library/cgi.rst | 7 +++++++ Doc/whatsnew/3.5.rst | 6 ++++++ Lib/cgi.py | 6 ++++++ Lib/test/test_cgi.py | 19 +++++++++++++------ Misc/NEWS | 3 +++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Doc/library/cgi.rst b/Doc/library/cgi.rst --- a/Doc/library/cgi.rst +++ b/Doc/library/cgi.rst @@ -157,6 +157,9 @@ if not line: break linecount = linecount + 1 +:class:`FieldStorage` objects also support being used in a :keyword:`with` +statement, which will automatically close them when done. + If an error is encountered when obtaining the contents of an uploaded file (for example, when the user interrupts the form submission by clicking on a Back or Cancel button) the :attr:`~FieldStorage.done` attribute of the @@ -182,6 +185,10 @@ The :attr:`~FieldStorage.file` attribute is automatically closed upon the garbage collection of the creating :class:`FieldStorage` instance. +.. versionchanged:: 3.5 + Added support for the context management protocol to the + :class:`FieldStorage` class. + Higher Level Interface ---------------------- diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -136,6 +136,12 @@ Improved Modules ================ +cgi +--- + +* :class:`FieldStorage` now supports the context management protocol. + (Contributed by Berker Peksag in :issue:`20289`.) + code ---- diff --git a/Lib/cgi.py b/Lib/cgi.py --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -566,6 +566,12 @@ except AttributeError: pass + def __enter__(self): + return self + + def __exit__(self, *args): + self.file.close() + def __repr__(self): """Return a printable representation.""" return "FieldStorage(%r, %r, %r)" % ( diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -1,4 +1,4 @@ -from test.support import run_unittest, check_warnings +from test.support import check_warnings import cgi import os import sys @@ -307,6 +307,17 @@ got = getattr(files[x], k) self.assertEqual(got, exp) + def test_fieldstorage_as_context_manager(self): + fp = BytesIO(b'x' * 10) + env = {'REQUEST_METHOD': 'PUT'} + with cgi.FieldStorage(fp=fp, environ=env) as fs: + content = fs.file.read() + self.assertFalse(fs.file.closed) + self.assertTrue(fs.file.closed) + self.assertEqual(content, 'x' * 10) + with self.assertRaisesRegex(ValueError, 'I/O operation on closed file'): + fs.file.read() + _qs_result = { 'key1': 'value1', 'key2': ['value2x', 'value2y'], @@ -481,9 +492,5 @@ --AaB03x-- """ - -def test_main(): - run_unittest(CgiTests) - if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -235,6 +235,9 @@ Library ------- +- Issue #20289: cgi.FieldStorage() now supports the context management + protocol. + - Issue #13128: Print response headers for CONNECT requests when debuglevel > 0. Patch by Demian Brecht. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Fri Feb 6 09:27:39 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 06 Feb 2015 09:27:39 +0100 Subject: [Python-checkins] Daily reference leaks (494376ec13d9): sum=6 Message-ID: results for 494376ec13d9 on branch "default" -------------------------------------------- test_asyncio leaked [0, 3, 0] memory blocks, sum=3 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogyKTm86', '-x'] From python-checkins at python.org Fri Feb 6 17:51:54 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 06 Feb 2015 16:51:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Fix_definition_mismatch_for_type=5Fis=5Fsubtype=5Fbase?= =?utf-8?q?=5Fchain=2E?= Message-ID: <20150206165152.25841.89366@psf.io> https://hg.python.org/cpython/rev/3a8d67d208e0 changeset: 94541:3a8d67d208e0 parent: 94539:367f5e98ffbb parent: 94540:c5f1ec12634d user: Steve Dower date: Fri Feb 06 08:51:26 2015 -0800 summary: Fix definition mismatch for type_is_subtype_base_chain. files: Objects/typeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -565,7 +565,7 @@ static PyTypeObject *best_base(PyObject *); static int mro_internal(PyTypeObject *, PyObject **); -static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); +Py_LOCAL_INLINE(int) type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); static int add_subclass(PyTypeObject*, PyTypeObject*); static int add_all_subclasses(PyTypeObject *type, PyObject *bases); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 17:51:54 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 06 Feb 2015 16:51:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_definition?= =?utf-8?q?_mismatch_for_type=5Fis=5Fsubtype=5Fbase=5Fchain=2E?= Message-ID: <20150206165151.96098.58369@psf.io> https://hg.python.org/cpython/rev/c5f1ec12634d changeset: 94540:c5f1ec12634d branch: 3.4 parent: 94536:05153851d1d6 user: Steve Dower date: Fri Feb 06 08:50:23 2015 -0800 summary: Fix definition mismatch for type_is_subtype_base_chain. files: Objects/typeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -540,7 +540,7 @@ static PyTypeObject *best_base(PyObject *); static int mro_internal(PyTypeObject *, PyObject **); -static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); +Py_LOCAL_INLINE(int) type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); static int add_subclass(PyTypeObject*, PyTypeObject*); static int add_all_subclasses(PyTypeObject *type, PyObject *bases); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 18:01:47 2015 From: python-checkins at python.org (barry.warsaw) Date: Fri, 06 Feb 2015 17:01:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNCk6?= =?utf-8?q?_Issue_=2323399=3A_pyvenv_creates_relative_symlinks_where_possi?= =?utf-8?q?ble=2E?= Message-ID: <20150206170128.106379.46451@psf.io> https://hg.python.org/cpython/rev/7a82b1539401 changeset: 94545:7a82b1539401 branch: 3.4 parent: 94540:c5f1ec12634d parent: 94542:6b8d95c12eaf user: Barry Warsaw date: Fri Feb 06 12:00:04 2015 -0500 summary: Issue #23399: pyvenv creates relative symlinks where possible. files: Lib/venv/__init__.py | 14 ++++++++------ Misc/NEWS | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -141,10 +141,9 @@ # Issue 21197: create lib64 as a symlink to lib on 64-bit non-OS X POSIX if ((sys.maxsize > 2**32) and (os.name == 'posix') and (sys.platform != 'darwin')): - p = os.path.join(env_dir, 'lib') link_path = os.path.join(env_dir, 'lib64') if not os.path.exists(link_path): # Issue #21643 - os.symlink(p, link_path) + os.symlink('lib', link_path) context.bin_path = binpath = os.path.join(env_dir, binname) context.bin_name = binname context.env_exe = os.path.join(binpath, exename) @@ -178,7 +177,7 @@ result = f.startswith('python') and f.endswith('.exe') return result - def symlink_or_copy(self, src, dst): + def symlink_or_copy(self, src, dst, relative_symlinks_ok=False): """ Try symlinking a file, and if that fails, fall back to copying. """ @@ -186,7 +185,11 @@ if not force_copy: try: if not os.path.islink(dst): # can't link to itself! - os.symlink(src, dst) + if relative_symlinks_ok: + assert os.path.dirname(src) == os.path.dirname(dst) + os.symlink(os.path.basename(src), dst) + else: + os.symlink(src, dst) except Exception: # may need to use a more specific exception logger.warning('Unable to symlink %r to %r', src, dst) force_copy = True @@ -201,7 +204,6 @@ being processed. """ binpath = context.bin_path - exename = context.python_exe path = context.env_exe copier = self.symlink_or_copy copier(context.executable, path) @@ -214,7 +216,7 @@ if not os.path.exists(path): # Issue 18807: make copies if # symlinks are not wanted - copier(context.env_exe, path) + copier(context.env_exe, path, relative_symlinks_ok=True) if not os.path.islink(path): os.chmod(path, 0o755) else: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,8 @@ Library ------- +- Issue #23399: pyvenv creates relative symlinks where possible. + - Issue #23099: Closing io.BytesIO with exported buffer is rejected now to prevent corrupting exported buffer. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 18:01:47 2015 From: python-checkins at python.org (barry.warsaw) Date: Fri, 06 Feb 2015 17:01:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <20150206170128.34412.38810@psf.io> https://hg.python.org/cpython/rev/23be7b70aa46 changeset: 94546:23be7b70aa46 parent: 94544:1ef6db8558b2 parent: 94545:7a82b1539401 user: Barry Warsaw date: Fri Feb 06 12:00:57 2015 -0500 summary: Merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 18:01:47 2015 From: python-checkins at python.org (barry.warsaw) Date: Fri, 06 Feb 2015 17:01:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323399=3A_pyvenv_creates_relative_symlinks_where?= =?utf-8?q?_possible=2E?= Message-ID: <20150206170127.106285.21972@psf.io> https://hg.python.org/cpython/rev/9e6f79495e0b changeset: 94543:9e6f79495e0b parent: 94539:367f5e98ffbb parent: 94542:6b8d95c12eaf user: Barry Warsaw date: Fri Feb 06 11:58:06 2015 -0500 summary: Issue #23399: pyvenv creates relative symlinks where possible. files: Lib/venv/__init__.py | 14 ++++++++------ Misc/NEWS | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -141,10 +141,9 @@ # Issue 21197: create lib64 as a symlink to lib on 64-bit non-OS X POSIX if ((sys.maxsize > 2**32) and (os.name == 'posix') and (sys.platform != 'darwin')): - p = os.path.join(env_dir, 'lib') link_path = os.path.join(env_dir, 'lib64') if not os.path.exists(link_path): # Issue #21643 - os.symlink(p, link_path) + os.symlink('lib', link_path) context.bin_path = binpath = os.path.join(env_dir, binname) context.bin_name = binname context.env_exe = os.path.join(binpath, exename) @@ -178,7 +177,7 @@ result = f.startswith('python') and f.endswith('.exe') return result - def symlink_or_copy(self, src, dst): + def symlink_or_copy(self, src, dst, relative_symlinks_ok=False): """ Try symlinking a file, and if that fails, fall back to copying. """ @@ -186,7 +185,11 @@ if not force_copy: try: if not os.path.islink(dst): # can't link to itself! - os.symlink(src, dst) + if relative_symlinks_ok: + assert os.path.dirname(src) == os.path.dirname(dst) + os.symlink(os.path.basename(src), dst) + else: + os.symlink(src, dst) except Exception: # may need to use a more specific exception logger.warning('Unable to symlink %r to %r', src, dst) force_copy = True @@ -201,7 +204,6 @@ being processed. """ binpath = context.bin_path - exename = context.python_exe path = context.env_exe copier = self.symlink_or_copy copier(context.executable, path) @@ -214,7 +216,7 @@ if not os.path.exists(path): # Issue 18807: make copies if # symlinks are not wanted - copier(context.env_exe, path) + copier(context.env_exe, path, relative_symlinks_ok=True) if not os.path.islink(path): os.chmod(path, 0o755) else: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -235,6 +235,8 @@ Library ------- +- Issue #23399: pyvenv creates relative symlinks where possible. + - Issue #20289: cgi.FieldStorage() now supports the context management protocol. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 18:01:53 2015 From: python-checkins at python.org (barry.warsaw) Date: Fri, 06 Feb 2015 17:01:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzk5?= =?utf-8?q?=3A_pyvenv_creates_relative_symlinks_where_possible=2E?= Message-ID: <20150206170127.96098.19538@psf.io> https://hg.python.org/cpython/rev/6b8d95c12eaf changeset: 94542:6b8d95c12eaf branch: 3.4 parent: 94536:05153851d1d6 user: Barry Warsaw date: Fri Feb 06 11:23:58 2015 -0500 summary: Issue #23399: pyvenv creates relative symlinks where possible. files: Lib/venv/__init__.py | 14 ++++++++------ Misc/NEWS | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -141,10 +141,9 @@ # Issue 21197: create lib64 as a symlink to lib on 64-bit non-OS X POSIX if ((sys.maxsize > 2**32) and (os.name == 'posix') and (sys.platform != 'darwin')): - p = os.path.join(env_dir, 'lib') link_path = os.path.join(env_dir, 'lib64') if not os.path.exists(link_path): # Issue #21643 - os.symlink(p, link_path) + os.symlink('lib', link_path) context.bin_path = binpath = os.path.join(env_dir, binname) context.bin_name = binname context.env_exe = os.path.join(binpath, exename) @@ -178,7 +177,7 @@ result = f.startswith('python') and f.endswith('.exe') return result - def symlink_or_copy(self, src, dst): + def symlink_or_copy(self, src, dst, relative_symlinks_ok=False): """ Try symlinking a file, and if that fails, fall back to copying. """ @@ -186,7 +185,11 @@ if not force_copy: try: if not os.path.islink(dst): # can't link to itself! - os.symlink(src, dst) + if relative_symlinks_ok: + assert os.path.dirname(src) == os.path.dirname(dst) + os.symlink(os.path.basename(src), dst) + else: + os.symlink(src, dst) except Exception: # may need to use a more specific exception logger.warning('Unable to symlink %r to %r', src, dst) force_copy = True @@ -201,7 +204,6 @@ being processed. """ binpath = context.bin_path - exename = context.python_exe path = context.env_exe copier = self.symlink_or_copy copier(context.executable, path) @@ -214,7 +216,7 @@ if not os.path.exists(path): # Issue 18807: make copies if # symlinks are not wanted - copier(context.env_exe, path) + copier(context.env_exe, path, relative_symlinks_ok=True) if not os.path.islink(path): os.chmod(path, 0o755) else: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,8 @@ Library ------- +- Issue #23399: pyvenv creates relative symlinks where possible. + - Issue #23099: Closing io.BytesIO with exported buffer is rejected now to prevent corrupting exported buffer. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 18:01:53 2015 From: python-checkins at python.org (barry.warsaw) Date: Fri, 06 Feb 2015 17:01:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogVHJ1bmsgbWVyZ2Uu?= Message-ID: <20150206170127.34402.58822@psf.io> https://hg.python.org/cpython/rev/1ef6db8558b2 changeset: 94544:1ef6db8558b2 parent: 94543:9e6f79495e0b parent: 94541:3a8d67d208e0 user: Barry Warsaw date: Fri Feb 06 11:59:26 2015 -0500 summary: Trunk merge. files: Objects/typeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -565,7 +565,7 @@ static PyTypeObject *best_base(PyObject *); static int mro_internal(PyTypeObject *, PyObject **); -static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); +Py_LOCAL_INLINE(int) type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); static int add_subclass(PyTypeObject*, PyTypeObject*); static int add_all_subclasses(PyTypeObject *type, PyObject *bases); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 18:05:49 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 06 Feb 2015 17:05:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Require_Mercurial_on_PATH_?= =?utf-8?q?when_building_a_Windows_release=2E?= Message-ID: <20150206170420.34390.61109@psf.io> https://hg.python.org/cpython/rev/b9816fb6f28d changeset: 94547:b9816fb6f28d user: Steve Dower date: Fri Feb 06 09:02:54 2015 -0800 summary: Require Mercurial on PATH when building a Windows release. Without it, we will generate invalid build information for sys.version files: Tools/msi/buildrelease.bat | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -44,6 +44,9 @@ if errorlevel 1 goto :eof :skipdoc +where hg >nul 2>nul +if errorlevel 1 echo Cannot find hg on PATH & exit /B 1 + where dlltool 2>nul >"%TEMP%\dlltool.loc" if errorlevel 1 dir "%D%..\..\externals\dlltool.exe" /s/b > "%TEMP%\dlltool.loc" if errorlevel 1 echo Cannot find binutils on PATH or in externals & exit /B 1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 6 18:59:20 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 06 Feb 2015 17:59:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_download_URL_embedded_?= =?utf-8?q?in_Windows_installer=2E?= Message-ID: <20150206175917.25871.70678@psf.io> https://hg.python.org/cpython/rev/7ed9c601accd changeset: 94548:7ed9c601accd user: Steve Dower date: Fri Feb 06 09:59:05 2015 -0800 summary: Fix download URL embedded in Windows installer. files: Tools/msi/bundle/bundle.targets | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/msi/bundle/bundle.targets b/Tools/msi/bundle/bundle.targets --- a/Tools/msi/bundle/bundle.targets +++ b/Tools/msi/bundle/bundle.targets @@ -1,5 +1,5 @@ - + 2.0 Bundle -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sat Feb 7 10:06:48 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 07 Feb 2015 10:06:48 +0100 Subject: [Python-checkins] Daily reference leaks (7ed9c601accd): sum=3 Message-ID: results for 7ed9c601accd on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog5l9haf', '-x'] From python-checkins at python.org Sat Feb 7 11:57:46 2015 From: python-checkins at python.org (vinay.sajip) Date: Sat, 07 Feb 2015 10:57:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Corrected_typo?= =?utf-8?q?=2E?= Message-ID: <20150207105746.69899.62247@psf.io> https://hg.python.org/cpython/rev/c5f62f8d053e changeset: 94550:c5f62f8d053e branch: 3.4 user: Vinay Sajip date: Sat Feb 07 10:56:06 2015 +0000 summary: Corrected typo. files: Doc/using/venv-create.inc | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -21,7 +21,7 @@ On Windows, you may have to invoke the ``pyvenv`` script as follows, if you don't have the relevant PATH and PATHEXT settings:: - c:\Temp>c:\Python34\python c:\Python33\Tools\Scripts\pyvenv.py myenv + c:\Temp>c:\Python34\python c:\Python34\Tools\Scripts\pyvenv.py myenv or equivalently:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 7 11:57:46 2015 From: python-checkins at python.org (vinay.sajip) Date: Sat, 07 Feb 2015 10:57:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2323357=3A_Updated_documentation_on_creating_ven?= =?utf-8?b?dnMu?= Message-ID: <20150207105746.52858.40054@psf.io> https://hg.python.org/cpython/rev/751910294200 changeset: 94551:751910294200 parent: 94548:7ed9c601accd parent: 94550:c5f62f8d053e user: Vinay Sajip date: Sat Feb 07 10:57:36 2015 +0000 summary: Closes #23357: Updated documentation on creating venvs. files: Doc/using/venv-create.inc | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -21,16 +21,16 @@ On Windows, you may have to invoke the ``pyvenv`` script as follows, if you don't have the relevant PATH and PATHEXT settings:: - c:\Temp>c:\Python33\python c:\Python33\Tools\Scripts\pyvenv.py myenv + c:\Temp>c:\Python35\python c:\Python35\Tools\Scripts\pyvenv.py myenv or equivalently:: - c:\Temp>c:\Python33\python -m venv myenv + c:\Temp>c:\Python35\python -m venv myenv The command, if run with ``-h``, will show the available options:: - usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear] - [--upgrade] [--without-pip] ENV_DIR [ENV_DIR ...] + usage: venv [-h] [--system-site-packages] [--symlinks] [--clear] + [--upgrade] [--without-pip] ENV_DIR [ENV_DIR ...] Creates virtual Python environments in one or more target directories. @@ -53,6 +53,9 @@ --without-pip Skips installing or upgrading pip in the virtual environment (pip is bootstrapped by default) +Depending on how the ``venv`` functionality has been invoked, the usage message +may vary slightly, e.g. referencing ``pyvenv`` rather than ``venv``. + .. versionchanged:: 3.4 Installs pip by default, added the ``--without-pip`` and ``--copies`` options -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 7 11:57:46 2015 From: python-checkins at python.org (vinay.sajip) Date: Sat, 07 Feb 2015 10:57:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Minor_change_t?= =?utf-8?q?o_documentation_on_creating_venvs=2E?= Message-ID: <20150207105745.69907.83036@psf.io> https://hg.python.org/cpython/rev/9ff0e0724575 changeset: 94549:9ff0e0724575 branch: 3.4 parent: 94545:7a82b1539401 user: Vinay Sajip date: Sat Feb 07 10:52:02 2015 +0000 summary: Minor change to documentation on creating venvs. files: Doc/using/venv-create.inc | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -21,16 +21,16 @@ On Windows, you may have to invoke the ``pyvenv`` script as follows, if you don't have the relevant PATH and PATHEXT settings:: - c:\Temp>c:\Python33\python c:\Python33\Tools\Scripts\pyvenv.py myenv + c:\Temp>c:\Python34\python c:\Python33\Tools\Scripts\pyvenv.py myenv or equivalently:: - c:\Temp>c:\Python33\python -m venv myenv + c:\Temp>c:\Python34\python -m venv myenv The command, if run with ``-h``, will show the available options:: - usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear] - [--upgrade] [--without-pip] ENV_DIR [ENV_DIR ...] + usage: venv [-h] [--system-site-packages] [--symlinks] [--clear] + [--upgrade] [--without-pip] ENV_DIR [ENV_DIR ...] Creates virtual Python environments in one or more target directories. @@ -53,6 +53,9 @@ --without-pip Skips installing or upgrading pip in the virtual environment (pip is bootstrapped by default) +Depending on how the ``venv`` functionality has been invoked, the usage message +may vary slightly, e.g. referencing ``pyvenv`` rather than ``venv``. + .. versionchanged:: 3.4 Installs pip by default, added the ``--without-pip`` and ``--copies`` options -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 7 14:29:45 2015 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 07 Feb 2015 13:29:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_whitespace=2E?= Message-ID: <20150207132930.52878.40141@psf.io> https://hg.python.org/cpython/rev/7b493dbf944b changeset: 94553:7b493dbf944b user: Charles-Fran?ois Natali date: Sat Feb 07 13:29:15 2015 +0000 summary: Fix whitespace. files: Lib/test/test_socket.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3627,7 +3627,7 @@ self.serv.settimeout(self.timeout) def checkInterruptedRecv(self, func, *args, **kwargs): - # Check that func(*args, **kwargs) raises + # Check that func(*args, **kwargs) raises # errno of EINTR when interrupted by a signal. self.setAlarm(self.alarm_time) with self.assertRaises(ZeroDivisionError) as cm: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 7 14:29:46 2015 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 07 Feb 2015 13:29:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323285=3A_PEP_475_?= =?utf-8?q?--_Retry_system_calls_failing_with_EINTR=2E?= Message-ID: <20150207132930.69897.16757@psf.io> https://hg.python.org/cpython/rev/5b63010be19e changeset: 94552:5b63010be19e user: Charles-Fran?ois Natali date: Sat Feb 07 13:27:50 2015 +0000 summary: Issue #23285: PEP 475 -- Retry system calls failing with EINTR. files: Doc/whatsnew/3.5.rst | 10 + Lib/_pyio.py | 19 +- Lib/distutils/spawn.py | 3 - Lib/multiprocessing/connection.py | 18 +- Lib/multiprocessing/forkserver.py | 18 +- Lib/multiprocessing/popen_fork.py | 3 - Lib/socket.py | 2 - Lib/socketserver.py | 2 - Lib/subprocess.py | 18 +- Lib/test/eintrdata/eintr_tester.py | 260 ++++++++++ Lib/test/test_eintr.py | 20 + Lib/test/test_signal.py | 7 +- Lib/test/test_socket.py | 124 +---- Lib/test/test_subprocess.py | 20 - Misc/NEWS | 2 + Modules/_io/fileio.c | 125 ++-- Modules/posixmodule.c | 431 ++++++++++------ Modules/socketmodule.c | 249 +++++---- 18 files changed, 781 insertions(+), 550 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -111,6 +111,16 @@ PEP written by Carl Meyer +PEP 475: Retry system calls failing with EINTR +---------------------------------------------- + +:pep:`475` adds support for automatic retry of system calls failing with EINTR: +this means that user code doesn't have to deal with EINTR or InterruptedError +manually, and should make it more robust against asynchronous signal reception. + +.. seealso:: + + :pep:`475` -- Retry system calls failing with EINTR Other Language Changes diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -1012,10 +1012,7 @@ current_size = 0 while True: # Read until EOF or until read() would block. - try: - chunk = self.raw.read() - except InterruptedError: - continue + chunk = self.raw.read() if chunk in empty_values: nodata_val = chunk break @@ -1034,10 +1031,7 @@ chunks = [buf[pos:]] wanted = max(self.buffer_size, n) while avail < n: - try: - chunk = self.raw.read(wanted) - except InterruptedError: - continue + chunk = self.raw.read(wanted) if chunk in empty_values: nodata_val = chunk break @@ -1066,12 +1060,7 @@ have = len(self._read_buf) - self._read_pos if have < want or have <= 0: to_read = self.buffer_size - have - while True: - try: - current = self.raw.read(to_read) - except InterruptedError: - continue - break + current = self.raw.read(to_read) if current: self._read_buf = self._read_buf[self._read_pos:] + current self._read_pos = 0 @@ -1220,8 +1209,6 @@ while self._write_buf: try: n = self.raw.write(self._write_buf) - except InterruptedError: - continue except BlockingIOError: raise RuntimeError("self.raw should implement RawIOBase: it " "should not raise BlockingIOError") diff --git a/Lib/distutils/spawn.py b/Lib/distutils/spawn.py --- a/Lib/distutils/spawn.py +++ b/Lib/distutils/spawn.py @@ -137,9 +137,6 @@ try: pid, status = os.waitpid(pid, 0) except OSError as exc: - import errno - if exc.errno == errno.EINTR: - continue if not DEBUG: cmd = executable raise DistutilsExecError( diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -365,10 +365,7 @@ def _send(self, buf, write=_write): remaining = len(buf) while True: - try: - n = write(self._handle, buf) - except InterruptedError: - continue + n = write(self._handle, buf) remaining -= n if remaining == 0: break @@ -379,10 +376,7 @@ handle = self._handle remaining = size while remaining > 0: - try: - chunk = read(handle, remaining) - except InterruptedError: - continue + chunk = read(handle, remaining) n = len(chunk) if n == 0: if remaining == size: @@ -595,13 +589,7 @@ self._unlink = None def accept(self): - while True: - try: - s, self._last_accepted = self._socket.accept() - except InterruptedError: - pass - else: - break + s, self._last_accepted = self._socket.accept() s.setblocking(True) return Connection(s.detach()) diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py --- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -188,8 +188,6 @@ finally: os._exit(code) - except InterruptedError: - pass except OSError as e: if e.errno != errno.ECONNABORTED: raise @@ -230,13 +228,7 @@ data = b'' length = UNSIGNED_STRUCT.size while len(data) < length: - while True: - try: - s = os.read(fd, length - len(data)) - except InterruptedError: - pass - else: - break + s = os.read(fd, length - len(data)) if not s: raise EOFError('unexpected EOF') data += s @@ -245,13 +237,7 @@ def write_unsigned(fd, n): msg = UNSIGNED_STRUCT.pack(n) while msg: - while True: - try: - nbytes = os.write(fd, msg) - except InterruptedError: - pass - else: - break + nbytes = os.write(fd, msg) if nbytes == 0: raise RuntimeError('should not get here') msg = msg[nbytes:] diff --git a/Lib/multiprocessing/popen_fork.py b/Lib/multiprocessing/popen_fork.py --- a/Lib/multiprocessing/popen_fork.py +++ b/Lib/multiprocessing/popen_fork.py @@ -1,7 +1,6 @@ import os import sys import signal -import errno from . import util @@ -29,8 +28,6 @@ try: pid, sts = os.waitpid(self.pid, flag) except OSError as e: - if e.errno == errno.EINTR: - continue # Child process not yet created. See #1731717 # e.errno == errno.ECHILD == 10 return None diff --git a/Lib/socket.py b/Lib/socket.py --- a/Lib/socket.py +++ b/Lib/socket.py @@ -572,8 +572,6 @@ except timeout: self._timeout_occurred = True raise - except InterruptedError: - continue except error as e: if e.args[0] in _blocking_errnos: return None diff --git a/Lib/socketserver.py b/Lib/socketserver.py --- a/Lib/socketserver.py +++ b/Lib/socketserver.py @@ -553,8 +553,6 @@ try: pid, _ = os.waitpid(-1, 0) self.active_children.discard(pid) - except InterruptedError: - pass except ChildProcessError: # we don't have any children, we're done self.active_children.clear() diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -489,14 +489,6 @@ DEVNULL = -3 -def _eintr_retry_call(func, *args): - while True: - try: - return func(*args) - except InterruptedError: - continue - - # XXX This function is only used by multiprocessing and the test suite, # but it's here so that it can be imported when Python is compiled without # threads. @@ -963,10 +955,10 @@ if self.stdin: self._stdin_write(input) elif self.stdout: - stdout = _eintr_retry_call(self.stdout.read) + stdout = self.stdout.read() self.stdout.close() elif self.stderr: - stderr = _eintr_retry_call(self.stderr.read) + stderr = self.stderr.read() self.stderr.close() self.wait() else: @@ -1410,7 +1402,7 @@ # exception (limited in size) errpipe_data = bytearray() while True: - part = _eintr_retry_call(os.read, errpipe_read, 50000) + part = os.read(errpipe_read, 50000) errpipe_data += part if not part or len(errpipe_data) > 50000: break @@ -1420,7 +1412,7 @@ if errpipe_data: try: - _eintr_retry_call(os.waitpid, self.pid, 0) + os.waitpid(self.pid, 0) except ChildProcessError: pass try: @@ -1505,7 +1497,7 @@ def _try_wait(self, wait_flags): """All callers to this function MUST hold self._waitpid_lock.""" try: - (pid, sts) = _eintr_retry_call(os.waitpid, self.pid, wait_flags) + (pid, sts) = os.waitpid(self.pid, wait_flags) except ChildProcessError: # This happens if SIGCLD is set to be ignored or waiting # for child processes has otherwise been disabled for our diff --git a/Lib/test/eintrdata/eintr_tester.py b/Lib/test/eintrdata/eintr_tester.py new file mode 100644 --- /dev/null +++ b/Lib/test/eintrdata/eintr_tester.py @@ -0,0 +1,260 @@ +""" +This test suite exercises some system calls subject to interruption with EINTR, +to check that it is actually handled transparently. +It is intended to be run by the main test suite within a child process, to +ensure there is no background thread running (so that signals are delivered to +the correct thread). +Signals are generated in-process using setitimer(ITIMER_REAL), which allows +sub-second periodicity (contrarily to signal()). +""" + +import io +import os +import signal +import socket +import time +import unittest + +from test import support + + + at unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") +class EINTRBaseTest(unittest.TestCase): + """ Base class for EINTR tests. """ + + # delay for initial signal delivery + signal_delay = 0.1 + # signal delivery periodicity + signal_period = 0.1 + # default sleep time for tests - should obviously have: + #?sleep_time > signal_period + sleep_time = 0.2 + + @classmethod + def setUpClass(cls): + cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None) + signal.setitimer(signal.ITIMER_REAL, cls.signal_delay, + cls.signal_period) + + @classmethod + def tearDownClass(cls): + signal.setitimer(signal.ITIMER_REAL, 0, 0) + signal.signal(signal.SIGALRM, cls.orig_handler) + + @classmethod + def _sleep(cls): + # default sleep time + time.sleep(cls.sleep_time) + + + at unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") +class OSEINTRTest(EINTRBaseTest): + """ EINTR tests for the os module. """ + + def _test_wait_multiple(self, wait_func): + num = 3 + for _ in range(num): + pid = os.fork() + if pid == 0: + self._sleep() + os._exit(0) + for _ in range(num): + wait_func() + + def test_wait(self): + self._test_wait_multiple(os.wait) + + @unittest.skipUnless(hasattr(os, 'wait3'), 'requires wait3()') + def test_wait3(self): + self._test_wait_multiple(lambda: os.wait3(0)) + + def _test_wait_single(self, wait_func): + pid = os.fork() + if pid == 0: + self._sleep() + os._exit(0) + else: + wait_func(pid) + + def test_waitpid(self): + self._test_wait_single(lambda pid: os.waitpid(pid, 0)) + + @unittest.skipUnless(hasattr(os, 'wait4'), 'requires wait4()') + def test_wait4(self): + self._test_wait_single(lambda pid: os.wait4(pid, 0)) + + def test_read(self): + rd, wr = os.pipe() + self.addCleanup(os.close, rd) + # wr closed explicitly by parent + + # the payload below are smaller than PIPE_BUF, hence the writes will be + # atomic + datas = [b"hello", b"world", b"spam"] + + pid = os.fork() + if pid == 0: + os.close(rd) + for data in datas: + # let the parent block on read() + self._sleep() + os.write(wr, data) + os._exit(0) + else: + self.addCleanup(os.waitpid, pid, 0) + os.close(wr) + for data in datas: + self.assertEqual(data, os.read(rd, len(data))) + + def test_write(self): + rd, wr = os.pipe() + self.addCleanup(os.close, wr) + # rd closed explicitly by parent + + # we must write enough data for the write() to block + data = b"xyz" * support.PIPE_MAX_SIZE + + pid = os.fork() + if pid == 0: + os.close(wr) + read_data = io.BytesIO() + # let the parent block on write() + self._sleep() + while len(read_data.getvalue()) < len(data): + chunk = os.read(rd, 2 * len(data)) + read_data.write(chunk) + self.assertEqual(read_data.getvalue(), data) + os._exit(0) + else: + os.close(rd) + written = 0 + while written < len(data): + written += os.write(wr, memoryview(data)[written:]) + self.assertEqual(0, os.waitpid(pid, 0)[1]) + + + at unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") +class SocketEINTRTest(EINTRBaseTest): + """ EINTR tests for the socket module. """ + + @unittest.skipUnless(hasattr(socket, 'socketpair'), 'needs socketpair()') + def _test_recv(self, recv_func): + rd, wr = socket.socketpair() + self.addCleanup(rd.close) + # wr closed explicitly by parent + + # single-byte payload guard us against partial recv + datas = [b"x", b"y", b"z"] + + pid = os.fork() + if pid == 0: + rd.close() + for data in datas: + # let the parent block on recv() + self._sleep() + wr.sendall(data) + os._exit(0) + else: + self.addCleanup(os.waitpid, pid, 0) + wr.close() + for data in datas: + self.assertEqual(data, recv_func(rd, len(data))) + + def test_recv(self): + self._test_recv(socket.socket.recv) + + @unittest.skipUnless(hasattr(socket.socket, 'recvmsg'), 'needs recvmsg()') + def test_recvmsg(self): + self._test_recv(lambda sock, data: sock.recvmsg(data)[0]) + + def _test_send(self, send_func): + rd, wr = socket.socketpair() + self.addCleanup(wr.close) + # rd closed explicitly by parent + + # we must send enough data for the send() to block + data = b"xyz" * (support.SOCK_MAX_SIZE // 3) + + pid = os.fork() + if pid == 0: + wr.close() + # let the parent block on send() + self._sleep() + received_data = bytearray(len(data)) + n = 0 + while n < len(data): + n += rd.recv_into(memoryview(received_data)[n:]) + self.assertEqual(received_data, data) + os._exit(0) + else: + rd.close() + written = 0 + while written < len(data): + sent = send_func(wr, memoryview(data)[written:]) + # sendall() returns None + written += len(data) if sent is None else sent + self.assertEqual(0, os.waitpid(pid, 0)[1]) + + def test_send(self): + self._test_send(socket.socket.send) + + def test_sendall(self): + self._test_send(socket.socket.sendall) + + @unittest.skipUnless(hasattr(socket.socket, 'sendmsg'), 'needs sendmsg()') + def test_sendmsg(self): + self._test_send(lambda sock, data: sock.sendmsg([data])) + + def test_accept(self): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(sock.close) + + sock.bind((support.HOST, 0)) + _, port = sock.getsockname() + sock.listen() + + pid = os.fork() + if pid == 0: + # let parent block on accept() + self._sleep() + with socket.create_connection((support.HOST, port)): + self._sleep() + os._exit(0) + else: + self.addCleanup(os.waitpid, pid, 0) + client_sock, _ = sock.accept() + client_sock.close() + + @unittest.skipUnless(hasattr(os, 'mkfifo'), 'needs mkfifo()') + def _test_open(self, do_open_close_reader, do_open_close_writer): + # Use a fifo: until the child opens it for reading, the parent will + # block when trying to open it for writing. + support.unlink(support.TESTFN) + os.mkfifo(support.TESTFN) + self.addCleanup(support.unlink, support.TESTFN) + + pid = os.fork() + if pid == 0: + # let the parent block + self._sleep() + do_open_close_reader(support.TESTFN) + os._exit(0) + else: + self.addCleanup(os.waitpid, pid, 0) + do_open_close_writer(support.TESTFN) + + def test_open(self): + self._test_open(lambda path: open(path, 'r').close(), + lambda path: open(path, 'w').close()) + + def test_os_open(self): + self._test_open(lambda path: os.close(os.open(path, os.O_RDONLY)), + lambda path: os.close(os.open(path, os.O_WRONLY))) + + +def test_main(): + support.run_unittest(OSEINTRTest, SocketEINTRTest) + + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_eintr.py b/Lib/test/test_eintr.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_eintr.py @@ -0,0 +1,20 @@ +import os +import signal +import unittest + +from test import script_helper, support + + + at unittest.skipUnless(os.name == "posix", "only supported on Unix") +class EINTRTests(unittest.TestCase): + + @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") + def test_all(self): + # Run the tester in a sub-process, to make sure there is only one + # thread (for reliable signal delivery). + tester = support.findfile("eintr_tester.py", subdir="eintrdata") + script_helper.assert_python_ok(tester) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -587,7 +587,7 @@ r, w = os.pipe() def handler(signum, frame): - pass + 1 / 0 signal.signal(signal.SIGALRM, handler) if interrupt is not None: @@ -604,9 +604,8 @@ try: # blocking call: read from a pipe without data os.read(r, 1) - except OSError as err: - if err.errno != errno.EINTR: - raise + except ZeroDivisionError: + pass else: sys.exit(2) sys.exit(3) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3590,7 +3590,7 @@ def setUp(self): super().setUp() orig_alrm_handler = signal.signal(signal.SIGALRM, - lambda signum, frame: None) + lambda signum, frame: 1 / 0) self.addCleanup(signal.signal, signal.SIGALRM, orig_alrm_handler) self.addCleanup(self.setAlarm, 0) @@ -3627,13 +3627,11 @@ self.serv.settimeout(self.timeout) def checkInterruptedRecv(self, func, *args, **kwargs): - # Check that func(*args, **kwargs) raises OSError with an + # Check that func(*args, **kwargs) raises # errno of EINTR when interrupted by a signal. self.setAlarm(self.alarm_time) - with self.assertRaises(OSError) as cm: + with self.assertRaises(ZeroDivisionError) as cm: func(*args, **kwargs) - self.assertNotIsInstance(cm.exception, socket.timeout) - self.assertEqual(cm.exception.errno, errno.EINTR) def testInterruptedRecvTimeout(self): self.checkInterruptedRecv(self.serv.recv, 1024) @@ -3689,12 +3687,10 @@ # Check that func(*args, **kwargs), run in a loop, raises # OSError with an errno of EINTR when interrupted by a # signal. - with self.assertRaises(OSError) as cm: + with self.assertRaises(ZeroDivisionError) as cm: while True: self.setAlarm(self.alarm_time) func(*args, **kwargs) - self.assertNotIsInstance(cm.exception, socket.timeout) - self.assertEqual(cm.exception.errno, errno.EINTR) # Issue #12958: The following tests have problems on OS X prior to 10.7 @support.requires_mac_ver(10, 7) @@ -4062,117 +4058,6 @@ pass -class FileObjectInterruptedTestCase(unittest.TestCase): - """Test that the file object correctly handles EINTR internally.""" - - class MockSocket(object): - def __init__(self, recv_funcs=()): - # A generator that returns callables that we'll call for each - # call to recv(). - self._recv_step = iter(recv_funcs) - - def recv_into(self, buffer): - data = next(self._recv_step)() - assert len(buffer) >= len(data) - buffer[:len(data)] = data - return len(data) - - def _decref_socketios(self): - pass - - def _textiowrap_for_test(self, buffering=-1): - raw = socket.SocketIO(self, "r") - if buffering < 0: - buffering = io.DEFAULT_BUFFER_SIZE - if buffering == 0: - return raw - buffer = io.BufferedReader(raw, buffering) - text = io.TextIOWrapper(buffer, None, None) - text.mode = "rb" - return text - - @staticmethod - def _raise_eintr(): - raise OSError(errno.EINTR, "interrupted") - - def _textiowrap_mock_socket(self, mock, buffering=-1): - raw = socket.SocketIO(mock, "r") - if buffering < 0: - buffering = io.DEFAULT_BUFFER_SIZE - if buffering == 0: - return raw - buffer = io.BufferedReader(raw, buffering) - text = io.TextIOWrapper(buffer, None, None) - text.mode = "rb" - return text - - def _test_readline(self, size=-1, buffering=-1): - mock_sock = self.MockSocket(recv_funcs=[ - lambda : b"This is the first line\nAnd the sec", - self._raise_eintr, - lambda : b"ond line is here\n", - lambda : b"", - lambda : b"", # XXX(gps): io library does an extra EOF read - ]) - fo = mock_sock._textiowrap_for_test(buffering=buffering) - self.assertEqual(fo.readline(size), "This is the first line\n") - self.assertEqual(fo.readline(size), "And the second line is here\n") - - def _test_read(self, size=-1, buffering=-1): - mock_sock = self.MockSocket(recv_funcs=[ - lambda : b"This is the first line\nAnd the sec", - self._raise_eintr, - lambda : b"ond line is here\n", - lambda : b"", - lambda : b"", # XXX(gps): io library does an extra EOF read - ]) - expecting = (b"This is the first line\n" - b"And the second line is here\n") - fo = mock_sock._textiowrap_for_test(buffering=buffering) - if buffering == 0: - data = b'' - else: - data = '' - expecting = expecting.decode('utf-8') - while len(data) != len(expecting): - part = fo.read(size) - if not part: - break - data += part - self.assertEqual(data, expecting) - - def test_default(self): - self._test_readline() - self._test_readline(size=100) - self._test_read() - self._test_read(size=100) - - def test_with_1k_buffer(self): - self._test_readline(buffering=1024) - self._test_readline(size=100, buffering=1024) - self._test_read(buffering=1024) - self._test_read(size=100, buffering=1024) - - def _test_readline_no_buffer(self, size=-1): - mock_sock = self.MockSocket(recv_funcs=[ - lambda : b"a", - lambda : b"\n", - lambda : b"B", - self._raise_eintr, - lambda : b"b", - lambda : b"", - ]) - fo = mock_sock._textiowrap_for_test(buffering=0) - self.assertEqual(fo.readline(size), b"a\n") - self.assertEqual(fo.readline(size), b"Bb") - - def test_no_buffer(self): - self._test_readline_no_buffer() - self._test_readline_no_buffer(size=4) - self._test_read(buffering=0) - self._test_read(size=100, buffering=0) - - class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase): """Repeat the tests from FileObjectClassTestCase with bufsize==0. @@ -5388,7 +5273,6 @@ tests.extend([ NonBlockingTCPTests, FileObjectClassTestCase, - FileObjectInterruptedTestCase, UnbufferedFileObjectClassTestCase, LineBufferedFileObjectClassTestCase, SmallBufferedFileObjectClassTestCase, diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -2421,25 +2421,6 @@ ProcessTestCase.tearDown(self) -class HelperFunctionTests(unittest.TestCase): - @unittest.skipIf(mswindows, "errno and EINTR make no sense on windows") - def test_eintr_retry_call(self): - record_calls = [] - def fake_os_func(*args): - record_calls.append(args) - if len(record_calls) == 2: - raise OSError(errno.EINTR, "fake interrupted system call") - return tuple(reversed(args)) - - self.assertEqual((999, 256), - subprocess._eintr_retry_call(fake_os_func, 256, 999)) - self.assertEqual([(256, 999)], record_calls) - # This time there will be an EINTR so it will loop once. - self.assertEqual((666,), - subprocess._eintr_retry_call(fake_os_func, 666)) - self.assertEqual([(256, 999), (666,), (666,)], record_calls) - - @unittest.skipUnless(mswindows, "Windows-specific tests") class CommandsWithSpaces (BaseTestCase): @@ -2528,7 +2509,6 @@ Win32ProcessTestCase, CommandTests, ProcessTestCaseNoPoll, - HelperFunctionTests, CommandsWithSpaces, ContextManagerTests, ) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #23285: PEP 475 - EINTR handling. + - Issue #22735: Fix many edge cases (including crashes) involving custom mro() implementations. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -218,6 +218,7 @@ #ifdef HAVE_FSTAT struct stat fdfstat; #endif + int async_err = 0; assert(PyFileIO_Check(oself)); if (self->fd >= 0) { @@ -360,15 +361,18 @@ errno = 0; if (opener == Py_None) { - Py_BEGIN_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - if (widename != NULL) - self->fd = _wopen(widename, flags, 0666); - else + if (widename != NULL) + self->fd = _wopen(widename, flags, 0666); + else #endif - self->fd = open(name, flags, 0666); + self->fd = open(name, flags, 0666); - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (self->fd < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else { PyObject *fdobj; @@ -397,7 +401,8 @@ fd_is_own = 1; if (self->fd < 0) { - PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); + if (!async_err) + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); goto error; } @@ -550,7 +555,7 @@ { Py_buffer pbuf; Py_ssize_t n, len; - int err; + int err, async_err = 0; if (self->fd < 0) return err_closed(); @@ -562,16 +567,19 @@ if (_PyVerify_fd(self->fd)) { len = pbuf.len; - Py_BEGIN_ALLOW_THREADS - errno = 0; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = read(self->fd, pbuf.buf, (int)len); + if (len > INT_MAX) + len = INT_MAX; + n = read(self->fd, pbuf.buf, (int)len); #else - n = read(self->fd, pbuf.buf, len); + n = read(self->fd, pbuf.buf, len); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else n = -1; err = errno; @@ -580,7 +588,8 @@ if (err == EAGAIN) Py_RETURN_NONE; errno = err; - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } @@ -627,6 +636,7 @@ Py_ssize_t bytes_read = 0; Py_ssize_t n; size_t bufsize; + int async_err = 0; if (self->fd < 0) return err_closed(); @@ -673,27 +683,23 @@ return NULL; } } - Py_BEGIN_ALLOW_THREADS - errno = 0; - n = bufsize - bytes_read; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; + n = bufsize - bytes_read; #ifdef MS_WINDOWS - if (n > INT_MAX) - n = INT_MAX; - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n); + if (n > INT_MAX) + n = INT_MAX; + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n); #else - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); if (n == 0) break; if (n < 0) { - if (errno == EINTR) { - if (PyErr_CheckSignals()) { - Py_DECREF(result); - return NULL; - } - continue; - } if (errno == EAGAIN) { if (bytes_read > 0) break; @@ -701,7 +707,8 @@ Py_RETURN_NONE; } Py_DECREF(result); - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } bytes_read += n; @@ -723,6 +730,7 @@ char *ptr; Py_ssize_t n; Py_ssize_t size = -1; + int async_err = 0; PyObject *bytes; if (self->fd < 0) @@ -747,14 +755,17 @@ ptr = PyBytes_AS_STRING(bytes); if (_PyVerify_fd(self->fd)) { - Py_BEGIN_ALLOW_THREADS - errno = 0; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; #ifdef MS_WINDOWS - n = read(self->fd, ptr, (int)size); + n = read(self->fd, ptr, (int)size); #else - n = read(self->fd, ptr, size); + n = read(self->fd, ptr, size); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else n = -1; @@ -764,7 +775,8 @@ if (err == EAGAIN) Py_RETURN_NONE; errno = err; - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } @@ -783,7 +795,7 @@ { Py_buffer pbuf; Py_ssize_t n, len; - int err; + int err, async_err = 0; if (self->fd < 0) return err_closed(); @@ -794,24 +806,26 @@ return NULL; if (_PyVerify_fd(self->fd)) { - Py_BEGIN_ALLOW_THREADS - errno = 0; - len = pbuf.len; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; + len = pbuf.len; #ifdef MS_WINDOWS - if (len > 32767 && isatty(self->fd)) { - /* Issue #11395: the Windows console returns an error (12: not - enough space error) on writing into stdout if stdout mode is - binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). */ - len = 32767; - } - else if (len > INT_MAX) - len = INT_MAX; - n = write(self->fd, pbuf.buf, (int)len); + if (len > 32767 && isatty(self->fd)) { + /* Issue #11395: the Windows console returns an error (12: not + enough space error) on writing into stdout if stdout mode is + binary and the length is greater than 66,000 bytes (or less, + depending on heap usage). */ + len = 32767; + } else if (len > INT_MAX) + len = INT_MAX; + n = write(self->fd, pbuf.buf, (int)len); #else - n = write(self->fd, pbuf.buf, len); + n = write(self->fd, pbuf.buf, len); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else n = -1; err = errno; @@ -822,7 +836,8 @@ if (err == EAGAIN) Py_RETURN_NONE; errno = err; - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1361,13 +1361,16 @@ posix_fildes_fd(int fd, int (*func)(int)) { int res; - Py_BEGIN_ALLOW_THREADS - res = (*func)(fd); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); - Py_INCREF(Py_None); - return Py_None; + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = (*func)(fd); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; + Py_RETURN_NONE; } @@ -3479,11 +3482,16 @@ /*[clinic end generated code: output=3c19fbfd724a8e0f input=8ab11975ca01ee5b]*/ { int res; - Py_BEGIN_ALLOW_THREADS - res = fchmod(fd, mode); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = fchmod(fd, mode); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; + Py_RETURN_NONE; } #endif /* HAVE_FCHMOD */ @@ -4104,11 +4112,16 @@ /*[clinic end generated code: output=687781cb7d8974d6 input=3af544ba1b13a0d7]*/ { int res; - Py_BEGIN_ALLOW_THREADS - res = fchown(fd, uid, gid); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = fchown(fd, uid, gid); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; + Py_RETURN_NONE; } #endif /* HAVE_FCHOWN */ @@ -9602,12 +9615,17 @@ { pid_t pid; struct rusage ru; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - Py_BEGIN_ALLOW_THREADS - pid = wait3(&status, options, &ru); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + pid = wait3(&status, options, &ru); + Py_END_ALLOW_THREADS + } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (pid < 0) + return (!async_err) ? posix_error() : NULL; return wait_helper(pid, WAIT_STATUS_INT(status), &ru); } @@ -9665,15 +9683,21 @@ os_wait4_impl(PyModuleDef *module, pid_t pid, int options) /*[clinic end generated code: output=20dfb05289d37dc6 input=d11deed0750600ba]*/ { + pid_t res; struct rusage ru; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - Py_BEGIN_ALLOW_THREADS - pid = wait4(pid, &status, options, &ru); - Py_END_ALLOW_THREADS - - return wait_helper(pid, WAIT_STATUS_INT(status), &ru); + do { + Py_BEGIN_ALLOW_THREADS + res = wait4(pid, &status, options, &ru); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res < 0) + return (!async_err) ? posix_error() : NULL; + + return wait_helper(res, WAIT_STATUS_INT(status), &ru); } #endif /* HAVE_WAIT4 */ @@ -9744,14 +9768,17 @@ { PyObject *result; int res; + int async_err = 0; siginfo_t si; si.si_pid = 0; - Py_BEGIN_ALLOW_THREADS - res = waitid(idtype, id, &si, options); - Py_END_ALLOW_THREADS - if (res == -1) - return posix_error(); + do { + Py_BEGIN_ALLOW_THREADS + res = waitid(idtype, id, &si, options); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res < 0) + return (!async_err) ? posix_error() : NULL; if (si.si_pid == 0) Py_RETURN_NONE; @@ -9828,16 +9855,20 @@ os_waitpid_impl(PyModuleDef *module, pid_t pid, int options) /*[clinic end generated code: output=095a6b00af70b7ac input=0bf1666b8758fda3]*/ { + pid_t res; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - Py_BEGIN_ALLOW_THREADS - pid = waitpid(pid, &status, options); - Py_END_ALLOW_THREADS - if (pid == -1) - return posix_error(); - - return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status)); + do { + Py_BEGIN_ALLOW_THREADS + res = waitpid(pid, &status, options); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res < 0) + return (!async_err) ? posix_error() : NULL; + + return Py_BuildValue("Ni", PyLong_FromPid(res), WAIT_STATUS_INT(status)); } #elif defined(HAVE_CWAIT) /* MS C has a variant of waitpid() that's usable for most purposes. */ @@ -9894,15 +9925,19 @@ /*[clinic end generated code: output=c20b95b15ad44a3a input=444c8f51cca5b862]*/ { int status; - - Py_BEGIN_ALLOW_THREADS - pid = _cwait(&status, pid, options); - Py_END_ALLOW_THREADS - if (pid == -1) - return posix_error(); + Py_intptr_t res; + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = _cwait(&status, pid, options); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; /* shift the status left a byte so this is more like the POSIX waitpid */ - return Py_BuildValue(_Py_PARSE_INTPTR "i", pid, status << 8); + return Py_BuildValue(_Py_PARSE_INTPTR "i", res, status << 8); } #endif @@ -9943,14 +9978,17 @@ /*[clinic end generated code: output=2a83a9d164e7e6a8 input=03b0182d4a4700ce]*/ { pid_t pid; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - Py_BEGIN_ALLOW_THREADS - pid = wait(&status); - Py_END_ALLOW_THREADS - if (pid == -1) - return posix_error(); + do { + Py_BEGIN_ALLOW_THREADS + pid = wait(&status); + Py_END_ALLOW_THREADS + } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (pid < 0) + return (!async_err) ? posix_error() : NULL; return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status)); } @@ -10837,6 +10875,7 @@ /*[clinic end generated code: output=05b68fc4ed5e29c9 input=ad8623b29acd2934]*/ { int fd; + int async_err = 0; #ifdef O_CLOEXEC int *atomic_flag_works = &_Py_open_cloexec_works; @@ -10850,22 +10889,25 @@ flags |= O_CLOEXEC; #endif - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (path->wide) - fd = _wopen(path->wide, flags, mode); - else + do { + Py_BEGIN_ALLOW_THREADS +#ifdef MS_WINDOWS + if (path->wide) + fd = _wopen(path->wide, flags, mode); + else #endif #ifdef HAVE_OPENAT - if (dir_fd != DEFAULT_DIR_FD) - fd = openat(dir_fd, path->narrow, flags, mode); - else -#endif - fd = open(path->narrow, flags, mode); - Py_END_ALLOW_THREADS + if (dir_fd != DEFAULT_DIR_FD) + fd = openat(dir_fd, path->narrow, flags, mode); + else +#endif + fd = open(path->narrow, flags, mode); + Py_END_ALLOW_THREADS + } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (fd == -1) { - PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); + if (!async_err) + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); return -1; } @@ -10924,6 +10966,10 @@ int res; if (!_PyVerify_fd(fd)) return posix_error(); + /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/ + * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + * for more details. + */ Py_BEGIN_ALLOW_THREADS res = close(fd); Py_END_ALLOW_THREADS @@ -11089,6 +11135,10 @@ if (!_PyVerify_fd_dup2(fd, fd2)) return posix_error(); + /* dup2() can fail with EINTR if the target FD is already open, because it + * then has to be closed. See os_close_impl() for why we don't handle EINTR + * upon close(), and therefore below. + */ #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS res = dup2(fd, fd2); @@ -11355,6 +11405,7 @@ /*[clinic end generated code: output=1f3bc27260a24968 input=1df2eaa27c0bf1d3]*/ { Py_ssize_t n; + int async_err = 0; PyObject *buffer; if (length < 0) { @@ -11375,13 +11426,16 @@ buffer = PyBytes_FromStringAndSize((char *)NULL, length); if (buffer == NULL) return NULL; - Py_BEGIN_ALLOW_THREADS - n = read(fd, PyBytes_AS_STRING(buffer), READ_CAST length); - Py_END_ALLOW_THREADS + + do { + Py_BEGIN_ALLOW_THREADS + n = read(fd, PyBytes_AS_STRING(buffer), READ_CAST length); + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (n < 0) { Py_DECREF(buffer); - return posix_error(); + return (!async_err) ? posix_error() : NULL; } if (n != length) @@ -11515,6 +11569,7 @@ { int cnt; Py_ssize_t n; + int async_err = 0; struct iovec *iov; Py_buffer *buf; @@ -11529,13 +11584,16 @@ if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0) return -1; - Py_BEGIN_ALLOW_THREADS - n = readv(fd, iov, cnt); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + n = readv(fd, iov, cnt); + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); iov_cleanup(iov, buf, cnt); if (n < 0) { - posix_error(); + if (!async_err) + posix_error(); return -1; } @@ -11598,6 +11656,7 @@ /*[clinic end generated code: output=7b62bf6c06e20ae8 input=084948dcbaa35d4c]*/ { Py_ssize_t n; + int async_err = 0; PyObject *buffer; if (length < 0) { @@ -11611,12 +11670,16 @@ Py_DECREF(buffer); return posix_error(); } - Py_BEGIN_ALLOW_THREADS - n = pread(fd, PyBytes_AS_STRING(buffer), length, offset); - Py_END_ALLOW_THREADS + + do { + Py_BEGIN_ALLOW_THREADS + n = pread(fd, PyBytes_AS_STRING(buffer), length, offset); + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (n < 0) { Py_DECREF(buffer); - return posix_error(); + return (!async_err) ? posix_error() : NULL; } if (n != length) _PyBytes_Resize(&buffer, n); @@ -11677,6 +11740,7 @@ /*[clinic end generated code: output=aeb96acfdd4d5112 input=3207e28963234f3c]*/ { Py_ssize_t size; + int async_err = 0; Py_ssize_t len = data->len; if (!_PyVerify_fd(fd)) { @@ -11684,17 +11748,21 @@ return -1; } - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - size = write(fd, data->buf, (int)len); -#else - size = write(fd, data->buf, len); -#endif - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS +#ifdef MS_WINDOWS + if (len > INT_MAX) + len = INT_MAX; + size = write(fd, data->buf, (int)len); +#else + size = write(fd, data->buf, len); +#endif + Py_END_ALLOW_THREADS + } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (size < 0) { - posix_error(); + if (!async_err) + posix_error(); return -1; } return size; @@ -11713,6 +11781,7 @@ { int in, out; Py_ssize_t ret; + int async_err = 0; off_t offset; #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) @@ -11775,13 +11844,15 @@ } } - Py_BEGIN_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS #ifdef __APPLE__ - ret = sendfile(in, out, offset, &sbytes, &sf, flags); -#else - ret = sendfile(in, out, offset, len, &sf, &sbytes, flags); -#endif - Py_END_ALLOW_THREADS + ret = sendfile(in, out, offset, &sbytes, &sf, flags); +#else + ret = sendfile(in, out, offset, len, &sf, &sbytes, flags); +#endif + Py_END_ALLOW_THREADS + } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (sf.headers != NULL) iov_cleanup(sf.headers, hbuf, sf.hdr_cnt); @@ -11800,7 +11871,7 @@ return posix_error(); } } - return posix_error(); + return (!async_err) ? posix_error() : NULL; } goto done; @@ -11821,21 +11892,26 @@ return NULL; #ifdef linux if (offobj == Py_None) { + do { + Py_BEGIN_ALLOW_THREADS + ret = sendfile(out, in, NULL, count); + Py_END_ALLOW_THREADS + } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (ret < 0) + return (!async_err) ? posix_error() : NULL; + return Py_BuildValue("n", ret); + } +#endif + if (!Py_off_t_converter(offobj, &offset)) + return NULL; + + do { Py_BEGIN_ALLOW_THREADS - ret = sendfile(out, in, NULL, count); + ret = sendfile(out, in, &offset, count); Py_END_ALLOW_THREADS - if (ret < 0) - return posix_error(); - return Py_BuildValue("n", ret); - } -#endif - if (!Py_off_t_converter(offobj, &offset)) - return NULL; - Py_BEGIN_ALLOW_THREADS - ret = sendfile(out, in, &offset, count); - Py_END_ALLOW_THREADS + } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (ret < 0) - return posix_error(); + return (!async_err) ? posix_error() : NULL; return Py_BuildValue("n", ret); #endif } @@ -11891,15 +11967,18 @@ { STRUCT_STAT st; int res; - - Py_BEGIN_ALLOW_THREADS - res = FSTAT(fd, &st); - Py_END_ALLOW_THREADS + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = FSTAT(fd, &st); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (res != 0) { #ifdef MS_WINDOWS return PyErr_SetFromWindowsErr(0); #else - return posix_error(); + return (!async_err) ? posix_error() : NULL; #endif } @@ -12185,6 +12264,7 @@ { int cnt; Py_ssize_t result; + int async_err = 0; struct iovec *iov; Py_buffer *buf; @@ -12199,12 +12279,14 @@ return -1; } - Py_BEGIN_ALLOW_THREADS - result = writev(fd, iov, cnt); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + result = writev(fd, iov, cnt); + Py_END_ALLOW_THREADS + } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); iov_cleanup(iov, buf, cnt); - if (result < 0) + if (result < 0 && !async_err) posix_error(); return result; @@ -12275,17 +12357,20 @@ /*[clinic end generated code: output=ec9cc5b2238e96a7 input=19903f1b3dd26377]*/ { Py_ssize_t size; + int async_err = 0; if (!_PyVerify_fd(fd)) { posix_error(); return -1; } - Py_BEGIN_ALLOW_THREADS - size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset); - Py_END_ALLOW_THREADS - - if (size < 0) + do { + Py_BEGIN_ALLOW_THREADS + size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset); + Py_END_ALLOW_THREADS + } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (size < 0 && !async_err) posix_error(); return size; } @@ -12353,18 +12438,21 @@ /*[clinic end generated code: output=b3321927546893d0 input=73032e98a36e0e19]*/ { int result; - - Py_BEGIN_ALLOW_THREADS + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKFIFOAT - if (dir_fd != DEFAULT_DIR_FD) - result = mkfifoat(dir_fd, path->narrow, mode); - else -#endif - result = mkfifo(path->narrow, mode); - Py_END_ALLOW_THREADS - - if (result < 0) - return posix_error(); + if (dir_fd != DEFAULT_DIR_FD) + result = mkfifoat(dir_fd, path->narrow, mode); + else +#endif + result = mkfifo(path->narrow, mode); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } @@ -12448,18 +12536,21 @@ /*[clinic end generated code: output=f71d54eaf9bb6f1a input=ee44531551a4d83b]*/ { int result; - - Py_BEGIN_ALLOW_THREADS + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKNODAT - if (dir_fd != DEFAULT_DIR_FD) - result = mknodat(dir_fd, path->narrow, mode, device); - else -#endif - result = mknod(path->narrow, mode, device); - Py_END_ALLOW_THREADS - - if (result < 0) - return posix_error(); + if (dir_fd != DEFAULT_DIR_FD) + result = mknodat(dir_fd, path->narrow, mode, device); + else +#endif + result = mknod(path->narrow, mode, device); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } @@ -12662,12 +12753,16 @@ /*[clinic end generated code: output=62326766cb9b76bf input=63b43641e52818f2]*/ { int result; - - Py_BEGIN_ALLOW_THREADS - result = ftruncate(fd, length); - Py_END_ALLOW_THREADS - if (result < 0) - return posix_error(); + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + result = ftruncate(fd, length); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } #endif /* HAVE_FTRUNCATE */ @@ -12805,14 +12900,16 @@ /*[clinic end generated code: output=0cd702d2065c79db input=d7a2ef0ab2ca52fb]*/ { int result; - - Py_BEGIN_ALLOW_THREADS - result = posix_fallocate(fd, offset, length); - Py_END_ALLOW_THREADS - if (result != 0) { - errno = result; - return posix_error(); - } + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + result = posix_fallocate(fd, offset, length); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } #endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG */ @@ -12883,14 +12980,16 @@ /*[clinic end generated code: output=dad93f32c04dd4f7 input=0fbe554edc2f04b5]*/ { int result; - - Py_BEGIN_ALLOW_THREADS - result = posix_fadvise(fd, offset, length, advice); - Py_END_ALLOW_THREADS - if (result != 0) { - errno = result; - return posix_error(); - } + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + result = posix_fadvise(fd, offset, length, advice); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } #endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */ @@ -13745,13 +13844,17 @@ /*[clinic end generated code: output=0e32bf07f946ec0d input=d8122243ac50975e]*/ { int result; + int async_err = 0; struct statvfs st; - Py_BEGIN_ALLOW_THREADS - result = fstatvfs(fd, &st); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + result = fstatvfs(fd, &st); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); if (result != 0) - return posix_error(); + return (!async_err) ? posix_error() : NULL; return _pystatvfs_fromstructstatvfs(st); } diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2037,6 +2037,7 @@ PyObject *addr = NULL; PyObject *res = NULL; int timeout; + int async_err = 0; #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ static int accept4_works = -1; @@ -2050,27 +2051,27 @@ return select_error(); BEGIN_SELECT_LOOP(s) - - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 0, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 0, interval); + if (!timeout) { #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) - if (accept4_works != 0) { - newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, - SOCK_CLOEXEC); - if (newfd == INVALID_SOCKET && accept4_works == -1) { - /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ - accept4_works = (errno != ENOSYS); + if (accept4_works != 0) { + newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, + SOCK_CLOEXEC); + if (newfd == INVALID_SOCKET && accept4_works == -1) { + /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ + accept4_works = (errno != ENOSYS); + } } + if (accept4_works == 0) + newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); +#else + newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); +#endif } - if (accept4_works == 0) - newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); -#else - newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); -#endif - } - Py_END_ALLOW_THREADS - + Py_END_ALLOW_THREADS + } while (newfd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); return NULL; @@ -2078,7 +2079,7 @@ END_SELECT_LOOP(s) if (newfd == INVALID_SOCKET) - return s->errorhandler(); + return (!async_err) ? s->errorhandler() : NULL; #ifdef MS_WINDOWS if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) { @@ -2341,6 +2342,10 @@ { SOCKET_T fd; + /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/ + * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + * for more details. + */ if ((fd = s->sock_fd) != -1) { s->sock_fd = -1; Py_BEGIN_ALLOW_THREADS @@ -2513,10 +2518,8 @@ /* Signals are not errors (though they may raise exceptions). Adapted from PyErr_SetFromErrnoWithFilenameObject(). */ -#ifdef EINTR if (res == EINTR && PyErr_CheckSignals()) return NULL; -#endif return PyLong_FromLong((long) res); } @@ -2650,6 +2653,7 @@ { Py_ssize_t outlen = -1; int timeout; + int async_err = 0; if (!IS_SELECTABLE(s)) { select_error(); @@ -2661,18 +2665,20 @@ } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 0, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 0, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - outlen = recv(s->sock_fd, cbuf, (int)len, flags); + if (len > INT_MAX) + len = INT_MAX; + outlen = recv(s->sock_fd, cbuf, (int)len, flags); #else - outlen = recv(s->sock_fd, cbuf, len, flags); -#endif - } - Py_END_ALLOW_THREADS + outlen = recv(s->sock_fd, cbuf, len, flags); +#endif + } + Py_END_ALLOW_THREADS + } while (outlen < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); @@ -2682,7 +2688,8 @@ if (outlen < 0) { /* Note: the call to errorhandler() ALWAYS indirectly returned NULL, so ignore its return value */ - s->errorhandler(); + if (!async_err) + s->errorhandler(); return -1; } return outlen; @@ -2819,6 +2826,7 @@ int timeout; Py_ssize_t n = -1; socklen_t addrlen; + int async_err = 0; *addr = NULL; @@ -2831,21 +2839,23 @@ } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - memset(&addrbuf, 0, addrlen); - timeout = internal_select_ex(s, 0, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + memset(&addrbuf, 0, addrlen); + timeout = internal_select_ex(s, 0, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = recvfrom(s->sock_fd, cbuf, (int)len, flags, - (void *) &addrbuf, &addrlen); + if (len > INT_MAX) + len = INT_MAX; + n = recvfrom(s->sock_fd, cbuf, (int)len, flags, + (void *) &addrbuf, &addrlen); #else - n = recvfrom(s->sock_fd, cbuf, len, flags, - SAS2SA(&addrbuf), &addrlen); -#endif - } - Py_END_ALLOW_THREADS + n = recvfrom(s->sock_fd, cbuf, len, flags, + SAS2SA(&addrbuf), &addrlen); +#endif + } + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyErr_SetString(socket_timeout, "timed out"); @@ -2853,7 +2863,8 @@ } END_SELECT_LOOP(s) if (n < 0) { - s->errorhandler(); + if (!async_err) + s->errorhandler(); return -1; } @@ -2993,6 +3004,7 @@ { ssize_t bytes_received = -1; int timeout; + int async_err = 0; sock_addr_t addrbuf; socklen_t addrbuflen; struct msghdr msg = {0}; @@ -3028,25 +3040,29 @@ } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS; - msg.msg_name = SAS2SA(&addrbuf); - msg.msg_namelen = addrbuflen; - msg.msg_iov = iov; - msg.msg_iovlen = iovlen; - msg.msg_control = controlbuf; - msg.msg_controllen = controllen; - timeout = internal_select_ex(s, 0, interval); - if (!timeout) - bytes_received = recvmsg(s->sock_fd, &msg, flags); - Py_END_ALLOW_THREADS; - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); - goto finally; - } + do { + Py_BEGIN_ALLOW_THREADS; + msg.msg_name = SAS2SA(&addrbuf); + msg.msg_namelen = addrbuflen; + msg.msg_iov = iov; + msg.msg_iovlen = iovlen; + msg.msg_control = controlbuf; + msg.msg_controllen = controllen; + timeout = internal_select_ex(s, 0, interval); + if (!timeout) + bytes_received = recvmsg(s->sock_fd, &msg, flags); + Py_END_ALLOW_THREADS; + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + goto finally; + } + } while (bytes_received < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); END_SELECT_LOOP(s) if (bytes_received < 0) { - s->errorhandler(); + if (!async_err) + s->errorhandler(); goto finally; } @@ -3305,6 +3321,7 @@ { char *buf; Py_ssize_t len, n = -1; + int async_err = 0; int flags = 0, timeout; Py_buffer pbuf; @@ -3319,18 +3336,20 @@ len = pbuf.len; BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 1, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 1, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = send(s->sock_fd, buf, (int)len, flags); + if (len > INT_MAX) + len = INT_MAX; + n = send(s->sock_fd, buf, (int)len, flags); #else - n = send(s->sock_fd, buf, len, flags); -#endif - } - Py_END_ALLOW_THREADS + n = send(s->sock_fd, buf, len, flags); +#endif + } + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyBuffer_Release(&pbuf); PyErr_SetString(socket_timeout, "timed out"); @@ -3340,7 +3359,7 @@ PyBuffer_Release(&pbuf); if (n < 0) - return s->errorhandler(); + return (!async_err) ? s->errorhandler() : NULL; return PyLong_FromSsize_t(n); } @@ -3359,7 +3378,8 @@ { char *buf; Py_ssize_t len, n = -1; - int flags = 0, timeout, saved_errno; + int async_err = 0; + int flags = 0, timeout; Py_buffer pbuf; if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags)) @@ -3391,29 +3411,16 @@ PyErr_SetString(socket_timeout, "timed out"); return NULL; } - /* PyErr_CheckSignals() might change errno */ - saved_errno = errno; - /* We must run our signal handlers before looping again. - send() can return a successful partial write when it is - interrupted, so we can't restrict ourselves to EINTR. */ - if (PyErr_CheckSignals()) { - PyBuffer_Release(&pbuf); - return NULL; + if (n >= 0) { + buf += n; + len -= n; } - if (n < 0) { - /* If interrupted, try again */ - if (saved_errno == EINTR) - continue; - else - break; - } - buf += n; - len -= n; - } while (len > 0); + } while (len > 0 && (n >= 0 || errno == EINTR) && + !(async_err = PyErr_CheckSignals())); PyBuffer_Release(&pbuf); - if (n < 0) - return s->errorhandler(); + if (n < 0 || async_err) + return (!async_err) ? s->errorhandler() : NULL; Py_INCREF(Py_None); return Py_None; @@ -3439,6 +3446,7 @@ Py_ssize_t len, arglen; sock_addr_t addrbuf; int addrlen, n = -1, flags, timeout; + int async_err = 0; flags = 0; arglen = PyTuple_Size(args); @@ -3473,20 +3481,22 @@ } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS - timeout = internal_select_ex(s, 1, interval); - if (!timeout) { + do { + Py_BEGIN_ALLOW_THREADS + timeout = internal_select_ex(s, 1, interval); + if (!timeout) { #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = sendto(s->sock_fd, buf, (int)len, flags, - SAS2SA(&addrbuf), addrlen); + if (len > INT_MAX) + len = INT_MAX; + n = sendto(s->sock_fd, buf, (int)len, flags, + SAS2SA(&addrbuf), addrlen); #else - n = sendto(s->sock_fd, buf, len, flags, - SAS2SA(&addrbuf), addrlen); -#endif - } - Py_END_ALLOW_THREADS + n = sendto(s->sock_fd, buf, len, flags, + SAS2SA(&addrbuf), addrlen); +#endif + } + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (timeout == 1) { PyBuffer_Release(&pbuf); @@ -3496,7 +3506,7 @@ END_SELECT_LOOP(s) PyBuffer_Release(&pbuf); if (n < 0) - return s->errorhandler(); + return (!async_err) ? s->errorhandler() : NULL; return PyLong_FromSsize_t(n); } @@ -3528,6 +3538,7 @@ void *controlbuf = NULL; size_t controllen, controllen_last; ssize_t bytes_sent = -1; + int async_err = 0; int addrlen, timeout, flags = 0; PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL, *data_fast = NULL, *cmsg_fast = NULL, *retval = NULL; @@ -3685,19 +3696,23 @@ } BEGIN_SELECT_LOOP(s) - Py_BEGIN_ALLOW_THREADS; - timeout = internal_select_ex(s, 1, interval); - if (!timeout) - bytes_sent = sendmsg(s->sock_fd, &msg, flags); - Py_END_ALLOW_THREADS; - if (timeout == 1) { - PyErr_SetString(socket_timeout, "timed out"); - goto finally; - } + do { + Py_BEGIN_ALLOW_THREADS; + timeout = internal_select_ex(s, 1, interval); + if (!timeout) + bytes_sent = sendmsg(s->sock_fd, &msg, flags); + Py_END_ALLOW_THREADS; + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + goto finally; + } + } while (bytes_sent < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); END_SELECT_LOOP(s) if (bytes_sent < 0) { - s->errorhandler(); + if (!async_err) + s->errorhandler(); goto finally; } retval = PyLong_FromSsize_t(bytes_sent); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 00:43:08 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 07 Feb 2015 23:43:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Adds_automated_test_script?= =?utf-8?q?_for_the_Windows_installer_and_fixes_download_URL?= Message-ID: <20150207234308.52864.48614@psf.io> https://hg.python.org/cpython/rev/45ba5de2711b changeset: 94554:45ba5de2711b user: Steve Dower date: Sat Feb 07 15:42:53 2015 -0800 summary: Adds automated test script for the Windows installer and fixes download URL files: Tools/msi/buildrelease.bat | 6 + Tools/msi/bundle/bundle.targets | 2 +- Tools/msi/get_wix.py | 2 +- Tools/msi/testrelease.bat | 80 +++++++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -22,6 +22,7 @@ set BUILDX86= set BUILDX64= set TARGET=Rebuild +set TESTTARGETDIR= :CheckOpts @@ -30,6 +31,7 @@ if "%1" EQU "-D" (set SKIPDOC=1) && shift && goto CheckOpts if "%1" EQU "-B" (set SKIPBUILD=1) && shift && goto CheckOpts if "%1" EQU "--download" (set DOWNLOAD_URL=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--test" (set TESTTARGETDIR=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-b" (set TARGET=Build) && shift && goto CheckOpts if '%1' EQU '-x86' (set BUILDX86=1) && shift && goto CheckOpts if '%1' EQU '-x64' (set BUILDX64=1) && shift && goto CheckOpts @@ -66,6 +68,10 @@ if errorlevel 1 exit /B ) +if defined TESTTARGETDIR ( + call "%D%testrelease.bat" -t "%TESTTARGETDIR%" +) + exit /B 0 :build diff --git a/Tools/msi/bundle/bundle.targets b/Tools/msi/bundle/bundle.targets --- a/Tools/msi/bundle/bundle.targets +++ b/Tools/msi/bundle/bundle.targets @@ -14,7 +14,7 @@ $(OutputPath)en-us\ $(OutputPath) - $(DownloadUrlBase.TrimEnd(`/`))/$(PythonVersion)/$(ArchName)/{2} + $(DownloadUrlBase.TrimEnd(`/`))/$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)/$(ArchName)$(ReleaseLevelName)/{2} $(DefineConstants);DownloadUrl=$(DownloadUrl) $(DefineConstants);DownloadUrl={2} diff --git a/Tools/msi/get_wix.py b/Tools/msi/get_wix.py --- a/Tools/msi/get_wix.py +++ b/Tools/msi/get_wix.py @@ -22,7 +22,7 @@ print("Cannot find project root") sys.exit(1) -WIX_BINARIES_ZIP = 'http://wixtoolset.org/downloads/v3.10.1124.0/wix310-binaries.zip' +WIX_BINARIES_ZIP = 'http://wixtoolset.org/downloads/v3.10.0.1403/wix310-binaries.zip' TARGET_BIN_ZIP = EXTERNALS_DIR / "wix.zip" TARGET_BIN_DIR = EXTERNALS_DIR / "wix" diff --git a/Tools/msi/testrelease.bat b/Tools/msi/testrelease.bat new file mode 100644 --- /dev/null +++ b/Tools/msi/testrelease.bat @@ -0,0 +1,80 @@ + at setlocal + at echo off + +set D=%~dp0 +set PCBUILD=%D%..\..\PCBuild\ + +set TARGETDIR=%TEMP% +set TESTX86= +set TESTX64= +set TESTALLUSER= +set TESTPERUSER= + +:CheckOpts +if '%1' EQU '-x86' (set TESTX86=1) && shift && goto CheckOpts +if '%1' EQU '-x64' (set TESTX64=1) && shift && goto CheckOpts +if '%1' EQU '-t' (set TARGETDIR=%~2) && shift && shift && goto CheckOpts +if '%1' EQU '-a' (set TESTALLUSER=1) && shift && goto CheckOpts +if '%1' EQU '-p' (set TESTPERUSER=1) && shift && goto CheckOpts + +if not defined TESTX86 if not defined TESTX64 (set TESTX86=1) && (set TESTX64=1) +if not defined TESTALLUSER if not defined TESTPERUSER (set TESTALLUSER=1) && (set TESTPERUSER=1) + + +if defined TESTX86 ( + for %%f in ("%PCBUILD%win32\en-us\*.exe") do ( + if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" InstallAllUsers=1 + if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" InstallAllUsers=0 + if errorlevel 1 exit /B + ) +) + +if defined TESTX64 ( + for %%f in ("%PCBUILD%amd64\en-us\*.exe") do ( + if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" InstallAllUsers=1 + if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" InstallAllUsers=0 + if errorlevel 1 exit /B + ) +) + +exit /B 0 + +:test + at setlocal + at echo on + + at if not exist "%~1" exit /B 1 + + at set EXITCODE=0 + at echo Installing %1 into %2 +"%~1" /passive /log "%~2\install\log.txt" %~3 TargetDir="%~2\Python" Include_debug=1 Include_symbols=1 CompileAll=1 + + at if not errorlevel 1 ( + @echo Printing version + "%~2\Python\python.exe" -c "import sys; print(sys.version)" > "%~2\version.txt" 2>&1 +) + at if not errorlevel 1 ( + @echo Installing package + "%~2\Python\python.exe" -m pip install azure > "%~2\pip.txt" 2>&1 + @if not errorlevel 1 ( + "%~2\Python\python.exe" -m pip uninstall -y azure python-dateutil six > "%~2\pip.txt" 2>&1 + ) +) + at if not errorlevel 1 ( + @echo Testing Tcl/tk + @set TCL_LIBRARY=%~2\Python\tcl\tcl8.6 + "%~2\Python\python.exe" -m test -uall -v test_ttk_guionly test_tk test_idle > "%~2\tcltk.txt" 2>&1 + @set TCL_LIBRARY= +) + + at set EXITCODE=%ERRORLEVEL% + + at for /d %%f in ("%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Python*") do @dir "%%~ff\*.lnk" /s/b > "%~2\startmenu.txt" 2>&1 + at for /d %%f in ("%APPDATA%\Microsoft\Windows\Start Menu\Programs\Python*") do @dir "%%~ff\*.lnk" /s/b >> "%~2\startmenu.txt" 2>&1 + + at echo Result was %EXITCODE% + at echo Removing %1 +"%~1" /passive /uninstall /log "%~2\uninstall\log.txt" + + at echo off +exit /B %EXITCODE% -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 05:49:27 2015 From: python-checkins at python.org (ned.deily) Date: Sun, 08 Feb 2015 04:49:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323285=3A_Install_?= =?utf-8?q?new_test_directory=2E?= Message-ID: <20150208044927.52864.8360@psf.io> https://hg.python.org/cpython/rev/000bbdf0ea76 changeset: 94555:000bbdf0ea76 user: Ned Deily date: Sun Feb 08 15:48:40 2015 +1100 summary: Issue #23285: Install new test directory. files: Makefile.pre.in | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1143,6 +1143,7 @@ test/audiodata \ test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata \ + test/eintrdata \ test/imghdrdata \ test/subprocessdata test/sndhdrdata test/support \ test/tracedmodules test/encoded_modules \ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 07:21:05 2015 From: python-checkins at python.org (steve.dower) Date: Sun, 08 Feb 2015 06:21:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Improve_Windows_release_sc?= =?utf-8?q?ripts?= Message-ID: <20150208062104.108387.28360@psf.io> https://hg.python.org/cpython/rev/5ea093a41198 changeset: 94556:5ea093a41198 user: Steve Dower date: Sat Feb 07 22:20:48 2015 -0800 summary: Improve Windows release scripts files: Doc/make.bat | 18 ++++-- Tools/msi/buildrelease.bat | 51 +++++++++++++++----- Tools/msi/bundle/bundle.targets | 4 +- Tools/msi/msi.props | 1 - Tools/msi/testrelease.bat | 42 ++++++++++++---- 5 files changed, 81 insertions(+), 35 deletions(-) diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -8,13 +8,17 @@ if "%SPHINXBUILD%" EQU "" set SPHINXBUILD=sphinx-build if "%PYTHON%" EQU "" set PYTHON=py -if "%HTMLHELP%" EQU "" ( - where hhc 2>nul >"%TEMP%\hhc.loc" - if errorlevel 1 dir "..\externals\hhc.exe" /s/b > "%TEMP%\hhc.loc" - if errorlevel 1 echo Cannot find HHC on PATH or in externals & exit /B 1 - set /P HTMLHELP= < "%TEMP%\hhc.loc" - del "%TEMP%\hhc.loc" -) +if "%1" NEQ "htmlhelp" goto :skiphhcsearch +if exist "%HTMLHELP%" goto :skiphhcsearch + +rem Search for HHC in likely places +set HTMLHELP= +where hhc /q && set HTMLHELP=hhc && goto :skiphhcsearch +where /R ..\externals hhc > "%TEMP%\hhc.loc" 2> nul && set /P HTMLHELP= < "%TEMP%\hhc.loc" & del "%TEMP%\hhc.loc" +if not exist "%HTMLHELP%" where /R "%ProgramFiles(x86)%" hhc > "%TEMP%\hhc.loc" 2> nul && set /P HTMLHELP= < "%TEMP%\hhc.loc" & del "%TEMP%\hhc.loc" +if not exist "%HTMLHELP%" where /R "%ProgramFiles%" hhc > "%TEMP%\hhc.loc" 2> nul && set /P HTMLHELP= < "%TEMP%\hhc.loc" & del "%TEMP%\hhc.loc" +if not exist "%HTMLHELP%" echo Cannot find HHC on PATH or in externals & exit /B 1 +:skiphhcsearch if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/extensions/patchlevel.py`) do set DISTVERSION=%%v diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -26,15 +26,21 @@ :CheckOpts +if "%1" EQU "-h" goto Help if "%1" EQU "-c" (set CERTNAME=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--certificate" (set CERTNAME=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-o" (set OUTDIR=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--out" (set OUTDIR=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-D" (set SKIPDOC=1) && shift && goto CheckOpts +if "%1" EQU "--skip-doc" (set SKIPDOC=1) && shift && goto CheckOpts if "%1" EQU "-B" (set SKIPBUILD=1) && shift && goto CheckOpts +if "%1" EQU "--skip-build" (set SKIPBUILD=1) && shift && goto CheckOpts if "%1" EQU "--download" (set DOWNLOAD_URL=%~2) && shift && shift && goto CheckOpts if "%1" EQU "--test" (set TESTTARGETDIR=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-b" (set TARGET=Build) && shift && goto CheckOpts -if '%1' EQU '-x86' (set BUILDX86=1) && shift && goto CheckOpts -if '%1' EQU '-x64' (set BUILDX64=1) && shift && goto CheckOpts +if "%1" EQU "--build" (set TARGET=Build) && shift && goto CheckOpts +if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) @@ -42,21 +48,21 @@ if "%SKIPBUILD%" EQU "1" goto skipdoc if "%SKIPDOC%" EQU "1" goto skipdoc +if not defined PYTHON where py -q || echo Cannot find py on path and PYTHON is not set. && exit /B 1 +if not defined SPHINXBUILD where sphinx-build -q || echo Cannot find sphinx-build on path and SPHINXBUILD is not set. && exit /B 1 call "%D%..\..\doc\make.bat" htmlhelp if errorlevel 1 goto :eof :skipdoc -where hg >nul 2>nul -if errorlevel 1 echo Cannot find hg on PATH & exit /B 1 +where hg /q || echo Cannot find Mercurial on PATH && exit /B 1 -where dlltool 2>nul >"%TEMP%\dlltool.loc" -if errorlevel 1 dir "%D%..\..\externals\dlltool.exe" /s/b > "%TEMP%\dlltool.loc" -if errorlevel 1 echo Cannot find binutils on PATH or in externals & exit /B 1 -set /P DLLTOOL= < "%TEMP%\dlltool.loc" -set PATH=%PATH%;%DLLTOOL:~,-12% -set DLLTOOL= -del "%TEMP%\dlltool.loc" - +where dlltool /q && goto skipdlltoolsearch +set _DLLTOOL_PATH= +where /R "%D%..\..\externals" dlltool > "%TEMP%\dlltool.loc" 2> nul && set /P _DLLTOOL_PATH= < "%TEMP%\dlltool.loc" & del "%TEMP%\dlltool.loc" +if not exist "%_DLLTOOL_PATH%" echo Cannot find binutils on PATH or in external && exit /B 1 +for %%f in (%_DLLTOOL_PATH%) do set PATH=%PATH%;%%~dpf +set _DLLTOOL_PATH= +:skipdlltoolsearch if defined BUILDX86 ( call :build x86 @@ -94,14 +100,12 @@ set RELEASE_URI=%RELEASE_URI_X64% ) -echo on if exist "%BUILD%en-us" ( echo Deleting %BUILD%en-us rmdir /q/s "%BUILD%en-us" if errorlevel 1 exit /B ) -echo on if exist "%D%obj\Release_%OBJDIR_PLAT%" ( echo Deleting "%D%obj\Release_%OBJDIR_PLAT%" rmdir /q/s "%D%obj\Release_%OBJDIR_PLAT%" @@ -138,3 +142,22 @@ copy /Y "%BUILD%en-us\*.msi" "%OUTDIR%\%OUTDIR_PLAT%" ) +exit /B 0 + +:Help +echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--skip-build] +echo [--skip-doc] [--download DOWNLOAD URL] [--test TARGETDIR] [-h] +echo. +echo --out (-o) Specify an additional output directory for installers +echo -x86 Build x86 installers +echo -x64 Build x64 installers +echo --build (-b) Incrementally build Python rather than rebuilding +echo --skip-build (-B) Do not build Python (just do the installers) +echo --skip-doc (-D) Do not build documentation +echo --download Specify the full download URL for MSIs (should include {2}) +echo --test Specify the test directory to run the installer tests +echo -h Display this help information +echo. +echo If no architecture is specified, all architectures will be built. +echo If --test is not specified, the installer tests are not run. +echo. \ No newline at end of file diff --git a/Tools/msi/bundle/bundle.targets b/Tools/msi/bundle/bundle.targets --- a/Tools/msi/bundle/bundle.targets +++ b/Tools/msi/bundle/bundle.targets @@ -14,8 +14,8 @@ $(OutputPath)en-us\ $(OutputPath) - $(DownloadUrlBase.TrimEnd(`/`))/$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)/$(ArchName)$(ReleaseLevelName)/{2} - $(DefineConstants);DownloadUrl=$(DownloadUrl) + $(DownloadUrlBase.TrimEnd(`/`))/$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)/$(ArchName)$(ReleaseLevelName)/ + $(DefineConstants);DownloadUrl=$(DownloadUrl){2} $(DefineConstants);DownloadUrl={2} diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props --- a/Tools/msi/msi.props +++ b/Tools/msi/msi.props @@ -69,7 +69,6 @@ MajorVersionNumber=$(MajorVersionNumber); MinorVersionNumber=$(MinorVersionNumber); UpgradeMinimumVersion=$(MajorVersionNumber).$(MinorVersionNumber).0.0; - UpgradeMaximumVersion=$(MajorVersionNumber).$(MinorVersionNumber).150.0; NextMajorVersionNumber=$(MajorVersionNumber).$([msbuild]::Add($(MinorVersionNumber), 1)).0.0; PyDebugExt=$(PyDebugExt); diff --git a/Tools/msi/testrelease.bat b/Tools/msi/testrelease.bat --- a/Tools/msi/testrelease.bat +++ b/Tools/msi/testrelease.bat @@ -11,11 +11,15 @@ set TESTPERUSER= :CheckOpts -if '%1' EQU '-x86' (set TESTX86=1) && shift && goto CheckOpts -if '%1' EQU '-x64' (set TESTX64=1) && shift && goto CheckOpts -if '%1' EQU '-t' (set TARGETDIR=%~2) && shift && shift && goto CheckOpts -if '%1' EQU '-a' (set TESTALLUSER=1) && shift && goto CheckOpts -if '%1' EQU '-p' (set TESTPERUSER=1) && shift && goto CheckOpts +if "%1" EQU "-h" goto Help +if "%1" EQU "-x86" (set TESTX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set TESTX64=1) && shift && goto CheckOpts +if "%1" EQU "-t" (set TARGETDIR=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--target" (set TARGETDIR=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "-a" (set TESTALLUSER=1) && shift && goto CheckOpts +if "%1" EQU "--alluser" (set TESTALLUSER=1) && shift && goto CheckOpts +if "%1" EQU "-p" (set TESTPERUSER=1) && shift && goto CheckOpts +if "%1" EQU "--peruser" (set TESTPERUSER=1) && shift && goto CheckOpts if not defined TESTX86 if not defined TESTX64 (set TESTX86=1) && (set TESTX64=1) if not defined TESTALLUSER if not defined TESTPERUSER (set TESTALLUSER=1) && (set TESTPERUSER=1) @@ -23,16 +27,18 @@ if defined TESTX86 ( for %%f in ("%PCBUILD%win32\en-us\*.exe") do ( - if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" InstallAllUsers=1 - if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" InstallAllUsers=0 + if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" "InstallAllUsers=1 CompileAll=1" + if errorlevel 1 exit /B + if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" "InstallAllUsers=0 CompileAll=0" if errorlevel 1 exit /B ) ) if defined TESTX64 ( for %%f in ("%PCBUILD%amd64\en-us\*.exe") do ( - if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" InstallAllUsers=1 - if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" InstallAllUsers=0 + if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" "InstallAllUsers=1 CompileAll=1" + if errorlevel 1 exit /B + if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" "InstallAllUsers=0 CompileAll=0" if errorlevel 1 exit /B ) ) @@ -47,7 +53,7 @@ @set EXITCODE=0 @echo Installing %1 into %2 -"%~1" /passive /log "%~2\install\log.txt" %~3 TargetDir="%~2\Python" Include_debug=1 Include_symbols=1 CompileAll=1 +"%~1" /passive /log "%~2\install\log.txt" TargetDir="%~2\Python" Include_debug=1 Include_symbols=1 %~3 @if not errorlevel 1 ( @echo Printing version @@ -57,7 +63,7 @@ @echo Installing package "%~2\Python\python.exe" -m pip install azure > "%~2\pip.txt" 2>&1 @if not errorlevel 1 ( - "%~2\Python\python.exe" -m pip uninstall -y azure python-dateutil six > "%~2\pip.txt" 2>&1 + "%~2\Python\python.exe" -m pip uninstall -y azure python-dateutil six >> "%~2\pip.txt" 2>&1 ) ) @if not errorlevel 1 ( @@ -78,3 +84,17 @@ @echo off exit /B %EXITCODE% + +:Help +echo testrelease.bat [--target TARGET] [-x86] [-x64] [--alluser] [--peruser] [-h] +echo. +echo --target (-t) Specify the target directory for installs and logs +echo -x86 Run tests for x86 installers +echo -x64 Run tests for x64 installers +echo --alluser (-a) Run tests for all-user installs (requires Administrator) +echo --peruser (-p) Run tests for per-user installs +echo -h Display this help information +echo. +echo If no test architecture is specified, all architectures will be tested. +echo If no install type is selected, all install types will be tested. +echo. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Feb 8 09:29:17 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 08 Feb 2015 09:29:17 +0100 Subject: [Python-checkins] Daily reference leaks (45ba5de2711b): sum=3 Message-ID: results for 45ba5de2711b on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogY01v60', '-x'] From python-checkins at python.org Sun Feb 8 23:05:42 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:05:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Updated_pydoc_?= =?utf-8?q?topics_data_for_3=2E4=2E3rc1_release=2E?= Message-ID: <20150208220542.69895.28622@psf.io> https://hg.python.org/cpython/rev/e2e588cda101 changeset: 94557:e2e588cda101 branch: 3.4 parent: 94550:c5f62f8d053e user: Larry Hastings date: Sat Feb 07 15:55:23 2015 -0800 summary: Updated pydoc topics data for 3.4.3rc1 release. files: Lib/pydoc_data/topics.py | 156 +++++++++++++------------- 1 files changed, 78 insertions(+), 78 deletions(-) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,79 +1,79 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sun Oct 5 19:01:41 2014 -topics = {'assert': '\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', - 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for\n*attributeref*, *subscription*, and *slicing*.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the target\n sequence allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nAlthough the definition of assignment implies that overlaps between\nthe left-hand side and the right-hand side are \'simultanenous\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables occur left-to-right, sometimes\nresulting in confusion. For instance, the following program prints\n"[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2 # i is updated, then x[i] is updated\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', - 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n', - 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\nThe attribute "__objclass__" is interpreted by the "inspect" module as\nspecifying the class where this object was defined (setting this\nappropriately can assist in runtime introspection of dynamic class\nattributes). For callables, it may indicate that an instance of the\ngiven type (or a subclass) is expected or required as the first\npositional argument (for example, CPython sets this attribute for\nunbound methods that are implemented in C).\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', - 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier. This\nproduction can be customized by overriding the "__getattr__()" method.\nIf this attribute is not available, the exception "AttributeError" is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', - 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', - 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe "*" (multiplication) operator yields the product of its arguments.\nThe arguments must either both be numbers, or one argument must be an\ninteger and the other must be a sequence. In the former case, the\nnumbers are converted to a common type and then multiplied together.\nIn the latter case, sequence repetition is performed; a negative\nrepetition factor yields an empty sequence.\n\nThe "/" (division) and "//" (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Division of integers yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the "ZeroDivisionError" exception.\n\nThe "%" (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n"ZeroDivisionError" exception. The arguments may be floating point\nnumbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals "4*0.7 +\n0.34".) The modulo operator always yields a result with the same sign\nas its second operand (or zero); the absolute value of the result is\nstrictly smaller than the absolute value of the second operand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: "x == (x//y)*y + (x%y)". Floor division and modulo are also\nconnected with the built-in function "divmod()": "divmod(x, y) ==\n(x//y, x%y)". [2].\n\nIn addition to performing the modulo operation on numbers, the "%"\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *printf-style String Formatting*.\n\nThe floor division operator, the modulo operator, and the "divmod()"\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the "abs()" function if appropriate.\n\nThe "+" (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both be sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe "-" (subtraction) operator yields the difference of its arguments.\nThe numeric arguments are first converted to a common type.\n', - 'bitwise': '\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe "&" operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe "^" operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe "|" operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', - 'bltin-code-objects': '\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin "compile()" function and can be extracted from function objects\nthrough their "__code__" attribute. See also the "code" module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the "exec()" or "eval()" built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', - 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the\n"Ellipsis" singleton.\n\nIt is written as "Ellipsis" or "...".\n', - 'bltin-null-object': '\nThe Null Object\n***************\n\nThis object is returned by functions that don\'t explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named "None" (a built-in name). "type(None)()" produces the\nsame singleton.\n\nIt is written as "None".\n', - 'bltin-type-objects': '\nType Objects\n************\n\nType objects represent the various object types. An object\'s type is\naccessed by the built-in function "type()". There are no special\noperations on types. The standard module "types" defines names for\nall standard built-in types.\n\nTypes are written like this: "".\n', - 'booleans': '\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: "False", "None", numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a "__bool__()" method.\n\nThe operator "not" yields "True" if its argument is false, "False"\notherwise.\n\nThe expression "x and y" first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression "x or y" first evaluates *x*; if *x* is true, its value\nis returned; otherwise, *y* is evaluated and the resulting value is\nreturned.\n\n(Note that neither "and" nor "or" restrict the value and type they\nreturn to "False" and "True", but rather return the last evaluated\nargument. This is sometimes useful, e.g., if "s" is a string that\nshould be replaced by a default value if it is empty, the expression\n"s or \'foo\'" yields the desired value. Because "not" has to create a\nnew value, it returns a boolean value regardless of the type of its\nargument (for example, "not \'foo\'" produces "False" rather than "\'\'".)\n', - 'break': '\nThe "break" statement\n*********************\n\n break_stmt ::= "break"\n\n"break" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition within that\nloop.\n\nIt terminates the nearest enclosing loop, skipping the optional "else"\nclause if the loop has one.\n\nIf a "for" loop is terminated by "break", the loop control target\nkeeps its current value.\n\nWhen "break" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nloop.\n', - 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n', - 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a *function*) with a possibly\nempty series of *arguments*:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nAn optional trailing comma may be present after the positional and\nkeyword arguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n"__call__()" method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal *parameter* lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a "TypeError" exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is "None", it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a "TypeError"\nexception is raised. Otherwise, the list of filled slots is used as\nthe argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use "PyArg_ParseTuple()" to parse\ntheir arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "*identifier" is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "**identifier" is present; in this case, that formal\nparameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax "*expression" appears in the function call, "expression"\nmust evaluate to an iterable. Elements from this iterable are treated\nas if they were additional positional arguments; if there are\npositional arguments *x1*, ..., *xN*, and "expression" evaluates to a\nsequence *y1*, ..., *yM*, this is equivalent to a call with M+N\npositional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the "*expression" syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the "**expression" argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the "*expression" syntax\nto be used in the same call, so in practice this confusion does not\narise.\n\nIf the syntax "**expression" appears in the function call,\n"expression" must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both "expression" and as an explicit keyword argument, a\n"TypeError" exception is raised.\n\nFormal parameters using the syntax "*identifier" or "**identifier"\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly "None", unless it raises an\nexception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a "return"\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a "__call__()" method; the effect is then the\n same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', - 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe "if", "while" and "for" statements implement traditional control\nflow constructs. "try" specifies exception handlers and/or cleanup\ncode for a group of statements, while the "with" statement allows the\nexecution of initialization and finalization code around a block of\ncode. Function and class definitions are also syntactically compound\nstatements.\n\nA compound statement consists of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of a suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which "if" clause a following "else" clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n"print()" calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a "NEWLINE" possibly followed by a\n"DEDENT". Also note that optional continuation clauses always begin\nwith a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling "else"\' problem is solved in Python by\nrequiring nested "if" statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe "if" statement\n==================\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n\n\nThe "while" statement\n=====================\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n\n\nThe "for" statement\n===================\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe "try" statement\n===================\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe "with" statement\n====================\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', - 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', - 'continue': '\nThe "continue" statement\n************************\n\n continue_stmt ::= "continue"\n\n"continue" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition or "finally"\nclause within that loop. It continues with the next cycle of the\nnearest enclosing loop.\n\nWhen "continue" passes control out of a "try" statement with a\n"finally" clause, that "finally" clause is executed before really\nstarting the next loop cycle.\n', - 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works as follows:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the\n other is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string as a\nleft argument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', - 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])". As a special constraint on\n constructors, no value may be returned; doing so will cause a\n "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing "None" in\n "sys.last_traceback". Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n "gc" module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\n Changed in version 3.4: The __format__ method of "object" itself\n raises a "TypeError" if passed any non-empty string.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n', - 'debugger': '\n"pdb" --- The Python Debugger\n*****************************\n\nThe module "pdb" defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n"Pdb". This is currently undocumented but easily understood by reading\nthe source. The extension interface uses the modules "bdb" and "cmd".\n\nThe debugger\'s prompt is "(Pdb)". Typical usage to run a program under\ncontrol of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\nChanged in version 3.3: Tab-completion via the "readline" module is\navailable for commands and command arguments, e.g. the current global\nand local names are offered as arguments of the "p" command.\n\n"pdb.py" can also be invoked as a script to debug other scripts. For\nexample:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: "pdb.py" now accepts a "-c" option that executes\ncommands as if given in a ".pdbrc" file, see *Debugger Commands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the "continue" command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type "continue", or you can\n step through the statement using "step" or "next" (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module "__main__" is used. (See the\n explanation of the built-in "exec()" or "eval()" functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When "runeval()" returns, it returns the\n value of the expression. Otherwise this function is similar to\n "run()".\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When "runcall()" returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n "sys.last_traceback".\n\nThe "run*" functions and "set_trace()" are aliases for instantiating\nthe "Pdb" class and calling the method of the same name. If you want\nto access further features, you have to do this yourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n "Pdb" is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying "cmd.Cmd" class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n "continue" command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n"h(elp)" means that either "h" or "help" can be used to enter the help\ncommand (but not "he" or "hel", nor "H" or "Help" or "HELP").\nArguments to commands must be separated by whitespace (spaces or\ntabs). Optional arguments are enclosed in square brackets ("[]") in\nthe command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n("|").\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a "list" command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint ("!"). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by ";;".\n(A single ";" is not used as it is the separator for multiple commands\nin a line that is passed to the Python parser.) No intelligence is\napplied to separating the commands; the input is split at the first\n";;" pair, even if it is in the middle of a quoted string.\n\nIf a file ".pdbrc" exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ".pdbrc" can now contain commands that\ncontinue debugging, such as "continue" or "next". Previously, these\ncommands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. "help pdb"\n displays the full documentation (the docstring of the "pdb"\n module). Since the *command* argument must be an identifier, "help\n exec" must be entered to get help on the "!" command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on "sys.path". Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for "break".\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just "end" to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) p some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with "end"; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between "next" and "step"\n is that "step" stops inside a called function, while "next"\n executes called functions at (nearly) full speed, only stopping at\n the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a "for" loop or out\n of a "finally" clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With "." as argument, list 11 lines around the current line. With\n one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by "->". If an\n exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ">>", if it differs\n from the current line.\n\n New in version 3.2: The ">>" marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for "list".\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\n Note: "print()" can also be used, but is not a debugger command\n --- this executes the Python "print()" function.\n\npp expression\n\n Like the "p" command, except the value of the expression is pretty-\n printed using the "pprint" module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the "code" module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by "%1", "%2", and so on, while "%*" is replaced by all\n the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ".pdbrc" file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n "global" statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with "shlex" and the result is used as the new\n "sys.argv". History, breakpoints, actions and debugger options are\n preserved. "restart" is an alias for "run".\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module\n is determined by the "__name__" in the frame globals.\n', - 'del': '\nThe "del" statement\n*******************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a "global"\nstatement in the same code block. If the name is unbound, a\n"NameError" exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2: Previously it was illegal to delete a name\nfrom the local namespace if it occurs as a free variable in a nested\nblock.\n', - 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', - 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', - 'else': '\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', - 'exceptions': '\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', - 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\nas a command line argument to the interpreter) is a code block. A\nscript command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, an\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\nglobal statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', - 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: "()".)\n', - 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, "077e010" is legal, and denotes the same number\nas "77e10". The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator "-" and the\nliteral "1".\n', - 'for': '\nThe "for" statement\n*******************\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', - 'formatstrings': '\nFormat String Syntax\n********************\n\nThe "str.format()" method and the "Formatter" class share the same\nsyntax for format strings (although in the case of "Formatter",\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n"{}". Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n"{{" and "}}".\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point "\'!\'", and a *format_spec*, which is\npreceded by a colon "\':\'". These specify a non-default format for the\nreplacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings "\'10\'" or\n"\':-]\'") within a format string. The *arg_name* can be followed by any\nnumber of index or attribute expressions. An expression of the form\n"\'.name\'" selects the named attribute using "getattr()", while an\nexpression of the form "\'[index]\'" does an index lookup using\n"__getitem__()".\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so "\'{} {}\'" is equivalent to "\'{0} {1}\'".\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the "__format__()"\nmethod of the value itself. However, in some cases it is desirable to\nforce a type to be formatted as a string, overriding its own\ndefinition of formatting. By converting the value to a string before\ncalling "__format__()", the normal formatting logic is bypassed.\n\nThree conversion flags are currently supported: "\'!s\'" which calls\n"str()" on the value, "\'!r\'" which calls "repr()" and "\'!a\'" which\ncalls "ascii()".\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in "format()" function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string ("""") produces\nthe same result as if you had called "str()" on the value. A non-empty\nformat string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nIf a valid *align* value is specified, it can be preceded by a *fill*\ncharacter that can be any character and defaults to a space if\nomitted. Note that it is not possible to use "{" and "}" as *fill*\nchar while using the "str.format()" method; this limitation however\ndoesn\'t affect the "format()" function.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'<\'" | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | "\'>\'" | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | "\'=\'" | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | "\'^\'" | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'+\'" | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | "\'-\'" | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe "\'#\'" option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective "\'0b\'", "\'0o\'", or\n"\'0x\'" to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for "\'g\'" and "\'G\'"\nconversions, trailing zeros are not removed from the result.\n\nThe "\',\'" option signals the use of a comma for a thousands separator.\nFor a locale aware separator, use the "\'n\'" integer presentation type\ninstead.\n\nChanged in version 3.1: Added the "\',\'" option (see also **PEP 378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nPreceding the *width* field by a zero ("\'0\'") character enables sign-\naware zero-padding for numeric types. This is equivalent to a *fill*\ncharacter of "\'0\'" with an *alignment* type of "\'=\'".\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with "\'f\'" and "\'F\'", or before and after the decimal point\nfor a floating point value formatted with "\'g\'" or "\'G\'". For non-\nnumber types the field indicates the maximum field size - in other\nwords, how many characters will be used from the field content. The\n*precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'s\'" | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'s\'". |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'b\'" | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | "\'c\'" | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | "\'d\'" | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | "\'o\'" | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | "\'x\'" | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | "\'X\'" | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'d\'", except that it uses the |\n | | current locale setting to insert the appropriate number |\n | | separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'d\'". |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except "\'n\'"\nand None). When doing so, "float()" is used to convert the integer to\na floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'e\'" | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n | | The default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'E\'" | Exponent notation. Same as "\'e\'" except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | "\'f\'" | Fixed point. Displays the number as a fixed-point number. |\n | | The default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'F\'" | Fixed point. Same as "\'f\'", but converts "nan" to "NAN" |\n | | and "inf" to "INF". |\n +-----------+------------------------------------------------------------+\n | "\'g\'" | General format. For a given precision "p >= 1", this |\n | | rounds the number to "p" significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type "\'e\'" and precision "p-1" |\n | | would have exponent "exp". Then if "-4 <= exp < p", the |\n | | number is formatted with presentation type "\'f\'" and |\n | | precision "p-1-exp". Otherwise, the number is formatted |\n | | with presentation type "\'e\'" and precision "p-1". In both |\n | | cases insignificant trailing zeros are removed from the |\n | | significand, and the decimal point is also removed if |\n | | there are no remaining digits following it. Positive and |\n | | negative infinity, positive and negative zero, and nans, |\n | | are formatted as "inf", "-inf", "0", "-0" and "nan" |\n | | respectively, regardless of the precision. A precision of |\n | | "0" is treated as equivalent to a precision of "1". The |\n | | default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'G\'" | General format. Same as "\'g\'" except switches to "\'E\'" if |\n | | the number gets too large. The representations of infinity |\n | | and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'g\'", except that it uses the |\n | | current locale setting to insert the appropriate number |\n | | separator characters. |\n +-----------+------------------------------------------------------------+\n | "\'%\'" | Percentage. Multiplies the number by 100 and displays in |\n | | fixed ("\'f\'") format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to "\'g\'", except with at least one digit past the |\n | | decimal point and a default precision of 12. This is |\n | | intended to match "str()", except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old "%"-formatting.\n\nIn most of the cases the syntax is similar to the old "%"-formatting,\nwith the addition of the "{}" and with ":" used instead of "%". For\nexample, "\'%03.2f\'" can be translated to "\'{:03.2f}\'".\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing "%s" and "%r":\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing "%+f", "%-f", and "% f" and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing "%x" and "%o" and converting the value to different bases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12): #doctest: +NORMALIZE_WHITESPACE\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', - 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n', - 'global': '\nThe "global" statement\n**********************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe "global" statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without "global", although free variables may refer to\nglobals without being declared global.\n\nNames listed in a "global" statement must not be used in the same code\nblock textually preceding that "global" statement.\n\nNames listed in a "global" statement must not be defined as formal\nparameters or in a "for" loop control target, "class" definition,\nfunction definition, or "import" statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the two restrictions, but programs should not abuse this\nfreedom, as future implementations may enforce them or silently change\nthe meaning of the program.\n\n**Programmer\'s note:** the "global" is a directive to the parser. It\napplies only to code parsed at the same time as the "global"\nstatement. In particular, a "global" statement contained in a string\nor code object supplied to the built-in "exec()" function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by "global" statements in the\ncode containing the function call. The same applies to the "eval()"\nand "compile()" functions.\n', - 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters "A" through "Z", the underscore "_" and, except for the first\ncharacter, the digits "0" through "9".\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n"unicodedata" module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'if': '\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', - 'imaginary': '\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., "(3+4j)". Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', - 'import': '\nThe "import" statement\n**********************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nThe basic import statement (no "from" clause) is executed in two\nsteps:\n\n1. find a module, loading and initializing it if necessary\n\n2. define a name or names in the local namespace for the scope\n where the "import" statement occurs.\n\nWhen the statement contains multiple clauses (separated by commas) the\ntwo steps are carried out separately for each clause, just as though\nthe clauses had been separated out into individiual import statements.\n\nThe details of the first step, finding and loading modules are\ndescribed in greater detail in the section on the *import system*,\nwhich also describes the various types of packages and modules that\ncan be imported, as well as all the hooks that can be used to\ncustomize the import system. Note that failures in this step may\nindicate either that the module could not be located, *or* that an\nerror occurred while initializing the module, which includes execution\nof the module\'s code.\n\nIf the requested module is retrieved successfully, it will be made\navailable in the local namespace in one of three ways:\n\n* If the module name is followed by "as", then the name following\n "as" is bound directly to the imported module.\n\n* If no other name is specified, and the module being imported is a\n top level module, the module\'s name is bound in the local namespace\n as a reference to the imported module\n\n* If the module being imported is *not* a top level module, then the\n name of the top level package that contains the module is bound in\n the local namespace as a reference to the top level package. The\n imported module must be accessed using its full qualified name\n rather than directly\n\nThe "from" form uses a slightly more complex process:\n\n1. find the module specified in the "from" clause, loading and\n initializing it if necessary;\n\n2. for each of the identifiers specified in the "import" clauses:\n\n 1. check if the imported module has an attribute by that name\n\n 2. if not, attempt to import a submodule with that name and then\n check the imported module again for that attribute\n\n 3. if the attribute is not found, "ImportError" is raised.\n\n 4. otherwise, a reference to that value is stored in the local\n namespace, using the name in the "as" clause if it is present,\n otherwise using the attribute name\n\nExamples:\n\n import foo # foo imported and bound locally\n import foo.bar.baz # foo.bar.baz imported, foo bound locally\n import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb\n from foo.bar import baz # foo.bar.baz imported and bound as baz\n from foo import attr # foo imported and foo.attr bound as attr\n\nIf the list of identifiers is replaced by a star ("\'*\'"), all public\nnames defined in the module are bound in the local namespace for the\nscope where the "import" statement occurs.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named "__all__"; if defined, it must\nbe a sequence of strings which are names defined or imported by that\nmodule. The names given in "__all__" are all considered public and\nare required to exist. If "__all__" is not defined, the set of public\nnames includes all names found in the module\'s namespace which do not\nbegin with an underscore character ("\'_\'"). "__all__" should contain\nthe entire public API. It is intended to avoid accidentally exporting\nitems that are not part of the API (such as library modules which were\nimported and used within the module).\n\nThe "from" form with "*" may only occur in a module scope. The wild\ncard form of import --- "from module import *" --- is only allowed at\nthe module level. Attempting to use it in class or function\ndefinitions will raise a "SyntaxError".\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after "from" you\ncan specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n"from . import mod" from a module in the "pkg" package then you will\nend up importing "pkg.mod". If you execute "from ..subpkg2 import mod"\nfrom within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\nspecification for relative imports is contained within **PEP 328**.\n\n"importlib.import_module()" is provided to support applications that\ndetermine dynamically the modules to be loaded.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python where the feature\nbecomes standard.\n\nThe future statement is intended to ease migration to future versions\nof Python that introduce incompatible changes to the language. It\nallows use of the new features on a per-module basis before the\nrelease in which the feature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are "absolute_import",\n"division", "generators", "unicode_literals", "print_function",\n"nested_scopes" and "with_statement". They are all redundant because\nthey are always enabled, and only kept for backwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module "__future__", described later, and it will\nbe imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions "exec()" and\n"compile()" that occur in a module "M" containing a future statement\nwill, by default, use the new syntax or semantics associated with the\nfuture statement. This can be controlled by optional arguments to\n"compile()" --- see the documentation of that function for details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also: **PEP 236** - Back to the __future__\n\n The original proposal for the __future__ mechanism.\n', - 'in': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', - 'integers': '\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', - 'lambda': '\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda expressions (sometimes called lambda forms) are used to create\nanonymous functions. The expression "lambda arguments: expression"\nyields a function object. The unnamed object behaves like a function\nobject defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda expressions cannot contain\nstatements or annotations.\n', - 'lists': '\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', - 'naming': '\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\nas a command line argument to the interpreter) is a code block. A\nscript command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, an\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\nglobal statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', - 'nonlocal': '\nThe "nonlocal" statement\n************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe "nonlocal" statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope excluding\nglobals. This is important because the default behavior for binding is\nto search the local namespace first. The statement allows\nencapsulated code to rebind variables outside of the local scope\nbesides the global (module) scope.\n\nNames listed in a "nonlocal" statement, unlike those listed in a\n"global" statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a "nonlocal" statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also: **PEP 3104** - Access to Names in Outer Scopes\n\n The specification for the "nonlocal" statement.\n', - 'numbers': '\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator \'"-"\' and the\nliteral "1".\n', - 'numeric-types': '\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, if *x* is an instance of a class with an\n "__iadd__()" method, "x += y" is equivalent to "x = x.__iadd__(y)"\n . Otherwise, "x.__add__(y)" and "y.__radd__(x)" are considered, as\n with the evaluation of "x + y". In certain situations, augmented\n assignment can result in unexpected errors (see *Why does\n a_tuple[i] += [\'item\'] raise an exception when the addition\n works?*), but this behavior is in fact part of the data model.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: In order to have a coherent integer type class, when\n "__index__()" is defined "__int__()" should also be defined, and\n both should return the same value.\n', - 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'"is"\' operator compares the\nidentity of two objects; the "id()" function returns an integer\nrepresenting its identity.\n\n**CPython implementation detail:** For CPython, "id(x)" is the memory\naddress where "x" is stored.\n\nAn object\'s type determines the operations that the object supports\n(e.g., "does it have a length?") and also defines the possible values\nfor objects of that type. The "type()" function returns an object\'s\ntype (which is an object itself). Like its identity, an object\'s\n*type* is also unchangeable. [1]\n\nThe *value* of some objects can change. Objects whose value can\nchange are said to be *mutable*; objects whose value is unchangeable\nonce they are created are called *immutable*. (The value of an\nimmutable container object that contains a reference to a mutable\nobject can change when the latter\'s value is changed; however the\ncontainer is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the "gc" module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (so\nyou should always close files explicitly).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'"try"..."except"\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a "close()" method. Programs\nare strongly recommended to explicitly close such objects. The\n\'"try"..."finally"\' statement and the \'"with"\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after "a = 1; b = 1",\n"a" and "b" may or may not refer to the same object with the value\none, depending on the implementation, but after "c = []; d = []", "c"\nand "d" are guaranteed to refer to two different, unique, newly\ncreated empty lists. (Note that "c = d = []" assigns the same object\nto both "c" and "d".)\n', - 'operator-summary': '\nOperator precedence\n*******************\n\nThe following table summarizes the operator precedence in Python, from\nlowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for exponentiation, which\ngroups from right to left).\n\nNote that comparisons, membership tests, and identity tests, all have\nthe same precedence and have a left-to-right chaining feature as\ndescribed in the *Comparisons* section.\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| "lambda" | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| "if" -- "else" | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| "or" | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| "and" | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| "not" "x" | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| "in", "not in", "is", "is not", "<", "<=", ">", | Comparisons, including membership |\n| ">=", "!=", "==" | tests and identity tests |\n+-------------------------------------------------+---------------------------------------+\n| "|" | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| "^" | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| "&" | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| "<<", ">>" | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| "+", "-" | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| "*", "/", "//", "%" | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| "+x", "-x", "~x" | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| "**" | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| "x[index]", "x[index:index]", | Subscription, slicing, call, |\n| "x(arguments...)", "x.attribute" | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| "(expressions...)", "[expressions...]", "{key: | Binding or tuple display, list |\n| value...}", "{expressions...}" | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While "abs(x%y) < abs(y)" is true mathematically, for floats\n it may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that "-1e-100 % 1e100" have the same\n sign as "1e100", the computed result is "-1e-100 + 1e100", which\n is numerically exactly equal to "1e100". The function\n "math.fmod()" returns a result whose sign matches the sign of the\n first argument instead, and so returns "-1e-100" in this case.\n Which approach is more appropriate depends on the application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for "x//y" to be one larger than "(x-x%y)//y" due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that "divmod(x,y)[0] * y + x % y" be very close\n to "x".\n\n[3] While comparisons between strings make sense at the byte\n level, they may be counter-intuitive to users. For example, the\n strings ""\\u00C7"" and ""\\u0327\\u0043"" compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using "unicodedata.normalize()".\n\n[4] Due to automatic garbage-collection, free lists, and the\n dynamic nature of descriptors, you may notice seemingly unusual\n behaviour in certain uses of the "is" operator, like those\n involving comparisons between instance methods, or constants.\n Check their documentation for more info.\n\n[5] The "%" operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator "**" binds less tightly than an arithmetic\n or bitwise unary operator on its right, that is, "2**-1" is "0.5".\n', - 'pass': '\nThe "pass" statement\n********************\n\n pass_stmt ::= "pass"\n\n"pass" is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', - 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): "-1**2" results in "-1".\n\nThe power operator has the same semantics as the built-in "pow()"\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n"10**2" returns "100", but "10**-2" returns "0.01".\n\nRaising "0.0" to a negative power results in a "ZeroDivisionError".\nRaising a negative number to a fractional power results in a "complex"\nnumber. (In earlier versions it raised a "ValueError".)\n', - 'raise': '\nThe "raise" statement\n*********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, "raise" re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a "RuntimeError" exception is raised indicating\nthat this is an error.\n\nOtherwise, "raise" evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n"BaseException". If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the "__traceback__" attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the "with_traceback()" exception method (which returns\nthe same exception instance, with its traceback set to its argument),\nlike so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe "from" clause is used for exception chaining: if given, the second\n*expression* must be another exception class or instance, which will\nthen be attached to the raised exception as the "__cause__" attribute\n(which is writable). If the raised exception is not handled, both\nexceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s "__context__" attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', - 'return': '\nThe "return" statement\n**********************\n\n return_stmt ::= "return" [expression_list]\n\n"return" may only occur syntactically nested in a function definition,\nnot within a nested class definition.\n\nIf an expression list is present, it is evaluated, else "None" is\nsubstituted.\n\n"return" leaves the current function call with the expression list (or\n"None") as return value.\n\nWhen "return" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nfunction.\n\nIn a generator function, the "return" statement indicates that the\ngenerator is done and will cause "StopIteration" to be raised. The\nreturned value (if any) is used as an argument to construct\n"StopIteration" and becomes the "StopIteration.value" attribute.\n', - 'sequence-types': '\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method "keys()".\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n', - 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as floor division by "pow(2,n)".\nA left shift by *n* bits is defined as multiplication with "pow(2,n)".\n\nNote: In the current implementation, the right-hand operand is\n required to be at most "sys.maxsize". If the right-hand operand is\n larger than "sys.maxsize" an "OverflowError" exception is raised.\n', - 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or "del" statements. The syntax for a slicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same "__getitem__()"\nmethod as normal subscription) with a key that is constructed from the\nslice list, as follows. If the slice list contains at least one\ncomma, the key is a tuple containing the conversion of the slice\nitems; otherwise, the conversion of the lone slice item is the key.\nThe conversion of a slice item that is an expression is that\nexpression. The conversion of a proper slice is a slice object (see\nsection *The standard type hierarchy*) whose "start", "stop" and\n"step" attributes are the values of the expressions given as lower\nbound, upper bound and stride, respectively, substituting "None" for\nmissing expressions.\n', - 'specialattrs': '\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the "dir()" built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in "__mro__".\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found\n in the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list "[1, 2]" is considered equal to\n "[1.0, 2.0]", and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property\n being one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase),\n or "Lt" (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a\n singleton tuple whose only element is the tuple to be formatted.\n', - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named "__getitem__()", and "x" is an instance of this class,\nthen "x[i]" is roughly equivalent to "type(x).__getitem__(x, i)".\nExcept where mentioned, attempts to execute an operation raise an\nexception when no appropriate method is defined (typically\n"AttributeError" or "TypeError").\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n"NodeList" interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])". As a special constraint on\n constructors, no value may be returned; doing so will cause a\n "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing "None" in\n "sys.last_traceback". Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n "gc" module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\n Changed in version 3.4: The __format__ method of "object" itself\n raises a "TypeError" if passed any non-empty string.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\nThe attribute "__objclass__" is interpreted by the "inspect" module as\nspecifying the class where this object was defined (setting this\nappropriately can assist in runtime introspection of dynamic class\nattributes). For callables, it may indicate that an instance of the\ngiven type (or a subclass) is expected or required as the first\npositional argument (for example, CPython sets this attribute for\nunbound methods that are implemented in C).\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using "type()". The class body is\nexecuted in a new namespace and the class name is bound locally to the\nresult of "type(name, bases, namespace)".\n\nThe class creation process can be customised by passing the\n"metaclass" keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both "MyClass" and "MySubclass" are instances\nof "Meta":\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then "type()" is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n "type()", then it is used directly as the metaclass\n\n* if an instance of "type()" is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. "type(cls)") of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with "TypeError".\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a "__prepare__" attribute,\nit is called as "namespace = metaclass.__prepare__(name, bases,\n**kwds)" (where the additional keyword arguments, if any, come from\nthe class definition).\n\nIf the metaclass has no "__prepare__" attribute, then the class\nnamespace is initialised as an empty "dict()" instance.\n\nSee also: **PEP 3115** - Metaclasses in Python 3000\n\n Introduced the "__prepare__" namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as "exec(body, globals(),\nnamespace)". The key difference from a normal call to "exec()" is that\nlexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling "metaclass(name, bases,\nnamespace, **kwds)" (the additional keywords passed here are the same\nas those passed to "__prepare__").\n\nThis class object is the one that will be referenced by the zero-\nargument form of "super()". "__class__" is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either "__class__" or "super". This allows the zero argument form\nof "super()" to correctly identify the class being defined based on\nlexical scoping, while the class or instance that was used to make the\ncurrent call is identified based on the first argument passed to the\nmethod.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also: **PEP 3135** - New super\n\n Describes the implicit "__class__" closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n"collections.OrderedDict" to remember the order that class variables\nare defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s "__prepare__()" method which returns an\nempty "collections.OrderedDict". That mapping records the methods and\nattributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s "__new__()" method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called "members".\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n"isinstance()" and "issubclass()" built-in functions.\n\nIn particular, the metaclass "abc.ABCMeta" implements these methods in\norder to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n "isinstance(instance, class)".\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n "issubclass(subclass, class)".\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also: **PEP 3119** - Introducing Abstract Base Classes\n\n Includes the specification for customizing "isinstance()" and\n "issubclass()" behavior through "__instancecheck__()" and\n "__subclasscheck__()", with motivation for this functionality in\n the context of adding Abstract Base Classes (see the "abc"\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method "keys()".\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, if *x* is an instance of a class with an\n "__iadd__()" method, "x += y" is equivalent to "x = x.__iadd__(y)"\n . Otherwise, "x.__add__(y)" and "y.__radd__(x)" are considered, as\n with the evaluation of "x + y". In certain situations, augmented\n assignment can result in unexpected errors (see *Why does\n a_tuple[i] += [\'item\'] raise an exception when the addition\n works?*), but this behavior is in fact part of the data model.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: In order to have a coherent integer type class, when\n "__index__()" is defined "__int__()" should also be defined, and\n both should return the same value.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as "__hash__()" and "__repr__()" that are implemented by\nall objects, including type objects. If the implicit lookup of these\nmethods used the conventional lookup process, they would fail when\ninvoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe "__getattribute__()" method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the "__getattribute__()" machinery in this fashion provides\nsignificant scope for speed optimisations within the interpreter, at\nthe cost of some flexibility in the handling of special methods (the\nspecial method *must* be set on the class object itself in order to be\nconsistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type,\n under certain controlled conditions. It generally isn\'t a good\n idea though, since it can lead to some very strange behaviour if\n it is handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as "__add__()") fails the operation is not\n supported, which is why the reflected method is not called.\n', - 'string-methods': '\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see "str.format()",\n*Format String Syntax* and *String Formatting*) and the other based on\nC "printf" style formatting that handles a narrower range of types and\nis slightly harder to use correctly, but is often faster for the cases\nit can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the "re" module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter "\'\xc3\x9f\'" is equivalent to ""ss"".\n Since it is already lowercase, "lower()" would do nothing to "\'\xc3\x9f\'";\n "casefold()" converts it to ""ss"".\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is an ASCII space). The\n original string is returned if *width* is less than or equal to\n "len(s)".\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is "\'utf-8\'". *errors* may be given to set a different\n error handling scheme. The default for *errors* is "\'strict\'",\n meaning that encoding errors raise a "UnicodeError". Other possible\n values are "\'ignore\'", "\'replace\'", "\'xmlcharrefreplace\'",\n "\'backslashreplace\'" and any other name registered via\n "codecs.register_error()", see section *Codec Base Classes*. For a\n list of possible encodings, see section *Standard Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return "True" if the string ends with the specified *suffix*,\n otherwise return "False". *suffix* can also be a tuple of suffixes\n to look for. With optional *start*, test beginning at that\n position. With optional *end*, stop comparing at that position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab ("\\t"), one or more space characters are inserted in the result\n until the current column is equal to the next tab position. (The\n tab character itself is not copied.) If the character is a newline\n ("\\n") or return ("\\r"), it is copied and the current column is\n reset to zero. Any other character is copied unchanged and the\n current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" if *sub* is not found.\n\n Note: The "find()" method should be used only if you need to know\n the position of *sub*. To check if *sub* is a substring or not,\n use the "in" operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces "{}". Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to "str.format(**mapping)", except that "mapping" is used\n directly and not copied to a "dict". This is useful if for example\n "mapping" is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like "find()", but raise "ValueError" when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character "c"\n is alphanumeric if one of the following returns "True":\n "c.isalpha()", "c.isdecimal()", "c.isdigit()", or "c.isnumeric()".\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use "keyword.iskeyword()" to test for reserved identifiers such as\n "def" and "class".\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when "repr()" is\n invoked on a string. It has no bearing on the handling of strings\n written to "sys.stdout" or "sys.stderr".)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A "TypeError" will be raised if there are\n any non-string values in *iterable*, including "bytes" objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is an ASCII\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n "str.translate()".\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like "rfind()" but raises "ValueError" when the substring *sub* is\n not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is an ASCII\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n "None", any whitespace string is a separator. Except for splitting\n from the right, "rsplit()" behaves like "split()" which is\n described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most "maxsplit+1"\n elements). If *maxsplit* is not specified or "-1", then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', \'2\']"). The *sep* argument\n may consist of multiple characters (for example,\n "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', \'3\']"). Splitting an\n empty string with a specified separator returns "[\'\']".\n\n For example:\n\n >>> \'1,2,3\'.split(\',\')\n [\'1\', \'2\', \'3\']\n >>> \'1,2,3\'.split(\',\', maxsplit=1)\n [\'1\', \'2 3\']\n >>> \'1,2,,3,\'.split(\',\')\n [\'1\', \'2\', \'\', \'3\', \'\']\n\n If *sep* is not specified or is "None", a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a "None" separator returns "[]".\n\n For example:\n\n >>> \'1 2 3\'.split()\n [\'1\', \'2\', \'3\']\n >>> \'1 2 3\'.split(maxsplit=1)\n [\'1\', \'2 3\']\n >>> \' 1 2 3 \'.split()\n [\'1\', \'2\', \'3\']\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example:\n\n >>> \'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()\n [\'ab c\', \'\', \'de fg\', \'kl\']``\n >>> \'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines(keepends=True)\n [\'ab c\\n\', \'\\n\', \'de fg\\r\', \'kl\\r\\n\']\n\n Unlike "split()" when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line:\n\n >>> "".splitlines()\n []\n >>> "One line\\n".splitlines()\n [\'One line\']\n\n For comparison, "split(\'\\n\')" gives:\n\n >>> \'\'.split(\'\\n\')\n [\'\']\n >>> \'Two lines\\n\'.split(\'\\n\')\n [\'Two lines\', \'\']\n\nstr.startswith(prefix[, start[, end]])\n\n Return "True" if string starts with the *prefix*, otherwise return\n "False". *prefix* can also be a tuple of prefixes to look for.\n With optional *start*, test string beginning at that position.\n With optional *end*, stop comparing string at that position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or "None", the *chars*\n argument defaults to removing whitespace. The *chars* argument is\n not a prefix or suffix; rather, all combinations of its values are\n stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n "s.swapcase().swapcase() == s".\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n For example:\n\n >>> \'Hello world\'.title()\n \'Hello World\'\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or "None". Unmapped\n characters are left untouched. Characters mapped to "None" are\n deleted.\n\n You can use "str.maketrans()" to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom\n character mapping codec using the "codecs" module (see\n "encodings.cp1251" for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that "str.upper().isupper()" might be\n "False" if "s" contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return a copy of the string left filled with ASCII "\'0\'" digits to\n make a string of length *width*. A leading sign prefix ("\'+\'"/"\'-\'"\n is handled by inserting the padding *after* the sign character\n rather than before. The original string is returned if *width* is\n less than or equal to "len(s)".\n\n For example:\n\n >>> "42".zfill(5)\n \'00042\'\n >>> "-42".zfill(5)\n \'-0042\'\n', - 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "R" | "U"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the "stringprefix" or "bytesprefix"\nand the rest of the literal. The source character set is defined by\nthe encoding declaration; it is UTF-8 if no encoding declaration is\ngiven in the source file; see section *Encoding declarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes ("\'") or double quotes ("""). They can also be enclosed\nin matching groups of three single or double quotes (these are\ngenerally referred to as *triple-quoted strings*). The backslash\n("\\") character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with "\'b\'" or "\'B\'"; they produce\nan instance of the "bytes" type instead of the "str" type. They may\nonly contain ASCII characters; bytes with a numeric value of 128 or\ngreater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix unicode strings with a\n"u" prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter "\'r\'" or "\'R\'"; such strings are called *raw strings* and treat\nbackslashes as literal characters. As a result, in string literals,\n"\'\\U\'" and "\'\\u\'" escapes in raw strings are not treated specially.\nGiven that Python 2.x\'s raw unicode literals behave differently than\nPython 3.x\'s the "\'ur\'" syntax is not supported.\n\n New in version 3.3: The "\'rb\'" prefix of raw bytes literals has\n been added as a synonym of "\'br\'".\n\n New in version 3.3: Support for the unicode legacy literal\n ("u\'value\'") was reintroduced to simplify the maintenance of dual\n Python 2.x and 3.x codebases. See **PEP 414** for more information.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either "\'" or """.)\n\nUnless an "\'r\'" or "\'R\'" prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\newline" | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| "\\\\" | Backslash ("\\") | |\n+-------------------+-----------------------------------+---------+\n| "\\\'" | Single quote ("\'") | |\n+-------------------+-----------------------------------+---------+\n| "\\"" | Double quote (""") | |\n+-------------------+-----------------------------------+---------+\n| "\\a" | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| "\\b" | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| "\\f" | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| "\\n" | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| "\\r" | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| "\\t" | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| "\\v" | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| "\\ooo" | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| "\\xhh" | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\N{name}" | Character named *name* in the | (4) |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| "\\uxxxx" | Character with 16-bit hex value | (5) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| "\\Uxxxxxxxx" | Character with 32-bit hex value | (6) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the\n byte with the given value. In a string literal, these escapes\n denote a Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can\n be encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way. Exactly eight\n hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, "r"\\""" is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; "r"\\"" is not a valid string literal (even a raw string\ncannot end in an odd number of backslashes). Specifically, *a raw\nstring cannot end in a single backslash* (since the backslash would\nescape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', - 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription\n(lists or dictionaries for example). User-defined objects can support\nsubscription by defining a "__getitem__()" method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a "__getitem__()"\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that "x[-1]" selects the last item of "x").\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero). Since the support for\nnegative indices and slicing occurs in the object\'s "__getitem__()"\nmethod, subclasses overriding this method will need to explicitly add\nthat support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', - 'truth': '\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an "if" or\n"while" condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* "None"\n\n* "False"\n\n* zero of any numeric type, for example, "0", "0.0", "0j".\n\n* any empty sequence, for example, "\'\'", "()", "[]".\n\n* any empty mapping, for example, "{}".\n\n* instances of user-defined classes, if the class defines a\n "__bool__()" or "__len__()" method, when that method returns the\n integer zero or "bool" value "False". [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn "0" or "False" for false and "1" or "True" for true, unless\notherwise stated. (Important exception: the Boolean operations "or"\nand "and" always return one of their operands.)\n', - 'try': '\nThe "try" statement\n*******************\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name "None". It\n is used to signify the absence of a value in many situations, e.g.,\n it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n "NotImplemented". Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal "..." or the\n built-in name "Ellipsis". Its truth value is true.\n\n"numbers.Number"\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n "numbers.Integral"\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers ("int")\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans ("bool")\n These represent the truth values False and True. The two\n objects representing the values "False" and "True" are the\n only Boolean objects. The Boolean type is a subtype of the\n integer type, and Boolean values behave like the values 0 and\n 1, respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ""False"" or\n ""True"" are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n "numbers.Real" ("float")\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n "numbers.Complex" ("complex")\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number "z" can be retrieved through the read-only\n attributes "z.real" and "z.imag".\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function "len()" returns the number of items\n of a sequence. When the length of a sequence is *n*, the index set\n contains the numbers 0, 1, ..., *n*-1. Item *i* of sequence *a* is\n selected by "a[i]".\n\n Sequences also support slicing: "a[i:j]" selects all items with\n index *k* such that *i* "<=" *k* "<" *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: "a[i:j:k]" selects all items of *a* with index *x* where\n "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode code\n points. All the code points in the range "U+0000 - U+10FFFF"\n can be represented in a string. Python doesn\'t have a "char"\n type; instead, every code point in the string is represented\n as a string object with length "1". The built-in function\n "ord()" converts a code point from its string form to an\n integer in the range "0 - 10FFFF"; "chr()" converts an\n integer in the range "0 - 10FFFF" to the corresponding length\n "1" string object. "str.encode()" can be used to convert a\n "str" to "bytes" using the given text encoding, and\n "bytes.decode()" can be used to achieve the opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like "b\'abc\'") and the built-in function\n "bytes()" can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the "decode()"\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and "del" (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in "bytearray()" constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module "array" provides an additional example of a\n mutable sequence type, as does the "collections" module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function "len()"\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., "1" and\n "1.0"), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n "set()" constructor and can be modified afterwards by several\n methods, such as "add()".\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in "frozenset()" constructor. As a frozenset is immutable\n and *hashable*, it can be used again as an element of another\n set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation "a[k]" selects the item indexed by "k"\n from the mapping "a"; this can be used in expressions and as the\n target of assignments or "del" statements. The built-in function\n "len()" returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., "1" and "1.0")\n then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the "{...}"\n notation (see section *Dictionary displays*).\n\n The extension modules "dbm.ndbm" and "dbm.gnu" provide\n additional examples of mapping types, as does the "collections"\n module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | "__doc__" | The function\'s documentation | Writable |\n | | string, or "None" if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | "__name__" | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__qualname__" | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n | | function was defined in, or | |\n | | "None" if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or "None" if no arguments have | |\n | | a default value | |\n +---------------------------+---------------------------------+-------------+\n | "__code__" | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | "__dict__" | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n | | contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | "__annotations__" | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | and "\'return\'" for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | "__kwdefaults__" | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: "__self__" is the class instance\n object, "__func__" is the function object; "__doc__" is the\n method\'s documentation (same as "__func__.__doc__"); "__name__"\n is the method name (same as "__func__.__name__"); "__module__"\n is the name of the module the method was defined in, or "None"\n if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its "__self__" attribute is the instance, and the method object\n is said to be bound. The new method\'s "__func__" attribute is\n the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the "__func__"\n attribute of the new instance is not the original method object\n but its "__func__" attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its "__self__" attribute\n is the class itself, and its "__func__" attribute is the\n function object underlying the class method.\n\n When an instance method object is called, the underlying\n function ("__func__") is called, inserting the class instance\n ("__self__") in front of the argument list. For instance, when\n "C" is a class which contains a definition for a function "f()",\n and "x" is an instance of "C", calling "x.f(1)" is equivalent to\n calling "C.f(x, 1)".\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in "__self__" will actually\n be the class itself, so that calling either "x.f(1)" or "C.f(1)"\n is equivalent to calling "f(C,1)" where "f" is the underlying\n function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "iterator.__next__()" method will cause the\n function to execute until it provides a value using the "yield"\n statement. When the function executes a "return" statement or\n falls off the end, a "StopIteration" exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are "len()" and "math.sin()"\n ("math" is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: "__doc__" is the function\'s documentation\n string, or "None" if unavailable; "__name__" is the function\'s\n name; "__self__" is set to "None" (but see the next item);\n "__module__" is the name of the module the function was defined\n in or "None" if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n "alist.append()", assuming *alist* is a list object. In this\n case, the special read-only attribute "__self__" is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override "__new__()". The arguments of the\n call are passed to "__new__()" and, in the typical case, to\n "__init__()" to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a "__call__()" method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the "import"\n statement (see "import"), or by calling functions such as\n "importlib.import_module()" and built-in "__import__()". A module\n object has a namespace implemented by a dictionary object (this is\n the dictionary referenced by the "__globals__" attribute of\n functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., "m.x" is equivalent\n to "m.__dict__["x"]". A module object does not contain the code\n object used to initialize the module (since it isn\'t needed once\n the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s name;\n "__doc__" is the module\'s documentation string, or "None" if\n unavailable; "__file__" is the pathname of the file from which the\n module was loaded, if it was loaded from a file. The "__file__"\n attribute may be missing for certain types of modules, such as C\n modules that are statically linked into the interpreter; for\n extension modules loaded dynamically from a shared library, it is\n the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., "C.x" is translated to\n "C.__dict__["x"]" (although there are a number of hooks which allow\n for other means of locating attributes). When the attribute name is\n not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n class method object, it is transformed into an instance method\n object whose "__self__" attributes is "C". When it would yield a\n static method object, it is transformed into the object wrapped by\n the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its "__dict__".\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: "__name__" is the class name; "__module__" is\n the module name in which the class was defined; "__dict__" is the\n dictionary containing the class\'s namespace; "__bases__" is a tuple\n (possibly empty or a singleton) containing the base classes, in the\n order of their occurrence in the base class list; "__doc__" is the\n class\'s documentation string, or None if undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose "__self__" attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s "__dict__".\n If no class attribute is found, and the object\'s class has a\n "__getattr__()" method, that is called to satisfy the lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n "__setattr__()" or "__delattr__()" method, this is called instead\n of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: "__dict__" is the attribute dictionary;\n "__class__" is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the "open()" built-in function,\n and also "os.popen()", "os.fdopen()", and the "makefile()" method\n of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n "io.TextIOBase" abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function name;\n "co_argcount" is the number of positional arguments (including\n arguments with default values); "co_nlocals" is the number of\n local variables used by the function (including arguments);\n "co_varnames" is a tuple containing the names of the local\n variables (starting with the argument names); "co_cellvars" is a\n tuple containing the names of local variables that are\n referenced by nested functions; "co_freevars" is a tuple\n containing the names of free variables; "co_code" is a string\n representing the sequence of bytecode instructions; "co_consts"\n is a tuple containing the literals used by the bytecode;\n "co_names" is a tuple containing the names used by the bytecode;\n "co_filename" is the filename from which the code was compiled;\n "co_firstlineno" is the first line number of the function;\n "co_lnotab" is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); "co_stacksize" is the required stack size\n (including local variables); "co_flags" is an integer encoding a\n number of flags for the interpreter.\n\n The following flag bits are defined for "co_flags": bit "0x04"\n is set if the function uses the "*arguments" syntax to accept an\n arbitrary number of positional arguments; bit "0x08" is set if\n the function uses the "**keywords" syntax to accept arbitrary\n keyword arguments; bit "0x20" is set if the function is a\n generator.\n\n Future feature declarations ("from __future__ import division")\n also use bits in "co_flags" to indicate whether a code object\n was compiled with a particular feature enabled: bit "0x2000" is\n set if the function was compiled with future division enabled;\n bits "0x10" and "0x1000" were used in earlier versions of\n Python.\n\n Other bits in "co_flags" are reserved for internal use.\n\n If a code object represents a function, the first item in\n "co_consts" is the documentation string of the function, or\n "None" if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: "f_back" is to the previous stack\n frame (towards the caller), or "None" if this is the bottom\n stack frame; "f_code" is the code object being executed in this\n frame; "f_locals" is the dictionary used to look up local\n variables; "f_globals" is used for global variables;\n "f_builtins" is used for built-in (intrinsic) names; "f_lasti"\n gives the precise instruction (this is an index into the\n bytecode string of the code object).\n\n Special writable attributes: "f_trace", if not "None", is a\n function called at the start of each source code line (this is\n used by the debugger); "f_lineno" is the current line number of\n the frame --- writing to this from within a trace function jumps\n to the given line (only for the bottom-most frame). A debugger\n can implement a Jump command (aka Set Next Statement) by writing\n to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n "RuntimeError" is raised if the frame is currently executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by "sys.exc_info()". When the program contains no\n suitable handler, the stack trace is written (nicely formatted)\n to the standard error stream; if the interpreter is interactive,\n it is also made available to the user as "sys.last_traceback".\n\n Special read-only attributes: "tb_next" is the next level in the\n stack trace (towards the frame where the exception occurred), or\n "None" if there is no next level; "tb_frame" points to the\n execution frame of the current level; "tb_lineno" gives the line\n number where the exception occurred; "tb_lasti" indicates the\n precise instruction. The line number and last instruction in\n the traceback may differ from the line number of its frame\n object if the exception occurred in a "try" statement with no\n matching except clause or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for "__getitem__()"\n methods. They are also created by the built-in "slice()"\n function.\n\n Special read-only attributes: "start" is the lower bound; "stop"\n is the upper bound; "step" is the step value; each is "None" if\n omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n "staticmethod()" constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in "classmethod()" constructor.\n', - 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: "func(argument-list)".\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', - 'typesmapping': '\nMapping Types --- "dict"\n************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin "list", "set", and "tuple" classes, and the "collections" module.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as "1" and "1.0") then they can be used interchangeably to index\nthe same dictionary entry. (Note however, that since computers store\nfloating-point numbers as approximations it is usually unwise to use\nthem as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of "key:\nvalue" pairs within braces, for example: "{\'jack\': 4098, \'sjoerd\':\n4127}" or "{4098: \'jack\', 4127: \'sjoerd\'}", or by the "dict"\nconstructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterable*\n object. Each item in the iterable must itself be an iterable with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to "{"one": 1, "two": 2, "three": 3}":\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a "KeyError" if\n *key* is not in the map.\n\n If a subclass of dict defines a method "__missing__()", if the\n key *key* is not present, the "d[key]" operation calls that\n method with the key *key* as argument. The "d[key]" operation\n then returns or raises whatever is returned or raised by the\n "__missing__(key)" call if the key is not present. No other\n operations or methods invoke "__missing__()". If "__missing__()"\n is not defined, "KeyError" is raised. "__missing__()" must be a\n method; it cannot be an instance variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See "collections.Counter" for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n key not in d\n\n Equivalent to "not key in d".\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iter(d.keys())".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n "fromkeys()" is a class method that returns a new dictionary.\n *value* defaults to "None".\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to "None", so\n that this method never raises a "KeyError".\n\n items()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a "KeyError" is raised.\n\n popitem()\n\n Remove and return an arbitrary "(key, value)" pair from the\n dictionary.\n\n "popitem()" is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling "popitem()" raises a "KeyError".\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to "None".\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return "None".\n\n "update()" accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: "d.update(red=1,\n blue=2)".\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also: "types.MappingProxyType" can be used to create a read-only\n view of a "dict".\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.keys()", "dict.values()" and\n"dict.items()" are *view objects*. They provide a dynamic view on the\ndictionary\'s entries, which means that when the dictionary changes,\nthe view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of "(key, value)") in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of "(value, key)" pairs using\n "zip()": "pairs = zip(d.values(), d.keys())". Another way to\n create the same list is "pairs = [(v, k) for (k, v) in d.items()]".\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a "RuntimeError" or fail to iterate over all entries.\n\nx in dictview\n\n Return "True" if *x* is in the underlying dictionary\'s keys, values\n or items (in the latter case, *x* should be a "(key, value)"\n tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that "(key, value)" pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class "collections.abc.Set" are available (for example, "==",\n"<", or "^").\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', - 'typesmethods': '\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as "append()" on lists)\nand class instance methods. Built-in methods are described with the\ntypes that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the "self"\nargument to the argument list. Bound methods have two special read-\nonly attributes: "m.__self__" is the object on which the method\noperates, and "m.__func__" is the function implementing the method.\nCalling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to\ncalling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object ("meth.__func__"), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an "AttributeError" being raised. In\norder to set a method attribute, you need to explicitly set it on the\nunderlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', - 'typesmodules': '\nModules\n*******\n\nThe only special operation on a module is attribute access: "m.name",\nwhere *m* is a module and *name* accesses a name defined in *m*\'s\nsymbol table. Module attributes can be assigned to. (Note that the\n"import" statement is not, strictly speaking, an operation on a module\nobject; "import foo" does not require a module object named *foo* to\nexist, rather it requires an (external) *definition* for a module\nnamed *foo* somewhere.)\n\nA special attribute of every module is "__dict__". This is the\ndictionary containing the module\'s symbol table. Modifying this\ndictionary will actually change the module\'s symbol table, but direct\nassignment to the "__dict__" attribute is not possible (you can write\n"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but you can\'t\nwrite "m.__dict__ = {}"). Modifying "__dict__" directly is not\nrecommended.\n\nModules built into the interpreter are written like this: "". If loaded from a file, they are written as\n"".\n', - 'typesseq': '\nSequence Types --- "list", "tuple", "range"\n*******************************************\n\nThere are three basic sequence types: lists, tuples, and range\nobjects. Additional sequence types tailored for processing of *binary\ndata* and *text strings* are described in dedicated sections.\n\n\nCommon Sequence Operations\n==========================\n\nThe operations in the following table are supported by most sequence\ntypes, both mutable and immutable. The "collections.abc.Sequence" ABC\nis provided to make it easier to correctly implement these operations\non custom sequence types.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type, *n*, *i*, *j* and *k* are\nintegers and *x* is an arbitrary object that meets any type and value\nrestrictions imposed by *s*.\n\nThe "in" and "not in" operations have the same priorities as the\ncomparison operations. The "+" (concatenation) and "*" (repetition)\noperations have the same priority as the corresponding numeric\noperations.\n\n+----------------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+============================+==================================+============+\n| "x in s" | "True" if an item of *s* is | (1) |\n| | equal to *x*, else "False" | |\n+----------------------------+----------------------------------+------------+\n| "x not in s" | "False" if an item of *s* is | (1) |\n| | equal to *x*, else "True" | |\n+----------------------------+----------------------------------+------------+\n| "s + t" | the concatenation of *s* and *t* | (6)(7) |\n+----------------------------+----------------------------------+------------+\n| "s * n" or "n * s" | *n* shallow copies of *s* | (2)(7) |\n| | concatenated | |\n+----------------------------+----------------------------------+------------+\n| "s[i]" | *i*th item of *s*, origin 0 | (3) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+----------------------------+----------------------------------+------------+\n| "len(s)" | length of *s* | |\n+----------------------------+----------------------------------+------------+\n| "min(s)" | smallest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "max(s)" | largest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) |\n| | *x* in *s* (at or after index | |\n| | *i* and before index *j*) | |\n+----------------------------+----------------------------------+------------+\n| "s.count(x)" | total number of occurrences of | |\n| | *x* in *s* | |\n+----------------------------+----------------------------------+------------+\n\nSequences of the same type also support comparisons. In particular,\ntuples and lists are compared lexicographically by comparing\ncorresponding elements. This means that to compare equal, every\nelement must compare equal and the two sequences must be of the same\ntype and have the same length. (For full details see *Comparisons* in\nthe language reference.)\n\nNotes:\n\n1. While the "in" and "not in" operations are used only for simple\n containment testing in the general case, some specialised sequences\n (such as "str", "bytes" and "bytearray") also use them for\n subsequence testing:\n\n >>> "gg" in "eggs"\n True\n\n2. Values of *n* less than "0" are treated as "0" (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that "[[]]" is a one-element list containing\n an empty list, so all three elements of "[[]] * 3" are (pointers\n to) this single empty list. Modifying any of the elements of\n "lists" modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of\n the string: "len(s) + i" or "len(s) + j" is substituted. But note\n that "-0" is still "0".\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that "i <= k < j". If *i* or *j* is\n greater than "len(s)", use "len(s)". If *i* is omitted or "None",\n use "0". If *j* is omitted or "None", use "len(s)". If *i* is\n greater than or equal to *j*, the slice is empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index "x = i + n*k" such that "0 <= n <\n (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k",\n "i+3*k" and so on, stopping when *j* is reached (but never\n including *j*). If *i* or *j* is greater than "len(s)", use\n "len(s)". If *i* or *j* are omitted or "None", they become "end"\n values (which end depends on the sign of *k*). Note, *k* cannot be\n zero. If *k* is "None", it is treated like "1".\n\n6. Concatenating immutable sequences always results in a new\n object. This means that building up a sequence by repeated\n concatenation will have a quadratic runtime cost in the total\n sequence length. To get a linear runtime cost, you must switch to\n one of the alternatives below:\n\n * if concatenating "str" objects, you can build a list and use\n "str.join()" at the end or else write to a "io.StringIO" instance\n and retrieve its value when complete\n\n * if concatenating "bytes" objects, you can similarly use\n "bytes.join()" or "io.BytesIO", or you can do in-place\n concatenation with a "bytearray" object. "bytearray" objects are\n mutable and have an efficient overallocation mechanism\n\n * if concatenating "tuple" objects, extend a "list" instead\n\n * for other types, investigate the relevant class documentation\n\n7. Some sequence types (such as "range") only support item\n sequences that follow specific patterns, and hence don\'t support\n sequence concatenation or repetition.\n\n8. "index" raises "ValueError" when *x* is not found in *s*. When\n supported, the additional arguments to the index method allow\n efficient searching of subsections of the sequence. Passing the\n extra arguments is roughly equivalent to using "s[i:j].index(x)",\n only without copying any data and with the returned index being\n relative to the start of the sequence rather than the start of the\n slice.\n\n\nImmutable Sequence Types\n========================\n\nThe only operation that immutable sequence types generally implement\nthat is not also implemented by mutable sequence types is support for\nthe "hash()" built-in.\n\nThis support allows immutable sequences, such as "tuple" instances, to\nbe used as "dict" keys and stored in "set" and "frozenset" instances.\n\nAttempting to hash an immutable sequence that contains unhashable\nvalues will result in "TypeError".\n\n\nMutable Sequence Types\n======================\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | appends *x* to the end of the | |\n| | sequence (same as | |\n| | "s[len(s):len(s)] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n| | as "del s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n| | (same as "s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(t)" | extends *s* with the contents of | |\n| | *t* (same as "s[len(s):len(s)] = | |\n| | t") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | "s[i:i] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n| | where "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n\n\nLists\n=====\n\nLists are mutable sequences, typically used to store collections of\nhomogeneous items (where the precise degree of similarity will vary by\napplication).\n\nclass class list([iterable])\n\n Lists may be constructed in several ways:\n\n * Using a pair of square brackets to denote the empty list: "[]"\n\n * Using square brackets, separating items with commas: "[a]",\n "[a, b, c]"\n\n * Using a list comprehension: "[x for x in iterable]"\n\n * Using the type constructor: "list()" or "list(iterable)"\n\n The constructor builds a list whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a list, a copy is made and\n returned, similar to "iterable[:]". For example, "list(\'abc\')"\n returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" returns "[1, 2,\n 3]". If no argument is given, the constructor creates a new empty\n list, "[]".\n\n Many other operations also produce lists, including the "sorted()"\n built-in.\n\n Lists implement all of the *common* and *mutable* sequence\n operations. Lists also provide the following additional method:\n\n sort(*, key=None, reverse=None)\n\n This method sorts the list in place, using only "<" comparisons\n between items. Exceptions are not suppressed - if any comparison\n operations fail, the entire sort operation will fail (and the\n list will likely be left in a partially modified state).\n\n "sort()" accepts two arguments that can only be passed by\n keyword (*keyword-only arguments*):\n\n *key* specifies a function of one argument that is used to\n extract a comparison key from each list element (for example,\n "key=str.lower"). The key corresponding to each item in the list\n is calculated once and then used for the entire sorting process.\n The default value of "None" means that list items are sorted\n directly without calculating a separate key value.\n\n The "functools.cmp_to_key()" utility is available to convert a\n 2.x style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n This method modifies the sequence in place for economy of space\n when sorting a large sequence. To remind users that it operates\n by side effect, it does not return the sorted sequence (use\n "sorted()" to explicitly request a new sorted list instance).\n\n The "sort()" method is guaranteed to be stable. A sort is\n stable if it guarantees not to change the relative order of\n elements that compare equal --- this is helpful for sorting in\n multiple passes (for example, sort by department, then by salary\n grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises "ValueError" if it can detect\n that the list has been mutated during a sort.\n\n\nTuples\n======\n\nTuples are immutable sequences, typically used to store collections of\nheterogeneous data (such as the 2-tuples produced by the "enumerate()"\nbuilt-in). Tuples are also used for cases where an immutable sequence\nof homogeneous data is needed (such as allowing storage in a "set" or\n"dict" instance).\n\nclass class tuple([iterable])\n\n Tuples may be constructed in a number of ways:\n\n * Using a pair of parentheses to denote the empty tuple: "()"\n\n * Using a trailing comma for a singleton tuple: "a," or "(a,)"\n\n * Separating items with commas: "a, b, c" or "(a, b, c)"\n\n * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)"\n\n The constructor builds a tuple whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a tuple, it is returned\n unchanged. For example, "tuple(\'abc\')" returns "(\'a\', \'b\', \'c\')"\n and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is\n given, the constructor creates a new empty tuple, "()".\n\n Note that it is actually the comma which makes a tuple, not the\n parentheses. The parentheses are optional, except in the empty\n tuple case, or when they are needed to avoid syntactic ambiguity.\n For example, "f(a, b, c)" is a function call with three arguments,\n while "f((a, b, c))" is a function call with a 3-tuple as the sole\n argument.\n\n Tuples implement all of the *common* sequence operations.\n\nFor heterogeneous collections of data where access by name is clearer\nthan access by index, "collections.namedtuple()" may be a more\nappropriate choice than a simple tuple object.\n\n\nRanges\n======\n\nThe "range" type represents an immutable sequence of numbers and is\ncommonly used for looping a specific number of times in "for" loops.\n\nclass class range(stop)\nclass class range(start, stop[, step])\n\n The arguments to the range constructor must be integers (either\n built-in "int" or any object that implements the "__index__"\n special method). If the *step* argument is omitted, it defaults to\n "1". If the *start* argument is omitted, it defaults to "0". If\n *step* is zero, "ValueError" is raised.\n\n For a positive *step*, the contents of a range "r" are determined\n by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] <\n stop".\n\n For a negative *step*, the contents of the range are still\n determined by the formula "r[i] = start + step*i", but the\n constraints are "i >= 0" and "r[i] > stop".\n\n A range object will be empty if "r[0]" does not meet the value\n constraint. Ranges do support negative indices, but these are\n interpreted as indexing from the end of the sequence determined by\n the positive indices.\n\n Ranges containing absolute values larger than "sys.maxsize" are\n permitted but some features (such as "len()") may raise\n "OverflowError".\n\n Range examples:\n\n >>> list(range(10))\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n >>> list(range(1, 11))\n [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n >>> list(range(0, 30, 5))\n [0, 5, 10, 15, 20, 25]\n >>> list(range(0, 10, 3))\n [0, 3, 6, 9]\n >>> list(range(0, -10, -1))\n [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n >>> list(range(0))\n []\n >>> list(range(1, 0))\n []\n\n Ranges implement all of the *common* sequence operations except\n concatenation and repetition (due to the fact that range objects\n can only represent sequences that follow a strict pattern and\n repetition and concatenation will usually violate that pattern).\n\nThe advantage of the "range" type over a regular "list" or "tuple" is\nthat a "range" object will always take the same (small) amount of\nmemory, no matter the size of the range it represents (as it only\nstores the "start", "stop" and "step" values, calculating individual\nitems and subranges as needed).\n\nRange objects implement the "collections.abc.Sequence" ABC, and\nprovide features such as containment tests, element index lookup,\nslicing and support for negative indices (see *Sequence Types ---\nlist, tuple, range*):\n\n>>> r = range(0, 20, 2)\n>>> r\nrange(0, 20, 2)\n>>> 11 in r\nFalse\n>>> 10 in r\nTrue\n>>> r.index(10)\n5\n>>> r[5]\n10\n>>> r[:5]\nrange(0, 10, 2)\n>>> r[-1]\n18\n\nTesting range objects for equality with "==" and "!=" compares them as\nsequences. That is, two range objects are considered equal if they\nrepresent the same sequence of values. (Note that two range objects\nthat compare equal might have different "start", "stop" and "step"\nattributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3,\n2) == range(0, 4, 2)".)\n\nChanged in version 3.2: Implement the Sequence ABC. Support slicing\nand negative indices. Test "int" objects for membership in constant\ntime instead of iterating through all items.\n\nChanged in version 3.3: Define \'==\' and \'!=\' to compare range objects\nbased on the sequence of values they define (instead of comparing\nbased on object identity).\n\nNew in version 3.3: The "start", "stop" and "step" attributes.\n', - 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | appends *x* to the end of the | |\n| | sequence (same as | |\n| | "s[len(s):len(s)] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n| | as "del s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n| | (same as "s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(t)" | extends *s* with the contents of | |\n| | *t* (same as "s[len(s):len(s)] = | |\n| | t") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | "s[i:i] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n| | where "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n', - 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary "-" (minus) operator yields the negation of its numeric\nargument.\n\nThe unary "+" (plus) operator yields its numeric argument unchanged.\n\nThe unary "~" (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of "x" is defined as\n"-(x+1)". It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n"TypeError" exception is raised.\n', - 'while': '\nThe "while" statement\n*********************\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n', - 'with': '\nThe "with" statement\n********************\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', - 'yield': '\nThe "yield" statement\n*********************\n\n yield_stmt ::= yield_expression\n\nA "yield" statement is semantically equivalent to a *yield\nexpression*. The yield statement can be used to omit the parentheses\nthat would otherwise be required in the equivalent yield expression\nstatement. For example, the yield statements\n\n yield \n yield from \n\nare equivalent to the yield expression statements\n\n (yield )\n (yield from )\n\nYield expressions and statements are only used when defining a\n*generator* function, and are only used in the body of the generator\nfunction. Using yield in a function definition is sufficient to cause\nthat definition to create a generator function instead of a normal\nfunction.\n\nFor full details of "yield" semantics, refer to the *Yield\nexpressions* section.\n'} +# Autogenerated by Sphinx on Sat Feb 7 15:53:49 2015 +topics = {'assert': u'\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', + 'assignment': u'\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for\n*attributeref*, *subscription*, and *slicing*.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the target\n sequence allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nAlthough the definition of assignment implies that overlaps between\nthe left-hand side and the right-hand side are \'simultanenous\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables occur left-to-right, sometimes\nresulting in confusion. For instance, the following program prints\n"[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2 # i is updated, then x[i] is updated\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'atom-identifiers': u'\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n', + 'atom-literals': u"\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", + 'attribute-access': u'\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\nThe attribute "__objclass__" is interpreted by the "inspect" module as\nspecifying the class where this object was defined (setting this\nappropriately can assist in runtime introspection of dynamic class\nattributes). For callables, it may indicate that an instance of the\ngiven type (or a subclass) is expected or required as the first\npositional argument (for example, CPython sets this attribute for\nunbound methods that are implemented in C).\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. *__slots__*\n reserves space for the declared variables and prevents the\n automatic creation of *__dict__* and *__weakref__* for each\n instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'attribute-references': u'\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier. This\nproduction can be customized by overriding the "__getattr__()" method.\nIf this attribute is not available, the exception "AttributeError" is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', + 'augassign': u'\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'binary': u'\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe "*" (multiplication) operator yields the product of its arguments.\nThe arguments must either both be numbers, or one argument must be an\ninteger and the other must be a sequence. In the former case, the\nnumbers are converted to a common type and then multiplied together.\nIn the latter case, sequence repetition is performed; a negative\nrepetition factor yields an empty sequence.\n\nThe "/" (division) and "//" (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Division of integers yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the "ZeroDivisionError" exception.\n\nThe "%" (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n"ZeroDivisionError" exception. The arguments may be floating point\nnumbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals "4*0.7 +\n0.34".) The modulo operator always yields a result with the same sign\nas its second operand (or zero); the absolute value of the result is\nstrictly smaller than the absolute value of the second operand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: "x == (x//y)*y + (x%y)". Floor division and modulo are also\nconnected with the built-in function "divmod()": "divmod(x, y) ==\n(x//y, x%y)". [2].\n\nIn addition to performing the modulo operation on numbers, the "%"\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *printf-style String Formatting*.\n\nThe floor division operator, the modulo operator, and the "divmod()"\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the "abs()" function if appropriate.\n\nThe "+" (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both be sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe "-" (subtraction) operator yields the difference of its arguments.\nThe numeric arguments are first converted to a common type.\n', + 'bitwise': u'\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe "&" operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe "^" operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe "|" operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', + 'bltin-code-objects': u'\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin "compile()" function and can be extracted from function objects\nthrough their "__code__" attribute. See also the "code" module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the "exec()" or "eval()" built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', + 'bltin-ellipsis-object': u'\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the\n"Ellipsis" singleton.\n\nIt is written as "Ellipsis" or "...".\n', + 'bltin-null-object': u'\nThe Null Object\n***************\n\nThis object is returned by functions that don\'t explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named "None" (a built-in name). "type(None)()" produces the\nsame singleton.\n\nIt is written as "None".\n', + 'bltin-type-objects': u'\nType Objects\n************\n\nType objects represent the various object types. An object\'s type is\naccessed by the built-in function "type()". There are no special\noperations on types. The standard module "types" defines names for\nall standard built-in types.\n\nTypes are written like this: "".\n', + 'booleans': u'\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: "False", "None", numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a "__bool__()" method.\n\nThe operator "not" yields "True" if its argument is false, "False"\notherwise.\n\nThe expression "x and y" first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression "x or y" first evaluates *x*; if *x* is true, its value\nis returned; otherwise, *y* is evaluated and the resulting value is\nreturned.\n\n(Note that neither "and" nor "or" restrict the value and type they\nreturn to "False" and "True", but rather return the last evaluated\nargument. This is sometimes useful, e.g., if "s" is a string that\nshould be replaced by a default value if it is empty, the expression\n"s or \'foo\'" yields the desired value. Because "not" has to create a\nnew value, it returns a boolean value regardless of the type of its\nargument (for example, "not \'foo\'" produces "False" rather than "\'\'".)\n', + 'break': u'\nThe "break" statement\n*********************\n\n break_stmt ::= "break"\n\n"break" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition within that\nloop.\n\nIt terminates the nearest enclosing loop, skipping the optional "else"\nclause if the loop has one.\n\nIf a "for" loop is terminated by "break", the loop control target\nkeeps its current value.\n\nWhen "break" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nloop.\n', + 'callable-types': u'\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n', + 'calls': u'\nCalls\n*****\n\nA call calls a callable object (e.g., a *function*) with a possibly\nempty series of *arguments*:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nAn optional trailing comma may be present after the positional and\nkeyword arguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n"__call__()" method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal *parameter* lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a "TypeError" exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is "None", it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a "TypeError"\nexception is raised. Otherwise, the list of filled slots is used as\nthe argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use "PyArg_ParseTuple()" to parse\ntheir arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "*identifier" is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "**identifier" is present; in this case, that formal\nparameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax "*expression" appears in the function call, "expression"\nmust evaluate to an iterable. Elements from this iterable are treated\nas if they were additional positional arguments; if there are\npositional arguments *x1*, ..., *xN*, and "expression" evaluates to a\nsequence *y1*, ..., *yM*, this is equivalent to a call with M+N\npositional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the "*expression" syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the "**expression" argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the "*expression" syntax\nto be used in the same call, so in practice this confusion does not\narise.\n\nIf the syntax "**expression" appears in the function call,\n"expression" must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both "expression" and as an explicit keyword argument, a\n"TypeError" exception is raised.\n\nFormal parameters using the syntax "*identifier" or "**identifier"\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly "None", unless it raises an\nexception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a "return"\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a "__call__()" method; the effect is then the\n same as if that method was called.\n', + 'class': u'\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', + 'comparisons': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', + 'compound': u'\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe "if", "while" and "for" statements implement traditional control\nflow constructs. "try" specifies exception handlers and/or cleanup\ncode for a group of statements, while the "with" statement allows the\nexecution of initialization and finalization code around a block of\ncode. Function and class definitions are also syntactically compound\nstatements.\n\nA compound statement consists of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of a suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which "if" clause a following "else" clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n"print()" calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a "NEWLINE" possibly followed by a\n"DEDENT". Also note that optional continuation clauses always begin\nwith a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling "else"\' problem is solved in Python by\nrequiring nested "if" statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe "if" statement\n==================\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n\n\nThe "while" statement\n=====================\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n\n\nThe "for" statement\n===================\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe "try" statement\n===================\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe "with" statement\n====================\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', + 'context-managers': u'\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', + 'continue': u'\nThe "continue" statement\n************************\n\n continue_stmt ::= "continue"\n\n"continue" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition or "finally"\nclause within that loop. It continues with the next cycle of the\nnearest enclosing loop.\n\nWhen "continue" passes control out of a "try" statement with a\n"finally" clause, that "finally" clause is executed before really\nstarting the next loop cycle.\n', + 'conversions': u'\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works as follows:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the\n other is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string as a\nleft argument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', + 'customization': u'\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called after the instance has been created (by "__new__()"), but\n before it is returned to the caller. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])".\n\n Because "__new__()" and "__init__()" work together in constructing\n objects ("__new__()" to create it, and "__init__()" to customise\n it), no non-"None" value may be returned by "__init__()"; doing so\n will cause a "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the second can be resolved by freeing the reference to the\n traceback object when it is no longer useful, and the third can\n be resolved by storing "None" in "sys.last_traceback". Circular\n references which are garbage are detected and cleaned up when the\n cyclic garbage collector is enabled (it\'s on by default). Refer\n to the documentation for the "gc" module for more information\n about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\n Changed in version 3.4: The __format__ method of "object" itself\n raises a "TypeError" if passed any non-empty string.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n', + 'debugger': u'\n"pdb" --- The Python Debugger\n*****************************\n\n**Source code:** Lib/pdb.py\n\n======================================================================\n\nThe module "pdb" defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n"Pdb". This is currently undocumented but easily understood by reading\nthe source. The extension interface uses the modules "bdb" and "cmd".\n\nThe debugger\'s prompt is "(Pdb)". Typical usage to run a program under\ncontrol of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\nChanged in version 3.3: Tab-completion via the "readline" module is\navailable for commands and command arguments, e.g. the current global\nand local names are offered as arguments of the "p" command.\n\n"pdb.py" can also be invoked as a script to debug other scripts. For\nexample:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: "pdb.py" now accepts a "-c" option that executes\ncommands as if given in a ".pdbrc" file, see *Debugger Commands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the "continue" command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type "continue", or you can\n step through the statement using "step" or "next" (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module "__main__" is used. (See the\n explanation of the built-in "exec()" or "eval()" functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When "runeval()" returns, it returns the\n value of the expression. Otherwise this function is similar to\n "run()".\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When "runcall()" returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n "sys.last_traceback".\n\nThe "run*" functions and "set_trace()" are aliases for instantiating\nthe "Pdb" class and calling the method of the same name. If you want\nto access further features, you have to do this yourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n "Pdb" is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying "cmd.Cmd" class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n "continue" command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n"h(elp)" means that either "h" or "help" can be used to enter the help\ncommand (but not "he" or "hel", nor "H" or "Help" or "HELP").\nArguments to commands must be separated by whitespace (spaces or\ntabs). Optional arguments are enclosed in square brackets ("[]") in\nthe command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n("|").\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a "list" command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint ("!"). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by ";;".\n(A single ";" is not used as it is the separator for multiple commands\nin a line that is passed to the Python parser.) No intelligence is\napplied to separating the commands; the input is split at the first\n";;" pair, even if it is in the middle of a quoted string.\n\nIf a file ".pdbrc" exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ".pdbrc" can now contain commands that\ncontinue debugging, such as "continue" or "next". Previously, these\ncommands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. "help pdb"\n displays the full documentation (the docstring of the "pdb"\n module). Since the *command* argument must be an identifier, "help\n exec" must be entered to get help on the "!" command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on "sys.path". Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for "break".\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just "end" to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) p some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with "end"; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between "next" and "step"\n is that "step" stops inside a called function, while "next"\n executes called functions at (nearly) full speed, only stopping at\n the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a "for" loop or out\n of a "finally" clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With "." as argument, list 11 lines around the current line. With\n one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by "->". If an\n exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ">>", if it differs\n from the current line.\n\n New in version 3.2: The ">>" marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for "list".\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\n Note: "print()" can also be used, but is not a debugger command\n --- this executes the Python "print()" function.\n\npp expression\n\n Like the "p" command, except the value of the expression is pretty-\n printed using the "pprint" module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the "code" module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by "%1", "%2", and so on, while "%*" is replaced by all\n the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ".pdbrc" file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n "global" statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with "shlex" and the result is used as the new\n "sys.argv". History, breakpoints, actions and debugger options are\n preserved. "restart" is an alias for "run".\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module\n is determined by the "__name__" in the frame globals.\n', + 'del': u'\nThe "del" statement\n*******************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a "global"\nstatement in the same code block. If the name is unbound, a\n"NameError" exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2: Previously it was illegal to delete a name\nfrom the local namespace if it occurs as a free variable in a nested\nblock.\n', + 'dict': u'\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', + 'dynamic-features': u'\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'else': u'\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', + 'exceptions': u'\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', + 'execmodel': u'\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\nas a command line argument to the interpreter) is a code block. A\nscript command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, an\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\n"global" statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', + 'exprlists': u'\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: "()".)\n', + 'floating': u'\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, "077e010" is legal, and denotes the same number\nas "77e10". The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator "-" and the\nliteral "1".\n', + 'for': u'\nThe "for" statement\n*******************\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', + 'formatstrings': u'\nFormat String Syntax\n********************\n\nThe "str.format()" method and the "Formatter" class share the same\nsyntax for format strings (although in the case of "Formatter",\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n"{}". Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n"{{" and "}}".\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point "\'!\'", and a *format_spec*, which is\npreceded by a colon "\':\'". These specify a non-default format for the\nreplacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings "\'10\'" or\n"\':-]\'") within a format string. The *arg_name* can be followed by any\nnumber of index or attribute expressions. An expression of the form\n"\'.name\'" selects the named attribute using "getattr()", while an\nexpression of the form "\'[index]\'" does an index lookup using\n"__getitem__()".\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so "\'{} {}\'" is equivalent to "\'{0} {1}\'".\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the "__format__()"\nmethod of the value itself. However, in some cases it is desirable to\nforce a type to be formatted as a string, overriding its own\ndefinition of formatting. By converting the value to a string before\ncalling "__format__()", the normal formatting logic is bypassed.\n\nThree conversion flags are currently supported: "\'!s\'" which calls\n"str()" on the value, "\'!r\'" which calls "repr()" and "\'!a\'" which\ncalls "ascii()".\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in "format()" function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string ("""") produces\nthe same result as if you had called "str()" on the value. A non-empty\nformat string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nIf a valid *align* value is specified, it can be preceded by a *fill*\ncharacter that can be any character and defaults to a space if\nomitted. Note that it is not possible to use "{" and "}" as *fill*\nchar while using the "str.format()" method; this limitation however\ndoesn\'t affect the "format()" function.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'<\'" | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | "\'>\'" | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | "\'=\'" | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | "\'^\'" | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'+\'" | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | "\'-\'" | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe "\'#\'" option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective "\'0b\'", "\'0o\'", or\n"\'0x\'" to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for "\'g\'" and "\'G\'"\nconversions, trailing zeros are not removed from the result.\n\nThe "\',\'" option signals the use of a comma for a thousands separator.\nFor a locale aware separator, use the "\'n\'" integer presentation type\ninstead.\n\nChanged in version 3.1: Added the "\',\'" option (see also **PEP 378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nPreceding the *width* field by a zero ("\'0\'") character enables sign-\naware zero-padding for numeric types. This is equivalent to a *fill*\ncharacter of "\'0\'" with an *alignment* type of "\'=\'".\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with "\'f\'" and "\'F\'", or before and after the decimal point\nfor a floating point value formatted with "\'g\'" or "\'G\'". For non-\nnumber types the field indicates the maximum field size - in other\nwords, how many characters will be used from the field content. The\n*precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'s\'" | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'s\'". |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'b\'" | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | "\'c\'" | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | "\'d\'" | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | "\'o\'" | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | "\'x\'" | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | "\'X\'" | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'d\'", except that it uses the |\n | | current locale setting to insert the appropriate number |\n | | separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'d\'". |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except "\'n\'"\nand None). When doing so, "float()" is used to convert the integer to\na floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'e\'" | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n | | The default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'E\'" | Exponent notation. Same as "\'e\'" except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | "\'f\'" | Fixed point. Displays the number as a fixed-point number. |\n | | The default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'F\'" | Fixed point. Same as "\'f\'", but converts "nan" to "NAN" |\n | | and "inf" to "INF". |\n +-----------+------------------------------------------------------------+\n | "\'g\'" | General format. For a given precision "p >= 1", this |\n | | rounds the number to "p" significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type "\'e\'" and precision "p-1" |\n | | would have exponent "exp". Then if "-4 <= exp < p", the |\n | | number is formatted with presentation type "\'f\'" and |\n | | precision "p-1-exp". Otherwise, the number is formatted |\n | | with presentation type "\'e\'" and precision "p-1". In both |\n | | cases insignificant trailing zeros are removed from the |\n | | significand, and the decimal point is also removed if |\n | | there are no remaining digits following it. Positive and |\n | | negative infinity, positive and negative zero, and nans, |\n | | are formatted as "inf", "-inf", "0", "-0" and "nan" |\n | | respectively, regardless of the precision. A precision of |\n | | "0" is treated as equivalent to a precision of "1". The |\n | | default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'G\'" | General format. Same as "\'g\'" except switches to "\'E\'" if |\n | | the number gets too large. The representations of infinity |\n | | and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'g\'", except that it uses the |\n | | current locale setting to insert the appropriate number |\n | | separator characters. |\n +-----------+------------------------------------------------------------+\n | "\'%\'" | Percentage. Multiplies the number by 100 and displays in |\n | | fixed ("\'f\'") format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to "\'g\'", except that fixed-point notation, when |\n | | used, has at least one digit past the decimal point. The |\n | | default precision is as high as needed to represent the |\n | | particular value. The overall effect is to match the |\n | | output of "str()" as altered by the other format |\n | | modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old "%"-formatting.\n\nIn most of the cases the syntax is similar to the old "%"-formatting,\nwith the addition of the "{}" and with ":" used instead of "%". For\nexample, "\'%03.2f\'" can be translated to "\'{:03.2f}\'".\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing "%s" and "%r":\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing "%+f", "%-f", and "% f" and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing "%x" and "%o" and converting the value to different bases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12): #doctest: +NORMALIZE_WHITESPACE\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', + 'function': u'\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n', + 'global': u'\nThe "global" statement\n**********************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe "global" statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without "global", although free variables may refer to\nglobals without being declared global.\n\nNames listed in a "global" statement must not be used in the same code\nblock textually preceding that "global" statement.\n\nNames listed in a "global" statement must not be defined as formal\nparameters or in a "for" loop control target, "class" definition,\nfunction definition, or "import" statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the two restrictions, but programs should not abuse this\nfreedom, as future implementations may enforce them or silently change\nthe meaning of the program.\n\n**Programmer\'s note:** the "global" is a directive to the parser. It\napplies only to code parsed at the same time as the "global"\nstatement. In particular, a "global" statement contained in a string\nor code object supplied to the built-in "exec()" function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by "global" statements in the\ncode containing the function call. The same applies to the "eval()"\nand "compile()" functions.\n', + 'id-classes': u'\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'identifiers': u'\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters "A" through "Z", the underscore "_" and, except for the first\ncharacter, the digits "0" through "9".\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n"unicodedata" module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'if': u'\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', + 'imaginary': u'\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., "(3+4j)". Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', + 'import': u'\nThe "import" statement\n**********************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nThe basic import statement (no "from" clause) is executed in two\nsteps:\n\n1. find a module, loading and initializing it if necessary\n\n2. define a name or names in the local namespace for the scope\n where the "import" statement occurs.\n\nWhen the statement contains multiple clauses (separated by commas) the\ntwo steps are carried out separately for each clause, just as though\nthe clauses had been separated out into individiual import statements.\n\nThe details of the first step, finding and loading modules are\ndescribed in greater detail in the section on the *import system*,\nwhich also describes the various types of packages and modules that\ncan be imported, as well as all the hooks that can be used to\ncustomize the import system. Note that failures in this step may\nindicate either that the module could not be located, *or* that an\nerror occurred while initializing the module, which includes execution\nof the module\'s code.\n\nIf the requested module is retrieved successfully, it will be made\navailable in the local namespace in one of three ways:\n\n* If the module name is followed by "as", then the name following\n "as" is bound directly to the imported module.\n\n* If no other name is specified, and the module being imported is a\n top level module, the module\'s name is bound in the local namespace\n as a reference to the imported module\n\n* If the module being imported is *not* a top level module, then the\n name of the top level package that contains the module is bound in\n the local namespace as a reference to the top level package. The\n imported module must be accessed using its full qualified name\n rather than directly\n\nThe "from" form uses a slightly more complex process:\n\n1. find the module specified in the "from" clause, loading and\n initializing it if necessary;\n\n2. for each of the identifiers specified in the "import" clauses:\n\n 1. check if the imported module has an attribute by that name\n\n 2. if not, attempt to import a submodule with that name and then\n check the imported module again for that attribute\n\n 3. if the attribute is not found, "ImportError" is raised.\n\n 4. otherwise, a reference to that value is stored in the local\n namespace, using the name in the "as" clause if it is present,\n otherwise using the attribute name\n\nExamples:\n\n import foo # foo imported and bound locally\n import foo.bar.baz # foo.bar.baz imported, foo bound locally\n import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb\n from foo.bar import baz # foo.bar.baz imported and bound as baz\n from foo import attr # foo imported and foo.attr bound as attr\n\nIf the list of identifiers is replaced by a star ("\'*\'"), all public\nnames defined in the module are bound in the local namespace for the\nscope where the "import" statement occurs.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named "__all__"; if defined, it must\nbe a sequence of strings which are names defined or imported by that\nmodule. The names given in "__all__" are all considered public and\nare required to exist. If "__all__" is not defined, the set of public\nnames includes all names found in the module\'s namespace which do not\nbegin with an underscore character ("\'_\'"). "__all__" should contain\nthe entire public API. It is intended to avoid accidentally exporting\nitems that are not part of the API (such as library modules which were\nimported and used within the module).\n\nThe wild card form of import --- "from module import *" --- is only\nallowed at the module level. Attempting to use it in class or\nfunction definitions will raise a "SyntaxError".\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after "from" you\ncan specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n"from . import mod" from a module in the "pkg" package then you will\nend up importing "pkg.mod". If you execute "from ..subpkg2 import mod"\nfrom within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\nspecification for relative imports is contained within **PEP 328**.\n\n"importlib.import_module()" is provided to support applications that\ndetermine dynamically the modules to be loaded.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python where the feature\nbecomes standard.\n\nThe future statement is intended to ease migration to future versions\nof Python that introduce incompatible changes to the language. It\nallows use of the new features on a per-module basis before the\nrelease in which the feature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are "absolute_import",\n"division", "generators", "unicode_literals", "print_function",\n"nested_scopes" and "with_statement". They are all redundant because\nthey are always enabled, and only kept for backwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module "__future__", described later, and it will\nbe imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions "exec()" and\n"compile()" that occur in a module "M" containing a future statement\nwill, by default, use the new syntax or semantics associated with the\nfuture statement. This can be controlled by optional arguments to\n"compile()" --- see the documentation of that function for details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also: **PEP 236** - Back to the __future__\n\n The original proposal for the __future__ mechanism.\n', + 'in': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', + 'integers': u'\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', + 'lambda': u'\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda expressions (sometimes called lambda forms) are used to create\nanonymous functions. The expression "lambda arguments: expression"\nyields a function object. The unnamed object behaves like a function\nobject defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda expressions cannot contain\nstatements or annotations.\n', + 'lists': u'\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', + 'naming': u'\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\nas a command line argument to the interpreter) is a code block. A\nscript command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, an\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\n"global" statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'nonlocal': u'\nThe "nonlocal" statement\n************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe "nonlocal" statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope excluding\nglobals. This is important because the default behavior for binding is\nto search the local namespace first. The statement allows\nencapsulated code to rebind variables outside of the local scope\nbesides the global (module) scope.\n\nNames listed in a "nonlocal" statement, unlike those listed in a\n"global" statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a "nonlocal" statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also: **PEP 3104** - Access to Names in Outer Scopes\n\n The specification for the "nonlocal" statement.\n', + 'numbers': u'\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator \'"-"\' and the\nliteral "1".\n', + 'numeric-types': u'\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, if *x* is an instance of a class with an\n "__iadd__()" method, "x += y" is equivalent to "x = x.__iadd__(y)"\n . Otherwise, "x.__add__(y)" and "y.__radd__(x)" are considered, as\n with the evaluation of "x + y". In certain situations, augmented\n assignment can result in unexpected errors (see *Why does\n a_tuple[i] += [\'item\'] raise an exception when the addition\n works?*), but this behavior is in fact part of the data model.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: In order to have a coherent integer type class, when\n "__index__()" is defined "__int__()" should also be defined, and\n both should return the same value.\n', + 'objects': u'\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'"is"\' operator compares the\nidentity of two objects; the "id()" function returns an integer\nrepresenting its identity.\n\n**CPython implementation detail:** For CPython, "id(x)" is the memory\naddress where "x" is stored.\n\nAn object\'s type determines the operations that the object supports\n(e.g., "does it have a length?") and also defines the possible values\nfor objects of that type. The "type()" function returns an object\'s\ntype (which is an object itself). Like its identity, an object\'s\n*type* is also unchangeable. [1]\n\nThe *value* of some objects can change. Objects whose value can\nchange are said to be *mutable*; objects whose value is unchangeable\nonce they are created are called *immutable*. (The value of an\nimmutable container object that contains a reference to a mutable\nobject can change when the latter\'s value is changed; however the\ncontainer is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the "gc" module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (so\nyou should always close files explicitly).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'"try"..."except"\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a "close()" method. Programs\nare strongly recommended to explicitly close such objects. The\n\'"try"..."finally"\' statement and the \'"with"\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after "a = 1; b = 1",\n"a" and "b" may or may not refer to the same object with the value\none, depending on the implementation, but after "c = []; d = []", "c"\nand "d" are guaranteed to refer to two different, unique, newly\ncreated empty lists. (Note that "c = d = []" assigns the same object\nto both "c" and "d".)\n', + 'operator-summary': u'\nOperator precedence\n*******************\n\nThe following table summarizes the operator precedence in Python, from\nlowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for exponentiation, which\ngroups from right to left).\n\nNote that comparisons, membership tests, and identity tests, all have\nthe same precedence and have a left-to-right chaining feature as\ndescribed in the *Comparisons* section.\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| "lambda" | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| "if" -- "else" | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| "or" | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| "and" | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| "not" "x" | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| "in", "not in", "is", "is not", "<", "<=", ">", | Comparisons, including membership |\n| ">=", "!=", "==" | tests and identity tests |\n+-------------------------------------------------+---------------------------------------+\n| "|" | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| "^" | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| "&" | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| "<<", ">>" | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| "+", "-" | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| "*", "/", "//", "%" | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| "+x", "-x", "~x" | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| "**" | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| "x[index]", "x[index:index]", | Subscription, slicing, call, |\n| "x(arguments...)", "x.attribute" | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| "(expressions...)", "[expressions...]", "{key: | Binding or tuple display, list |\n| value...}", "{expressions...}" | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While "abs(x%y) < abs(y)" is true mathematically, for floats\n it may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that "-1e-100 % 1e100" have the same\n sign as "1e100", the computed result is "-1e-100 + 1e100", which\n is numerically exactly equal to "1e100". The function\n "math.fmod()" returns a result whose sign matches the sign of the\n first argument instead, and so returns "-1e-100" in this case.\n Which approach is more appropriate depends on the application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for "x//y" to be one larger than "(x-x%y)//y" due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that "divmod(x,y)[0] * y + x % y" be very close\n to "x".\n\n[3] While comparisons between strings make sense at the byte\n level, they may be counter-intuitive to users. For example, the\n strings ""\\u00C7"" and ""\\u0327\\u0043"" compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using "unicodedata.normalize()".\n\n[4] Due to automatic garbage-collection, free lists, and the\n dynamic nature of descriptors, you may notice seemingly unusual\n behaviour in certain uses of the "is" operator, like those\n involving comparisons between instance methods, or constants.\n Check their documentation for more info.\n\n[5] The "%" operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator "**" binds less tightly than an arithmetic\n or bitwise unary operator on its right, that is, "2**-1" is "0.5".\n', + 'pass': u'\nThe "pass" statement\n********************\n\n pass_stmt ::= "pass"\n\n"pass" is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', + 'power': u'\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): "-1**2" results in "-1".\n\nThe power operator has the same semantics as the built-in "pow()"\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n"10**2" returns "100", but "10**-2" returns "0.01".\n\nRaising "0.0" to a negative power results in a "ZeroDivisionError".\nRaising a negative number to a fractional power results in a "complex"\nnumber. (In earlier versions it raised a "ValueError".)\n', + 'raise': u'\nThe "raise" statement\n*********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, "raise" re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a "RuntimeError" exception is raised indicating\nthat this is an error.\n\nOtherwise, "raise" evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n"BaseException". If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the "__traceback__" attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the "with_traceback()" exception method (which returns\nthe same exception instance, with its traceback set to its argument),\nlike so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe "from" clause is used for exception chaining: if given, the second\n*expression* must be another exception class or instance, which will\nthen be attached to the raised exception as the "__cause__" attribute\n(which is writable). If the raised exception is not handled, both\nexceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler or a "finally" clause: the previous exception is\nthen attached as the new exception\'s "__context__" attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', + 'return': u'\nThe "return" statement\n**********************\n\n return_stmt ::= "return" [expression_list]\n\n"return" may only occur syntactically nested in a function definition,\nnot within a nested class definition.\n\nIf an expression list is present, it is evaluated, else "None" is\nsubstituted.\n\n"return" leaves the current function call with the expression list (or\n"None") as return value.\n\nWhen "return" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nfunction.\n\nIn a generator function, the "return" statement indicates that the\ngenerator is done and will cause "StopIteration" to be raised. The\nreturned value (if any) is used as an argument to construct\n"StopIteration" and becomes the "StopIteration.value" attribute.\n', + 'sequence-types': u'\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__missing__(self, key)\n\n Called by "dict"."__getitem__()" to implement "self[key]" for dict\n subclasses when key is not in the dictionary.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n', + 'shifting': u'\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as floor division by "pow(2,n)".\nA left shift by *n* bits is defined as multiplication with "pow(2,n)".\n\nNote: In the current implementation, the right-hand operand is\n required to be at most "sys.maxsize". If the right-hand operand is\n larger than "sys.maxsize" an "OverflowError" exception is raised.\n', + 'slicings': u'\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or "del" statements. The syntax for a slicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary is indexed\n(using the same "__getitem__()" method as normal subscription) with a\nkey that is constructed from the slice list, as follows. If the slice\nlist contains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n"start", "stop" and "step" attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting "None" for missing expressions.\n', + 'specialattrs': u'\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the "dir()" built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in "__mro__".\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found\n in the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list "[1, 2]" is considered equal to\n "[1.0, 2.0]", and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property\n being one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase),\n or "Lt" (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a\n singleton tuple whose only element is the tuple to be formatted.\n', + 'specialnames': u'\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named "__getitem__()", and "x" is an instance of this class,\nthen "x[i]" is roughly equivalent to "type(x).__getitem__(x, i)".\nExcept where mentioned, attempts to execute an operation raise an\nexception when no appropriate method is defined (typically\n"AttributeError" or "TypeError").\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n"NodeList" interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called after the instance has been created (by "__new__()"), but\n before it is returned to the caller. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])".\n\n Because "__new__()" and "__init__()" work together in constructing\n objects ("__new__()" to create it, and "__init__()" to customise\n it), no non-"None" value may be returned by "__init__()"; doing so\n will cause a "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the second can be resolved by freeing the reference to the\n traceback object when it is no longer useful, and the third can\n be resolved by storing "None" in "sys.last_traceback". Circular\n references which are garbage are detected and cleaned up when the\n cyclic garbage collector is enabled (it\'s on by default). Refer\n to the documentation for the "gc" module for more information\n about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\n Changed in version 3.4: The __format__ method of "object" itself\n raises a "TypeError" if passed any non-empty string.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\nThe attribute "__objclass__" is interpreted by the "inspect" module as\nspecifying the class where this object was defined (setting this\nappropriately can assist in runtime introspection of dynamic class\nattributes). For callables, it may indicate that an instance of the\ngiven type (or a subclass) is expected or required as the first\npositional argument (for example, CPython sets this attribute for\nunbound methods that are implemented in C).\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. *__slots__*\n reserves space for the declared variables and prevents the\n automatic creation of *__dict__* and *__weakref__* for each\n instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using "type()". The class body is\nexecuted in a new namespace and the class name is bound locally to the\nresult of "type(name, bases, namespace)".\n\nThe class creation process can be customised by passing the\n"metaclass" keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both "MyClass" and "MySubclass" are instances\nof "Meta":\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then "type()" is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n "type()", then it is used directly as the metaclass\n\n* if an instance of "type()" is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. "type(cls)") of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with "TypeError".\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a "__prepare__" attribute,\nit is called as "namespace = metaclass.__prepare__(name, bases,\n**kwds)" (where the additional keyword arguments, if any, come from\nthe class definition).\n\nIf the metaclass has no "__prepare__" attribute, then the class\nnamespace is initialised as an empty "dict()" instance.\n\nSee also: **PEP 3115** - Metaclasses in Python 3000\n\n Introduced the "__prepare__" namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as "exec(body, globals(),\nnamespace)". The key difference from a normal call to "exec()" is that\nlexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling "metaclass(name, bases,\nnamespace, **kwds)" (the additional keywords passed here are the same\nas those passed to "__prepare__").\n\nThis class object is the one that will be referenced by the zero-\nargument form of "super()". "__class__" is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either "__class__" or "super". This allows the zero argument form\nof "super()" to correctly identify the class being defined based on\nlexical scoping, while the class or instance that was used to make the\ncurrent call is identified based on the first argument passed to the\nmethod.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also: **PEP 3135** - New super\n\n Describes the implicit "__class__" closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n"collections.OrderedDict" to remember the order that class variables\nare defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s "__prepare__()" method which returns an\nempty "collections.OrderedDict". That mapping records the methods and\nattributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s "__new__()" method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called "members".\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n"isinstance()" and "issubclass()" built-in functions.\n\nIn particular, the metaclass "abc.ABCMeta" implements these methods in\norder to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n "isinstance(instance, class)".\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n "issubclass(subclass, class)".\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also: **PEP 3119** - Introducing Abstract Base Classes\n\n Includes the specification for customizing "isinstance()" and\n "issubclass()" behavior through "__instancecheck__()" and\n "__subclasscheck__()", with motivation for this functionality in\n the context of adding Abstract Base Classes (see the "abc"\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__missing__(self, key)\n\n Called by "dict"."__getitem__()" to implement "self[key]" for dict\n subclasses when key is not in the dictionary.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, if *x* is an instance of a class with an\n "__iadd__()" method, "x += y" is equivalent to "x = x.__iadd__(y)"\n . Otherwise, "x.__add__(y)" and "y.__radd__(x)" are considered, as\n with the evaluation of "x + y". In certain situations, augmented\n assignment can result in unexpected errors (see *Why does\n a_tuple[i] += [\'item\'] raise an exception when the addition\n works?*), but this behavior is in fact part of the data model.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: In order to have a coherent integer type class, when\n "__index__()" is defined "__int__()" should also be defined, and\n both should return the same value.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as "__hash__()" and "__repr__()" that are implemented by\nall objects, including type objects. If the implicit lookup of these\nmethods used the conventional lookup process, they would fail when\ninvoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe "__getattribute__()" method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the "__getattribute__()" machinery in this fashion provides\nsignificant scope for speed optimisations within the interpreter, at\nthe cost of some flexibility in the handling of special methods (the\nspecial method *must* be set on the class object itself in order to be\nconsistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type,\n under certain controlled conditions. It generally isn\'t a good\n idea though, since it can lead to some very strange behaviour if\n it is handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as "__add__()") fails the operation is not\n supported, which is why the reflected method is not called.\n', + 'string-methods': u'\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see "str.format()",\n*Format String Syntax* and *String Formatting*) and the other based on\nC "printf" style formatting that handles a narrower range of types and\nis slightly harder to use correctly, but is often faster for the cases\nit can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the "re" module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter "\'\xdf\'" is equivalent to ""ss"".\n Since it is already lowercase, "lower()" would do nothing to "\'\xdf\'";\n "casefold()" converts it to ""ss"".\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is an ASCII space). The\n original string is returned if *width* is less than or equal to\n "len(s)".\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is "\'utf-8\'". *errors* may be given to set a different\n error handling scheme. The default for *errors* is "\'strict\'",\n meaning that encoding errors raise a "UnicodeError". Other possible\n values are "\'ignore\'", "\'replace\'", "\'xmlcharrefreplace\'",\n "\'backslashreplace\'" and any other name registered via\n "codecs.register_error()", see section *Error Handlers*. For a list\n of possible encodings, see section *Standard Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return "True" if the string ends with the specified *suffix*,\n otherwise return "False". *suffix* can also be a tuple of suffixes\n to look for. With optional *start*, test beginning at that\n position. With optional *end*, stop comparing at that position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab ("\\t"), one or more space characters are inserted in the result\n until the current column is equal to the next tab position. (The\n tab character itself is not copied.) If the character is a newline\n ("\\n") or return ("\\r"), it is copied and the current column is\n reset to zero. Any other character is copied unchanged and the\n current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" if *sub* is not found.\n\n Note: The "find()" method should be used only if you need to know\n the position of *sub*. To check if *sub* is a substring or not,\n use the "in" operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces "{}". Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to "str.format(**mapping)", except that "mapping" is used\n directly and not copied to a "dict". This is useful if for example\n "mapping" is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like "find()", but raise "ValueError" when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character "c"\n is alphanumeric if one of the following returns "True":\n "c.isalpha()", "c.isdecimal()", "c.isdigit()", or "c.isnumeric()".\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use "keyword.iskeyword()" to test for reserved identifiers such as\n "def" and "class".\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when "repr()" is\n invoked on a string. It has no bearing on the handling of strings\n written to "sys.stdout" or "sys.stderr".)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A "TypeError" will be raised if there are\n any non-string values in *iterable*, including "bytes" objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is an ASCII\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n "str.translate()".\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like "rfind()" but raises "ValueError" when the substring *sub* is\n not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is an ASCII\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n "None", any whitespace string is a separator. Except for splitting\n from the right, "rsplit()" behaves like "split()" which is\n described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most "maxsplit+1"\n elements). If *maxsplit* is not specified or "-1", then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', \'2\']"). The *sep* argument\n may consist of multiple characters (for example,\n "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', \'3\']"). Splitting an\n empty string with a specified separator returns "[\'\']".\n\n For example:\n\n >>> \'1,2,3\'.split(\',\')\n [\'1\', \'2\', \'3\']\n >>> \'1,2,3\'.split(\',\', maxsplit=1)\n [\'1\', \'2,3\']\n >>> \'1,2,,3,\'.split(\',\')\n [\'1\', \'2\', \'\', \'3\', \'\']\n\n If *sep* is not specified or is "None", a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a "None" separator returns "[]".\n\n For example:\n\n >>> \'1 2 3\'.split()\n [\'1\', \'2\', \'3\']\n >>> \'1 2 3\'.split(maxsplit=1)\n [\'1\', \'2 3\']\n >>> \' 1 2 3 \'.split()\n [\'1\', \'2\', \'3\']\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example:\n\n >>> \'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()\n [\'ab c\', \'\', \'de fg\', \'kl\']\n >>> \'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines(keepends=True)\n [\'ab c\\n\', \'\\n\', \'de fg\\r\', \'kl\\r\\n\']\n\n Unlike "split()" when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line:\n\n >>> "".splitlines()\n []\n >>> "One line\\n".splitlines()\n [\'One line\']\n\n For comparison, "split(\'\\n\')" gives:\n\n >>> \'\'.split(\'\\n\')\n [\'\']\n >>> \'Two lines\\n\'.split(\'\\n\')\n [\'Two lines\', \'\']\n\nstr.startswith(prefix[, start[, end]])\n\n Return "True" if string starts with the *prefix*, otherwise return\n "False". *prefix* can also be a tuple of prefixes to look for.\n With optional *start*, test string beginning at that position.\n With optional *end*, stop comparing string at that position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or "None", the *chars*\n argument defaults to removing whitespace. The *chars* argument is\n not a prefix or suffix; rather, all combinations of its values are\n stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n "s.swapcase().swapcase() == s".\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n For example:\n\n >>> \'Hello world\'.title()\n \'Hello World\'\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or "None". Unmapped\n characters are left untouched. Characters mapped to "None" are\n deleted.\n\n You can use "str.maketrans()" to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom\n character mapping codec using the "codecs" module (see\n "encodings.cp1251" for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that "str.upper().isupper()" might be\n "False" if "s" contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return a copy of the string left filled with ASCII "\'0\'" digits to\n make a string of length *width*. A leading sign prefix ("\'+\'"/"\'-\'"\n is handled by inserting the padding *after* the sign character\n rather than before. The original string is returned if *width* is\n less than or equal to "len(s)".\n\n For example:\n\n >>> "42".zfill(5)\n \'00042\'\n >>> "-42".zfill(5)\n \'-0042\'\n', + 'strings': u'\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "R" | "U"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the "stringprefix" or "bytesprefix"\nand the rest of the literal. The source character set is defined by\nthe encoding declaration; it is UTF-8 if no encoding declaration is\ngiven in the source file; see section *Encoding declarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes ("\'") or double quotes ("""). They can also be enclosed\nin matching groups of three single or double quotes (these are\ngenerally referred to as *triple-quoted strings*). The backslash\n("\\") character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with "\'b\'" or "\'B\'"; they produce\nan instance of the "bytes" type instead of the "str" type. They may\nonly contain ASCII characters; bytes with a numeric value of 128 or\ngreater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix string literals with a\n"u" prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter "\'r\'" or "\'R\'"; such strings are called *raw strings* and treat\nbackslashes as literal characters. As a result, in string literals,\n"\'\\U\'" and "\'\\u\'" escapes in raw strings are not treated specially.\nGiven that Python 2.x\'s raw unicode literals behave differently than\nPython 3.x\'s the "\'ur\'" syntax is not supported.\n\nNew in version 3.3: The "\'rb\'" prefix of raw bytes literals has been\nadded as a synonym of "\'br\'".\n\nNew in version 3.3: Support for the unicode legacy literal\n("u\'value\'") was reintroduced to simplify the maintenance of dual\nPython 2.x and 3.x codebases. See **PEP 414** for more information.\n\nIn triple-quoted literals, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the literal. (A "quote" is the character used to open the\nliteral, i.e. either "\'" or """.)\n\nUnless an "\'r\'" or "\'R\'" prefix is present, escape sequences in string\nand bytes literals are interpreted according to rules similar to those\nused by Standard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\newline" | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| "\\\\" | Backslash ("\\") | |\n+-------------------+-----------------------------------+---------+\n| "\\\'" | Single quote ("\'") | |\n+-------------------+-----------------------------------+---------+\n| "\\"" | Double quote (""") | |\n+-------------------+-----------------------------------+---------+\n| "\\a" | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| "\\b" | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| "\\f" | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| "\\n" | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| "\\r" | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| "\\t" | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| "\\v" | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| "\\ooo" | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| "\\xhh" | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\N{name}" | Character named *name* in the | (4) |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| "\\uxxxx" | Character with 16-bit hex value | (5) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| "\\Uxxxxxxxx" | Character with 32-bit hex value | (6) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the\n byte with the given value. In a string literal, these escapes\n denote a Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can\n be encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way. Exactly eight\n hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the result*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw literal, quotes can be escaped with a backslash, but the\nbackslash remains in the result; for example, "r"\\""" is a valid\nstring literal consisting of two characters: a backslash and a double\nquote; "r"\\"" is not a valid string literal (even a raw string cannot\nend in an odd number of backslashes). Specifically, *a raw literal\ncannot end in a single backslash* (since the backslash would escape\nthe following quote character). Note also that a single backslash\nfollowed by a newline is interpreted as those two characters as part\nof the literal, *not* as a line continuation.\n', + 'subscriptions': u'\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription\n(lists or dictionaries for example). User-defined objects can support\nsubscription by defining a "__getitem__()" method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a "__getitem__()"\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that "x[-1]" selects the last item of "x").\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero). Since the support for\nnegative indices and slicing occurs in the object\'s "__getitem__()"\nmethod, subclasses overriding this method will need to explicitly add\nthat support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', + 'truth': u'\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an "if" or\n"while" condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* "None"\n\n* "False"\n\n* zero of any numeric type, for example, "0", "0.0", "0j".\n\n* any empty sequence, for example, "\'\'", "()", "[]".\n\n* any empty mapping, for example, "{}".\n\n* instances of user-defined classes, if the class defines a\n "__bool__()" or "__len__()" method, when that method returns the\n integer zero or "bool" value "False". [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn "0" or "False" for false and "1" or "True" for true, unless\notherwise stated. (Important exception: the Boolean operations "or"\nand "and" always return one of their operands.)\n', + 'try': u'\nThe "try" statement\n*******************\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n', + 'types': u'\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name "None". It\n is used to signify the absence of a value in many situations, e.g.,\n it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n "NotImplemented". Numeric methods and rich comparison methods\n should return this value if they do not implement the operation for\n the operands provided. (The interpreter will then try the\n reflected operation, or some other fallback, depending on the\n operator.) Its truth value is true.\n\n See *Implementing the arithmetic operations* for more details.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal "..." or the\n built-in name "Ellipsis". Its truth value is true.\n\n"numbers.Number"\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n "numbers.Integral"\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers ("int")\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans ("bool")\n These represent the truth values False and True. The two\n objects representing the values "False" and "True" are the\n only Boolean objects. The Boolean type is a subtype of the\n integer type, and Boolean values behave like the values 0 and\n 1, respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ""False"" or\n ""True"" are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n "numbers.Real" ("float")\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these are\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n "numbers.Complex" ("complex")\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number "z" can be retrieved through the read-only\n attributes "z.real" and "z.imag".\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function "len()" returns the number of items\n of a sequence. When the length of a sequence is *n*, the index set\n contains the numbers 0, 1, ..., *n*-1. Item *i* of sequence *a* is\n selected by "a[i]".\n\n Sequences also support slicing: "a[i:j]" selects all items with\n index *k* such that *i* "<=" *k* "<" *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: "a[i:j:k]" selects all items of *a* with index *x* where\n "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode code\n points. All the code points in the range "U+0000 - U+10FFFF"\n can be represented in a string. Python doesn\'t have a "char"\n type; instead, every code point in the string is represented\n as a string object with length "1". The built-in function\n "ord()" converts a code point from its string form to an\n integer in the range "0 - 10FFFF"; "chr()" converts an\n integer in the range "0 - 10FFFF" to the corresponding length\n "1" string object. "str.encode()" can be used to convert a\n "str" to "bytes" using the given text encoding, and\n "bytes.decode()" can be used to achieve the opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like "b\'abc\'") and the built-in function\n "bytes()" can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the "decode()"\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and "del" (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in "bytearray()" constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module "array" provides an additional example of a\n mutable sequence type, as does the "collections" module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function "len()"\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., "1" and\n "1.0"), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n "set()" constructor and can be modified afterwards by several\n methods, such as "add()".\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in "frozenset()" constructor. As a frozenset is immutable\n and *hashable*, it can be used again as an element of another\n set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation "a[k]" selects the item indexed by "k"\n from the mapping "a"; this can be used in expressions and as the\n target of assignments or "del" statements. The built-in function\n "len()" returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., "1" and "1.0")\n then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the "{...}"\n notation (see section *Dictionary displays*).\n\n The extension modules "dbm.ndbm" and "dbm.gnu" provide\n additional examples of mapping types, as does the "collections"\n module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | "__doc__" | The function\'s documentation | Writable |\n | | string, or "None" if | |\n | | unavailable; not inherited by | |\n | | subclasses | |\n +---------------------------+---------------------------------+-------------+\n | "__name__" | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__qualname__" | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n | | function was defined in, or | |\n | | "None" if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or "None" if no arguments have | |\n | | a default value | |\n +---------------------------+---------------------------------+-------------+\n | "__code__" | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | "__dict__" | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n | | contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | "__annotations__" | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | and "\'return\'" for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | "__kwdefaults__" | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: "__self__" is the class instance\n object, "__func__" is the function object; "__doc__" is the\n method\'s documentation (same as "__func__.__doc__"); "__name__"\n is the method name (same as "__func__.__name__"); "__module__"\n is the name of the module the method was defined in, or "None"\n if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its "__self__" attribute is the instance, and the method object\n is said to be bound. The new method\'s "__func__" attribute is\n the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the "__func__"\n attribute of the new instance is not the original method object\n but its "__func__" attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its "__self__" attribute\n is the class itself, and its "__func__" attribute is the\n function object underlying the class method.\n\n When an instance method object is called, the underlying\n function ("__func__") is called, inserting the class instance\n ("__self__") in front of the argument list. For instance, when\n "C" is a class which contains a definition for a function "f()",\n and "x" is an instance of "C", calling "x.f(1)" is equivalent to\n calling "C.f(x, 1)".\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in "__self__" will actually\n be the class itself, so that calling either "x.f(1)" or "C.f(1)"\n is equivalent to calling "f(C,1)" where "f" is the underlying\n function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "iterator.__next__()" method will cause the\n function to execute until it provides a value using the "yield"\n statement. When the function executes a "return" statement or\n falls off the end, a "StopIteration" exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are "len()" and "math.sin()"\n ("math" is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: "__doc__" is the function\'s documentation\n string, or "None" if unavailable; "__name__" is the function\'s\n name; "__self__" is set to "None" (but see the next item);\n "__module__" is the name of the module the function was defined\n in or "None" if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n "alist.append()", assuming *alist* is a list object. In this\n case, the special read-only attribute "__self__" is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override "__new__()". The arguments of the\n call are passed to "__new__()" and, in the typical case, to\n "__init__()" to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a "__call__()" method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the "import"\n statement (see "import"), or by calling functions such as\n "importlib.import_module()" and built-in "__import__()". A module\n object has a namespace implemented by a dictionary object (this is\n the dictionary referenced by the "__globals__" attribute of\n functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., "m.x" is equivalent\n to "m.__dict__["x"]". A module object does not contain the code\n object used to initialize the module (since it isn\'t needed once\n the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s name;\n "__doc__" is the module\'s documentation string, or "None" if\n unavailable; "__file__" is the pathname of the file from which the\n module was loaded, if it was loaded from a file. The "__file__"\n attribute may be missing for certain types of modules, such as C\n modules that are statically linked into the interpreter; for\n extension modules loaded dynamically from a shared library, it is\n the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., "C.x" is translated to\n "C.__dict__["x"]" (although there are a number of hooks which allow\n for other means of locating attributes). When the attribute name is\n not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n https://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n class method object, it is transformed into an instance method\n object whose "__self__" attributes is "C". When it would yield a\n static method object, it is transformed into the object wrapped by\n the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its "__dict__".\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: "__name__" is the class name; "__module__" is\n the module name in which the class was defined; "__dict__" is the\n dictionary containing the class\'s namespace; "__bases__" is a tuple\n (possibly empty or a singleton) containing the base classes, in the\n order of their occurrence in the base class list; "__doc__" is the\n class\'s documentation string, or None if undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose "__self__" attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s "__dict__".\n If no class attribute is found, and the object\'s class has a\n "__getattr__()" method, that is called to satisfy the lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n "__setattr__()" or "__delattr__()" method, this is called instead\n of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: "__dict__" is the attribute dictionary;\n "__class__" is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the "open()" built-in function,\n and also "os.popen()", "os.fdopen()", and the "makefile()" method\n of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n "io.TextIOBase" abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function name;\n "co_argcount" is the number of positional arguments (including\n arguments with default values); "co_nlocals" is the number of\n local variables used by the function (including arguments);\n "co_varnames" is a tuple containing the names of the local\n variables (starting with the argument names); "co_cellvars" is a\n tuple containing the names of local variables that are\n referenced by nested functions; "co_freevars" is a tuple\n containing the names of free variables; "co_code" is a string\n representing the sequence of bytecode instructions; "co_consts"\n is a tuple containing the literals used by the bytecode;\n "co_names" is a tuple containing the names used by the bytecode;\n "co_filename" is the filename from which the code was compiled;\n "co_firstlineno" is the first line number of the function;\n "co_lnotab" is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); "co_stacksize" is the required stack size\n (including local variables); "co_flags" is an integer encoding a\n number of flags for the interpreter.\n\n The following flag bits are defined for "co_flags": bit "0x04"\n is set if the function uses the "*arguments" syntax to accept an\n arbitrary number of positional arguments; bit "0x08" is set if\n the function uses the "**keywords" syntax to accept arbitrary\n keyword arguments; bit "0x20" is set if the function is a\n generator.\n\n Future feature declarations ("from __future__ import division")\n also use bits in "co_flags" to indicate whether a code object\n was compiled with a particular feature enabled: bit "0x2000" is\n set if the function was compiled with future division enabled;\n bits "0x10" and "0x1000" were used in earlier versions of\n Python.\n\n Other bits in "co_flags" are reserved for internal use.\n\n If a code object represents a function, the first item in\n "co_consts" is the documentation string of the function, or\n "None" if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: "f_back" is to the previous stack\n frame (towards the caller), or "None" if this is the bottom\n stack frame; "f_code" is the code object being executed in this\n frame; "f_locals" is the dictionary used to look up local\n variables; "f_globals" is used for global variables;\n "f_builtins" is used for built-in (intrinsic) names; "f_lasti"\n gives the precise instruction (this is an index into the\n bytecode string of the code object).\n\n Special writable attributes: "f_trace", if not "None", is a\n function called at the start of each source code line (this is\n used by the debugger); "f_lineno" is the current line number of\n the frame --- writing to this from within a trace function jumps\n to the given line (only for the bottom-most frame). A debugger\n can implement a Jump command (aka Set Next Statement) by writing\n to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n "RuntimeError" is raised if the frame is currently executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by "sys.exc_info()". When the program contains no\n suitable handler, the stack trace is written (nicely formatted)\n to the standard error stream; if the interpreter is interactive,\n it is also made available to the user as "sys.last_traceback".\n\n Special read-only attributes: "tb_next" is the next level in the\n stack trace (towards the frame where the exception occurred), or\n "None" if there is no next level; "tb_frame" points to the\n execution frame of the current level; "tb_lineno" gives the line\n number where the exception occurred; "tb_lasti" indicates the\n precise instruction. The line number and last instruction in\n the traceback may differ from the line number of its frame\n object if the exception occurred in a "try" statement with no\n matching except clause or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for "__getitem__()"\n methods. They are also created by the built-in "slice()"\n function.\n\n Special read-only attributes: "start" is the lower bound; "stop"\n is the upper bound; "step" is the step value; each is "None" if\n omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n "staticmethod()" constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in "classmethod()" constructor.\n', + 'typesfunctions': u'\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: "func(argument-list)".\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', + 'typesmapping': u'\nMapping Types --- "dict"\n************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin "list", "set", and "tuple" classes, and the "collections" module.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as "1" and "1.0") then they can be used interchangeably to index\nthe same dictionary entry. (Note however, that since computers store\nfloating-point numbers as approximations it is usually unwise to use\nthem as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of "key:\nvalue" pairs within braces, for example: "{\'jack\': 4098, \'sjoerd\':\n4127}" or "{4098: \'jack\', 4127: \'sjoerd\'}", or by the "dict"\nconstructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterable*\n object. Each item in the iterable must itself be an iterable with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to "{"one": 1, "two": 2, "three": 3}":\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a "KeyError" if\n *key* is not in the map.\n\n If a subclass of dict defines a method "__missing__()" and *key*\n is not present, the "d[key]" operation calls that method with\n the key *key* as argument. The "d[key]" operation then returns\n or raises whatever is returned or raised by the\n "__missing__(key)" call. No other operations or methods invoke\n "__missing__()". If "__missing__()" is not defined, "KeyError"\n is raised. "__missing__()" must be a method; it cannot be an\n instance variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n The example above shows part of the implementation of\n "collections.Counter". A different "__missing__" method is used\n by "collections.defaultdict".\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n key not in d\n\n Equivalent to "not key in d".\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iter(d.keys())".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n "fromkeys()" is a class method that returns a new dictionary.\n *value* defaults to "None".\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to "None", so\n that this method never raises a "KeyError".\n\n items()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a "KeyError" is raised.\n\n popitem()\n\n Remove and return an arbitrary "(key, value)" pair from the\n dictionary.\n\n "popitem()" is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling "popitem()" raises a "KeyError".\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to "None".\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return "None".\n\n "update()" accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: "d.update(red=1,\n blue=2)".\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also: "types.MappingProxyType" can be used to create a read-only\n view of a "dict".\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.keys()", "dict.values()" and\n"dict.items()" are *view objects*. They provide a dynamic view on the\ndictionary\'s entries, which means that when the dictionary changes,\nthe view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of "(key, value)") in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of "(value, key)" pairs using\n "zip()": "pairs = zip(d.values(), d.keys())". Another way to\n create the same list is "pairs = [(v, k) for (k, v) in d.items()]".\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a "RuntimeError" or fail to iterate over all entries.\n\nx in dictview\n\n Return "True" if *x* is in the underlying dictionary\'s keys, values\n or items (in the latter case, *x* should be a "(key, value)"\n tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that "(key, value)" pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class "collections.abc.Set" are available (for example, "==",\n"<", or "^").\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', + 'typesmethods': u'\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as "append()" on lists)\nand class instance methods. Built-in methods are described with the\ntypes that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the "self"\nargument to the argument list. Bound methods have two special read-\nonly attributes: "m.__self__" is the object on which the method\noperates, and "m.__func__" is the function implementing the method.\nCalling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to\ncalling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object ("meth.__func__"), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an "AttributeError" being raised. In\norder to set a method attribute, you need to explicitly set it on the\nunderlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', + 'typesmodules': u'\nModules\n*******\n\nThe only special operation on a module is attribute access: "m.name",\nwhere *m* is a module and *name* accesses a name defined in *m*\'s\nsymbol table. Module attributes can be assigned to. (Note that the\n"import" statement is not, strictly speaking, an operation on a module\nobject; "import foo" does not require a module object named *foo* to\nexist, rather it requires an (external) *definition* for a module\nnamed *foo* somewhere.)\n\nA special attribute of every module is "__dict__". This is the\ndictionary containing the module\'s symbol table. Modifying this\ndictionary will actually change the module\'s symbol table, but direct\nassignment to the "__dict__" attribute is not possible (you can write\n"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but you can\'t\nwrite "m.__dict__ = {}"). Modifying "__dict__" directly is not\nrecommended.\n\nModules built into the interpreter are written like this: "". If loaded from a file, they are written as\n"".\n', + 'typesseq': u'\nSequence Types --- "list", "tuple", "range"\n*******************************************\n\nThere are three basic sequence types: lists, tuples, and range\nobjects. Additional sequence types tailored for processing of *binary\ndata* and *text strings* are described in dedicated sections.\n\n\nCommon Sequence Operations\n==========================\n\nThe operations in the following table are supported by most sequence\ntypes, both mutable and immutable. The "collections.abc.Sequence" ABC\nis provided to make it easier to correctly implement these operations\non custom sequence types.\n\nThis table lists the sequence operations sorted in ascending priority.\nIn the table, *s* and *t* are sequences of the same type, *n*, *i*,\n*j* and *k* are integers and *x* is an arbitrary object that meets any\ntype and value restrictions imposed by *s*.\n\nThe "in" and "not in" operations have the same priorities as the\ncomparison operations. The "+" (concatenation) and "*" (repetition)\noperations have the same priority as the corresponding numeric\noperations.\n\n+----------------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+============================+==================================+============+\n| "x in s" | "True" if an item of *s* is | (1) |\n| | equal to *x*, else "False" | |\n+----------------------------+----------------------------------+------------+\n| "x not in s" | "False" if an item of *s* is | (1) |\n| | equal to *x*, else "True" | |\n+----------------------------+----------------------------------+------------+\n| "s + t" | the concatenation of *s* and *t* | (6)(7) |\n+----------------------------+----------------------------------+------------+\n| "s * n" or "n * s" | *n* shallow copies of *s* | (2)(7) |\n| | concatenated | |\n+----------------------------+----------------------------------+------------+\n| "s[i]" | *i*th item of *s*, origin 0 | (3) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+----------------------------+----------------------------------+------------+\n| "len(s)" | length of *s* | |\n+----------------------------+----------------------------------+------------+\n| "min(s)" | smallest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "max(s)" | largest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) |\n| | *x* in *s* (at or after index | |\n| | *i* and before index *j*) | |\n+----------------------------+----------------------------------+------------+\n| "s.count(x)" | total number of occurrences of | |\n| | *x* in *s* | |\n+----------------------------+----------------------------------+------------+\n\nSequences of the same type also support comparisons. In particular,\ntuples and lists are compared lexicographically by comparing\ncorresponding elements. This means that to compare equal, every\nelement must compare equal and the two sequences must be of the same\ntype and have the same length. (For full details see *Comparisons* in\nthe language reference.)\n\nNotes:\n\n1. While the "in" and "not in" operations are used only for simple\n containment testing in the general case, some specialised sequences\n (such as "str", "bytes" and "bytearray") also use them for\n subsequence testing:\n\n >>> "gg" in "eggs"\n True\n\n2. Values of *n* less than "0" are treated as "0" (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that "[[]]" is a one-element list containing\n an empty list, so all three elements of "[[]] * 3" are (pointers\n to) this single empty list. Modifying any of the elements of\n "lists" modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of\n the string: "len(s) + i" or "len(s) + j" is substituted. But note\n that "-0" is still "0".\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that "i <= k < j". If *i* or *j* is\n greater than "len(s)", use "len(s)". If *i* is omitted or "None",\n use "0". If *j* is omitted or "None", use "len(s)". If *i* is\n greater than or equal to *j*, the slice is empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index "x = i + n*k" such that "0 <= n <\n (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k",\n "i+3*k" and so on, stopping when *j* is reached (but never\n including *j*). If *i* or *j* is greater than "len(s)", use\n "len(s)". If *i* or *j* are omitted or "None", they become "end"\n values (which end depends on the sign of *k*). Note, *k* cannot be\n zero. If *k* is "None", it is treated like "1".\n\n6. Concatenating immutable sequences always results in a new\n object. This means that building up a sequence by repeated\n concatenation will have a quadratic runtime cost in the total\n sequence length. To get a linear runtime cost, you must switch to\n one of the alternatives below:\n\n * if concatenating "str" objects, you can build a list and use\n "str.join()" at the end or else write to a "io.StringIO" instance\n and retrieve its value when complete\n\n * if concatenating "bytes" objects, you can similarly use\n "bytes.join()" or "io.BytesIO", or you can do in-place\n concatenation with a "bytearray" object. "bytearray" objects are\n mutable and have an efficient overallocation mechanism\n\n * if concatenating "tuple" objects, extend a "list" instead\n\n * for other types, investigate the relevant class documentation\n\n7. Some sequence types (such as "range") only support item\n sequences that follow specific patterns, and hence don\'t support\n sequence concatenation or repetition.\n\n8. "index" raises "ValueError" when *x* is not found in *s*. When\n supported, the additional arguments to the index method allow\n efficient searching of subsections of the sequence. Passing the\n extra arguments is roughly equivalent to using "s[i:j].index(x)",\n only without copying any data and with the returned index being\n relative to the start of the sequence rather than the start of the\n slice.\n\n\nImmutable Sequence Types\n========================\n\nThe only operation that immutable sequence types generally implement\nthat is not also implemented by mutable sequence types is support for\nthe "hash()" built-in.\n\nThis support allows immutable sequences, such as "tuple" instances, to\nbe used as "dict" keys and stored in "set" and "frozenset" instances.\n\nAttempting to hash an immutable sequence that contains unhashable\nvalues will result in "TypeError".\n\n\nMutable Sequence Types\n======================\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | appends *x* to the end of the | |\n| | sequence (same as | |\n| | "s[len(s):len(s)] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n| | as "del s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n| | (same as "s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(t)" | extends *s* with the contents of | |\n| | *t* (same as "s[len(s):len(s)] = | |\n| | t") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | "s[i:i] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n| | where "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n\n\nLists\n=====\n\nLists are mutable sequences, typically used to store collections of\nhomogeneous items (where the precise degree of similarity will vary by\napplication).\n\nclass class list([iterable])\n\n Lists may be constructed in several ways:\n\n * Using a pair of square brackets to denote the empty list: "[]"\n\n * Using square brackets, separating items with commas: "[a]",\n "[a, b, c]"\n\n * Using a list comprehension: "[x for x in iterable]"\n\n * Using the type constructor: "list()" or "list(iterable)"\n\n The constructor builds a list whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a list, a copy is made and\n returned, similar to "iterable[:]". For example, "list(\'abc\')"\n returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" returns "[1, 2,\n 3]". If no argument is given, the constructor creates a new empty\n list, "[]".\n\n Many other operations also produce lists, including the "sorted()"\n built-in.\n\n Lists implement all of the *common* and *mutable* sequence\n operations. Lists also provide the following additional method:\n\n sort(*, key=None, reverse=None)\n\n This method sorts the list in place, using only "<" comparisons\n between items. Exceptions are not suppressed - if any comparison\n operations fail, the entire sort operation will fail (and the\n list will likely be left in a partially modified state).\n\n "sort()" accepts two arguments that can only be passed by\n keyword (*keyword-only arguments*):\n\n *key* specifies a function of one argument that is used to\n extract a comparison key from each list element (for example,\n "key=str.lower"). The key corresponding to each item in the list\n is calculated once and then used for the entire sorting process.\n The default value of "None" means that list items are sorted\n directly without calculating a separate key value.\n\n The "functools.cmp_to_key()" utility is available to convert a\n 2.x style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n This method modifies the sequence in place for economy of space\n when sorting a large sequence. To remind users that it operates\n by side effect, it does not return the sorted sequence (use\n "sorted()" to explicitly request a new sorted list instance).\n\n The "sort()" method is guaranteed to be stable. A sort is\n stable if it guarantees not to change the relative order of\n elements that compare equal --- this is helpful for sorting in\n multiple passes (for example, sort by department, then by salary\n grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises "ValueError" if it can detect\n that the list has been mutated during a sort.\n\n\nTuples\n======\n\nTuples are immutable sequences, typically used to store collections of\nheterogeneous data (such as the 2-tuples produced by the "enumerate()"\nbuilt-in). Tuples are also used for cases where an immutable sequence\nof homogeneous data is needed (such as allowing storage in a "set" or\n"dict" instance).\n\nclass class tuple([iterable])\n\n Tuples may be constructed in a number of ways:\n\n * Using a pair of parentheses to denote the empty tuple: "()"\n\n * Using a trailing comma for a singleton tuple: "a," or "(a,)"\n\n * Separating items with commas: "a, b, c" or "(a, b, c)"\n\n * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)"\n\n The constructor builds a tuple whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a tuple, it is returned\n unchanged. For example, "tuple(\'abc\')" returns "(\'a\', \'b\', \'c\')"\n and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is\n given, the constructor creates a new empty tuple, "()".\n\n Note that it is actually the comma which makes a tuple, not the\n parentheses. The parentheses are optional, except in the empty\n tuple case, or when they are needed to avoid syntactic ambiguity.\n For example, "f(a, b, c)" is a function call with three arguments,\n while "f((a, b, c))" is a function call with a 3-tuple as the sole\n argument.\n\n Tuples implement all of the *common* sequence operations.\n\nFor heterogeneous collections of data where access by name is clearer\nthan access by index, "collections.namedtuple()" may be a more\nappropriate choice than a simple tuple object.\n\n\nRanges\n======\n\nThe "range" type represents an immutable sequence of numbers and is\ncommonly used for looping a specific number of times in "for" loops.\n\nclass class range(stop)\nclass class range(start, stop[, step])\n\n The arguments to the range constructor must be integers (either\n built-in "int" or any object that implements the "__index__"\n special method). If the *step* argument is omitted, it defaults to\n "1". If the *start* argument is omitted, it defaults to "0". If\n *step* is zero, "ValueError" is raised.\n\n For a positive *step*, the contents of a range "r" are determined\n by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] <\n stop".\n\n For a negative *step*, the contents of the range are still\n determined by the formula "r[i] = start + step*i", but the\n constraints are "i >= 0" and "r[i] > stop".\n\n A range object will be empty if "r[0]" does not meet the value\n constraint. Ranges do support negative indices, but these are\n interpreted as indexing from the end of the sequence determined by\n the positive indices.\n\n Ranges containing absolute values larger than "sys.maxsize" are\n permitted but some features (such as "len()") may raise\n "OverflowError".\n\n Range examples:\n\n >>> list(range(10))\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n >>> list(range(1, 11))\n [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n >>> list(range(0, 30, 5))\n [0, 5, 10, 15, 20, 25]\n >>> list(range(0, 10, 3))\n [0, 3, 6, 9]\n >>> list(range(0, -10, -1))\n [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n >>> list(range(0))\n []\n >>> list(range(1, 0))\n []\n\n Ranges implement all of the *common* sequence operations except\n concatenation and repetition (due to the fact that range objects\n can only represent sequences that follow a strict pattern and\n repetition and concatenation will usually violate that pattern).\n\nThe advantage of the "range" type over a regular "list" or "tuple" is\nthat a "range" object will always take the same (small) amount of\nmemory, no matter the size of the range it represents (as it only\nstores the "start", "stop" and "step" values, calculating individual\nitems and subranges as needed).\n\nRange objects implement the "collections.abc.Sequence" ABC, and\nprovide features such as containment tests, element index lookup,\nslicing and support for negative indices (see *Sequence Types ---\nlist, tuple, range*):\n\n>>> r = range(0, 20, 2)\n>>> r\nrange(0, 20, 2)\n>>> 11 in r\nFalse\n>>> 10 in r\nTrue\n>>> r.index(10)\n5\n>>> r[5]\n10\n>>> r[:5]\nrange(0, 10, 2)\n>>> r[-1]\n18\n\nTesting range objects for equality with "==" and "!=" compares them as\nsequences. That is, two range objects are considered equal if they\nrepresent the same sequence of values. (Note that two range objects\nthat compare equal might have different "start", "stop" and "step"\nattributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3,\n2) == range(0, 4, 2)".)\n\nChanged in version 3.2: Implement the Sequence ABC. Support slicing\nand negative indices. Test "int" objects for membership in constant\ntime instead of iterating through all items.\n\nChanged in version 3.3: Define \'==\' and \'!=\' to compare range objects\nbased on the sequence of values they define (instead of comparing\nbased on object identity).\n\nNew in version 3.3: The "start", "stop" and "step" attributes.\n', + 'typesseq-mutable': u'\nMutable Sequence Types\n**********************\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | appends *x* to the end of the | |\n| | sequence (same as | |\n| | "s[len(s):len(s)] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n| | as "del s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n| | (same as "s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(t)" | extends *s* with the contents of | |\n| | *t* (same as "s[len(s):len(s)] = | |\n| | t") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | "s[i:i] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n| | where "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n', + 'unary': u'\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary "-" (minus) operator yields the negation of its numeric\nargument.\n\nThe unary "+" (plus) operator yields its numeric argument unchanged.\n\nThe unary "~" (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of "x" is defined as\n"-(x+1)". It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n"TypeError" exception is raised.\n', + 'while': u'\nThe "while" statement\n*********************\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n', + 'with': u'\nThe "with" statement\n********************\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', + 'yield': u'\nThe "yield" statement\n*********************\n\n yield_stmt ::= yield_expression\n\nA "yield" statement is semantically equivalent to a *yield\nexpression*. The yield statement can be used to omit the parentheses\nthat would otherwise be required in the equivalent yield expression\nstatement. For example, the yield statements\n\n yield \n yield from \n\nare equivalent to the yield expression statements\n\n (yield )\n (yield from )\n\nYield expressions and statements are only used when defining a\n*generator* function, and are only used in the body of the generator\nfunction. Using yield in a function definition is sufficient to cause\nthat definition to create a generator function instead of a normal\nfunction.\n\nFor full details of "yield" semantics, refer to the *Yield\nexpressions* section.\n'} -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:05:54 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:05:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Post-release_u?= =?utf-8?q?pdates_for_Python_3=2E4=2E3rc1=2E?= Message-ID: <20150208220543.52858.48005@psf.io> https://hg.python.org/cpython/rev/70449fbe5d4c changeset: 94561:70449fbe5d4c branch: 3.4 user: Larry Hastings date: Sun Feb 08 14:04:36 2015 -0800 summary: Post-release updates for Python 3.4.3rc1. files: Include/patchlevel.h | 2 +- Misc/NEWS | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.4.3rc1" +#define PY_VERSION "3.4.3rc1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,17 @@ Python News +++++++++++ +What's New in Python 3.4.3? +=========================== + +Release date: 2015-02-22 + +Core and Builtins +----------------- + +Library +------- + What's New in Python 3.4.3rc1? ============================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:05:53 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:05:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Added_tag_v3?= =?utf-8?q?=2E4=2E3rc1_for_changeset_69dd528ca625?= Message-ID: <20150208220543.108395.42639@psf.io> https://hg.python.org/cpython/rev/a2077b58422e changeset: 94560:a2077b58422e branch: 3.4 user: Larry Hastings date: Sat Feb 07 16:04:55 2015 -0800 summary: Added tag v3.4.3rc1 for changeset 69dd528ca625 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -142,3 +142,4 @@ c0e311e010fcb5bae8d87ca22051cd0845ea0ca0 v3.4.1 8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 +69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:05:53 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:05:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Version_bump_f?= =?utf-8?b?b3IgMy40LjNyYzEu?= Message-ID: <20150208220542.108389.70427@psf.io> https://hg.python.org/cpython/rev/4815253bd027 changeset: 94558:4815253bd027 branch: 3.4 user: Larry Hastings date: Sat Feb 07 16:00:45 2015 -0800 summary: Version bump for 3.4.3rc1. files: Include/patchlevel.h | 8 ++++---- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-3.4.spec | 2 +- README | 6 +++--- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 4 -#define PY_MICRO_VERSION 2 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 +#define PY_MICRO_VERSION 3 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.4.2+" +#define PY_VERSION "3.4.3rc1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.4.2" +__version__ = "3.4.3rc1" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.4.2" +IDLE_VERSION = "3.4.3rc1" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -6,7 +6,7 @@ What's New in Python 3.4.3rc1? ============================== -Release date: TBA +Release date: 2015-02-08 Core and Builtins ----------------- diff --git a/Misc/RPM/python-3.4.spec b/Misc/RPM/python-3.4.spec --- a/Misc/RPM/python-3.4.spec +++ b/Misc/RPM/python-3.4.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.4.2 +%define version 3.4.3rc1 %define libvers 3.4 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Python version 3.4.2 -============================ +This is Python version 3.4.3rc1 +=============================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Python Software Foundation. All rights reserved. @@ -175,7 +175,7 @@ --------------------------------- Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013, 2014 Python Software Foundation. All rights reserved. +2012, 2013, 2014, 2015 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:05:54 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:05:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_a_copyrigh?= =?utf-8?q?t_notice_that_still_said_2014=2E?= Message-ID: <20150208220543.50313.79586@psf.io> https://hg.python.org/cpython/rev/69dd528ca625 changeset: 94559:69dd528ca625 branch: 3.4 tag: v3.4.3rc1 user: Larry Hastings date: Sat Feb 07 16:04:22 2015 -0800 summary: Fix a copyright notice that still said 2014. files: Doc/README.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/README.txt b/Doc/README.txt --- a/Doc/README.txt +++ b/Doc/README.txt @@ -128,7 +128,7 @@ as long as you don't change or remove the copyright notice: ---------------------------------------------------------------------- -Copyright (c) 2000-2014 Python Software Foundation. +Copyright (c) 2000-2015 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:07:45 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:07:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Updated_pydoc_topics_data_?= =?utf-8?q?for_3=2E5=2E0a1_release=2E?= Message-ID: <20150208220745.108377.29752@psf.io> https://hg.python.org/cpython/rev/38f8adc173b6 changeset: 94562:38f8adc173b6 parent: 94553:7b493dbf944b user: Larry Hastings date: Sat Feb 07 15:55:34 2015 -0800 summary: Updated pydoc topics data for 3.5.0a1 release. files: Lib/pydoc_data/topics.py | 156 +++++++++++++------------- 1 files changed, 78 insertions(+), 78 deletions(-) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,79 +1,79 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Feb 10 04:20:03 2014 -topics = {'assert': '\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', - 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints "[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', - 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n', - 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', - 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the "__getattr__()" method). If this\nattribute is not available, the exception "AttributeError" is raised.\nOtherwise, the type and value of the object produced is determined by\nthe object. Multiple evaluations of the same attribute reference may\nyield different objects.\n', - 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', - 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe "*" (multiplication) operator yields the product of its arguments.\nThe arguments must either both be numbers, or one argument must be an\ninteger and the other must be a sequence. In the former case, the\nnumbers are converted to a common type and then multiplied together.\nIn the latter case, sequence repetition is performed; a negative\nrepetition factor yields an empty sequence.\n\nThe "/" (division) and "//" (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Division of integers yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the "ZeroDivisionError" exception.\n\nThe "%" (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n"ZeroDivisionError" exception. The arguments may be floating point\nnumbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals "4*0.7 +\n0.34".) The modulo operator always yields a result with the same sign\nas its second operand (or zero); the absolute value of the result is\nstrictly smaller than the absolute value of the second operand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: "x == (x//y)*y + (x%y)". Floor division and modulo are also\nconnected with the built-in function "divmod()": "divmod(x, y) ==\n(x//y, x%y)". [2].\n\nIn addition to performing the modulo operation on numbers, the "%"\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *printf-style String Formatting*.\n\nThe floor division operator, the modulo operator, and the "divmod()"\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the "abs()" function if appropriate.\n\nThe "+" (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe "-" (subtraction) operator yields the difference of its arguments.\nThe numeric arguments are first converted to a common type.\n', - 'bitwise': '\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe "&" operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe "^" operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe "|" operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', - 'bltin-code-objects': '\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin "compile()" function and can be extracted from function objects\nthrough their "__code__" attribute. See also the "code" module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the "exec()" or "eval()" built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', - 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the\n"Ellipsis" singleton.\n\nIt is written as "Ellipsis" or "...".\n', - 'bltin-null-object': '\nThe Null Object\n***************\n\nThis object is returned by functions that don\'t explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named "None" (a built-in name). "type(None)()" produces the\nsame singleton.\n\nIt is written as "None".\n', - 'bltin-type-objects': '\nType Objects\n************\n\nType objects represent the various object types. An object\'s type is\naccessed by the built-in function "type()". There are no special\noperations on types. The standard module "types" defines names for\nall standard built-in types.\n\nTypes are written like this: "".\n', - 'booleans': '\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: "False", "None", numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a "__bool__()" method.\n\nThe operator "not" yields "True" if its argument is false, "False"\notherwise.\n\nThe expression "x and y" first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression "x or y" first evaluates *x*; if *x* is true, its value\nis returned; otherwise, *y* is evaluated and the resulting value is\nreturned.\n\n(Note that neither "and" nor "or" restrict the value and type they\nreturn to "False" and "True", but rather return the last evaluated\nargument. This is sometimes useful, e.g., if "s" is a string that\nshould be replaced by a default value if it is empty, the expression\n"s or \'foo\'" yields the desired value. Because "not" has to invent a\nvalue anyway, it does not bother to return a value of the same type as\nits argument, so e.g., "not \'foo\'" yields "False", not "\'\'".)\n', - 'break': '\nThe "break" statement\n*********************\n\n break_stmt ::= "break"\n\n"break" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition within that\nloop.\n\nIt terminates the nearest enclosing loop, skipping the optional "else"\nclause if the loop has one.\n\nIf a "for" loop is terminated by "break", the loop control target\nkeeps its current value.\n\nWhen "break" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nloop.\n', - 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n', - 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a *function*) with a possibly\nempty series of *arguments*:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n"__call__()" method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal *parameter* lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a "TypeError" exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is "None", it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a "TypeError"\nexception is raised. Otherwise, the list of filled slots is used as\nthe argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use "PyArg_ParseTuple()" to parse\ntheir arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "*identifier" is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "**identifier" is present; in this case, that formal\nparameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax "*expression" appears in the function call, "expression"\nmust evaluate to an iterable. Elements from this iterable are treated\nas if they were additional positional arguments; if there are\npositional arguments *x1*, ..., *xN*, and "expression" evaluates to a\nsequence *y1*, ..., *yM*, this is equivalent to a call with M+N\npositional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the "*expression" syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the "**expression" argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the "*expression" syntax\nto be used in the same call, so in practice this confusion does not\narise.\n\nIf the syntax "**expression" appears in the function call,\n"expression" must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both "expression" and as an explicit keyword argument, a\n"TypeError" exception is raised.\n\nFormal parameters using the syntax "*identifier" or "**identifier"\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly "None", unless it raises an\nexception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a "return"\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a "__call__()" method; the effect is then the\n same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', - 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another. When cross-type\ncomparison is not supported, the comparison method returns\n"NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether a the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe "if", "while" and "for" statements implement traditional control\nflow constructs. "try" specifies exception handlers and/or cleanup\ncode for a group of statements, while the "with" statement allows the\nexecution of initialization and finalization code around a block of\ncode. Function and class definitions are also syntactically compound\nstatements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which "if" clause a following "else" clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n"print()" calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a "NEWLINE" possibly followed by a\n"DEDENT". Also note that optional continuation clauses always begin\nwith a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling "else"\' problem is solved in Python by\nrequiring nested "if" statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe "if" statement\n==================\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n\n\nThe "while" statement\n=====================\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n\n\nThe "for" statement\n===================\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there was no next\nitem.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe "try" statement\n===================\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be access via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n def f():\n try:\n 1/0\n finally:\n return 42\n\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe "with" statement\n====================\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', - 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', - 'continue': '\nThe "continue" statement\n************************\n\n continue_stmt ::= "continue"\n\n"continue" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition or "finally"\nclause within that loop. It continues with the next cycle of the\nnearest enclosing loop.\n\nWhen "continue" passes control out of a "try" statement with a\n"finally" clause, that "finally" clause is executed before really\nstarting the next loop cycle.\n', - 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the\n other is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', - 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])". As a special constraint on\n constructors, no value may be returned; doing so will cause a\n "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing "None" in\n "sys.last_traceback". Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n "gc" module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n', - 'debugger': '\n"pdb" --- The Python Debugger\n*****************************\n\nThe module "pdb" defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n"Pdb". This is currently undocumented but easily understood by reading\nthe source. The extension interface uses the modules "bdb" and "cmd".\n\nThe debugger\'s prompt is "(Pdb)". Typical usage to run a program under\ncontrol of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\nChanged in version 3.3: Tab-completion via the "readline" module is\navailable for commands and command arguments, e.g. the current global\nand local names are offered as arguments of the "p" command.\n\n"pdb.py" can also be invoked as a script to debug other scripts. For\nexample:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: "pdb.py" now accepts a "-c" option that executes\ncommands as if given in a ".pdbrc" file, see *Debugger Commands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the "continue" command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type "continue", or you can\n step through the statement using "step" or "next" (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module "__main__" is used. (See the\n explanation of the built-in "exec()" or "eval()" functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When "runeval()" returns, it returns the\n value of the expression. Otherwise this function is similar to\n "run()".\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When "runcall()" returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n "sys.last_traceback".\n\nThe "run*" functions and "set_trace()" are aliases for instantiating\nthe "Pdb" class and calling the method of the same name. If you want\nto access further features, you have to do this yourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n "Pdb" is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying "cmd.Cmd" class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n "continue" command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n"h(elp)" means that either "h" or "help" can be used to enter the help\ncommand (but not "he" or "hel", nor "H" or "Help" or "HELP").\nArguments to commands must be separated by whitespace (spaces or\ntabs). Optional arguments are enclosed in square brackets ("[]") in\nthe command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n("|").\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a "list" command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint ("!"). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by ";;".\n(A single ";" is not used as it is the separator for multiple commands\nin a line that is passed to the Python parser.) No intelligence is\napplied to separating the commands; the input is split at the first\n";;" pair, even if it is in the middle of a quoted string.\n\nIf a file ".pdbrc" exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ".pdbrc" can now contain commands that\ncontinue debugging, such as "continue" or "next". Previously, these\ncommands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. "help pdb"\n displays the full documentation (the docstring of the "pdb"\n module). Since the *command* argument must be an identifier, "help\n exec" must be entered to get help on the "!" command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on "sys.path". Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for "break".\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just "end" to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) p some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with "end"; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between "next" and "step"\n is that "step" stops inside a called function, while "next"\n executes called functions at (nearly) full speed, only stopping at\n the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a "for" loop or out\n of a "finally" clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With "." as argument, list 11 lines around the current line. With\n one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by "->". If an\n exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ">>", if it differs\n from the current line.\n\n New in version 3.2: The ">>" marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for "list".\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\n Note: "print()" can also be used, but is not a debugger command\n --- this executes the Python "print()" function.\n\npp expression\n\n Like the "p" command, except the value of the expression is pretty-\n printed using the "pprint" module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the "code" module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by "%1", "%2", and so on, while "%*" is replaced by all\n the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ".pdbrc" file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n "global" statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with "shlex" and the result is used as the new\n "sys.argv". History, breakpoints, actions and debugger options are\n preserved. "restart" is an alias for "run".\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module\n is determined by the "__name__" in the frame globals.\n', - 'del': '\nThe "del" statement\n*******************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a "global"\nstatement in the same code block. If the name is unbound, a\n"NameError" exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2: Previously it was illegal to delete a name\nfrom the local namespace if it occurs as a free variable in a nested\nblock.\n', - 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', - 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', - 'else': '\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', - 'exceptions': '\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', - 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, a\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\nglobal statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', - 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: "()".)\n', - 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, "077e010" is legal, and denotes the same number\nas "77e10". The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator "-" and the\nliteral "1".\n', - 'for': '\nThe "for" statement\n*******************\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there was no next\nitem.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', - 'formatstrings': '\nFormat String Syntax\n********************\n\nThe "str.format()" method and the "Formatter" class share the same\nsyntax for format strings (although in the case of "Formatter",\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n"{}". Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n"{{" and "}}".\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point "\'!\'", and a *format_spec*, which is\npreceded by a colon "\':\'". These specify a non-default format for the\nreplacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings "\'10\'" or\n"\':-]\'") within a format string. The *arg_name* can be followed by any\nnumber of index or attribute expressions. An expression of the form\n"\'.name\'" selects the named attribute using "getattr()", while an\nexpression of the form "\'[index]\'" does an index lookup using\n"__getitem__()".\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so "\'{} {}\'" is equivalent to "\'{0} {1}\'".\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the "__format__()"\nmethod of the value itself. However, in some cases it is desirable to\nforce a type to be formatted as a string, overriding its own\ndefinition of formatting. By converting the value to a string before\ncalling "__format__()", the normal formatting logic is bypassed.\n\nThree conversion flags are currently supported: "\'!s\'" which calls\n"str()" on the value, "\'!r\'" which calls "repr()" and "\'!a\'" which\ncalls "ascii()".\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in "format()" function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string ("""") produces\nthe same result as if you had called "str()" on the value. A non-empty\nformat string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nIf a valid *align* value is specified, it can be preceded by a *fill*\ncharacter that can be any character and defaults to a space if\nomitted. Note that it is not possible to use "{" and "}" as *fill*\nchar while using the "str.format()" method; this limitation however\ndoesn\'t affect the "format()" function.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'<\'" | Forces the field to be left-aligned within the available |\n +-----------+------------------------------------------------------------+\n | "\'>\'" | Forces the field to be right-aligned within the available |\n +-----------+------------------------------------------------------------+\n | "\'=\'" | Forces the padding to be placed after the sign (if any) |\n +-----------+------------------------------------------------------------+\n | "\'^\'" | Forces the field to be centered within the available |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'+\'" | indicates that a sign should be used for both positive as |\n +-----------+------------------------------------------------------------+\n | "\'-\'" | indicates that a sign should be used only for negative |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n +-----------+------------------------------------------------------------+\n\nThe "\'#\'" option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective "\'0b\'", "\'0o\'", or\n"\'0x\'" to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for "\'g\'" and "\'G\'"\nconversions, trailing zeros are not removed from the result.\n\nThe "\',\'" option signals the use of a comma for a thousands separator.\nFor a locale aware separator, use the "\'n\'" integer presentation type\ninstead.\n\nChanged in version 3.1: Added the "\',\'" option (see also **PEP 378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nPreceding the *width* field by a zero ("\'0\'") character enables sign-\naware zero-padding for numeric types. This is equivalent to a *fill*\ncharacter of "\'0\'" with an *alignment* type of "\'=\'".\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with "\'f\'" and "\'F\'", or before and after the decimal point\nfor a floating point value formatted with "\'g\'" or "\'G\'". For non-\nnumber types the field indicates the maximum field size - in other\nwords, how many characters will be used from the field content. The\n*precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'s\'" | String format. This is the default type for strings and |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'s\'". |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'b\'" | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | "\'c\'" | Character. Converts the integer to the corresponding |\n +-----------+------------------------------------------------------------+\n | "\'d\'" | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | "\'o\'" | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | "\'x\'" | Hex format. Outputs the number in base 16, using lower- |\n +-----------+------------------------------------------------------------+\n | "\'X\'" | Hex format. Outputs the number in base 16, using upper- |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'d\'", except that it uses the |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'d\'". |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except "\'n\'"\nand None). When doing so, "float()" is used to convert the integer to\na floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'e\'" | Exponent notation. Prints the number in scientific |\n +-----------+------------------------------------------------------------+\n | "\'E\'" | Exponent notation. Same as "\'e\'" except it uses an upper |\n +-----------+------------------------------------------------------------+\n | "\'f\'" | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | "\'F\'" | Fixed point. Same as "\'f\'", but converts "nan" to "NAN" |\n +-----------+------------------------------------------------------------+\n | "\'g\'" | General format. For a given precision "p >= 1", this |\n +-----------+------------------------------------------------------------+\n | "\'G\'" | General format. Same as "\'g\'" except switches to "\'E\'" if |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'g\'", except that it uses the |\n +-----------+------------------------------------------------------------+\n | "\'%\'" | Percentage. Multiplies the number by 100 and displays in |\n +-----------+------------------------------------------------------------+\n | None | Similar to "\'g\'", except with at least one digit past the |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old "%"-formatting.\n\nIn most of the cases the syntax is similar to the old "%"-formatting,\nwith the addition of the "{}" and with ":" used instead of "%". For\nexample, "\'%03.2f\'" can be translated to "\'{:03.2f}\'".\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing "%s" and "%r":\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing "%+f", "%-f", and "% f" and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing "%x" and "%o" and converting the value to different bases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12): #doctest: +NORMALIZE_WHITESPACE\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', - 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n', - 'global': '\nThe "global" statement\n**********************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe "global" statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without "global", although free variables may refer to\nglobals without being declared global.\n\nNames listed in a "global" statement must not be used in the same code\nblock textually preceding that "global" statement.\n\nNames listed in a "global" statement must not be defined as formal\nparameters or in a "for" loop control target, "class" definition,\nfunction definition, or "import" statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the latter two restrictions, but programs should not abuse\nthis freedom, as future implementations may enforce them or silently\nchange the meaning of the program.\n\n**Programmer\'s note:** the "global" is a directive to the parser. It\napplies only to code parsed at the same time as the "global"\nstatement. In particular, a "global" statement contained in a string\nor code object supplied to the built-in "exec()" function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by "global" statements in the\ncode containing the function call. The same applies to the "eval()"\nand "compile()" functions.\n', - 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters "A" through "Z", the underscore "_" and, except for the first\ncharacter, the digits "0" through "9".\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n"unicodedata" module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'if': '\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', - 'imaginary': '\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., "(3+4j)". Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', - 'import': '\nThe "import" statement\n**********************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nThe basic import statement (no "from" clause) is executed in two\nsteps:\n\n1. find a module, loading and initializing it if necessary\n\n2. define a name or names in the local namespace for the scope\n where the "import" statement occurs.\n\nWhen the statement contains multiple clauses (separated by commas) the\ntwo steps are carried out separately for each clause, just as though\nthe clauses had been separated out into individiual import statements.\n\nThe details of the first step, finding and loading modules is\ndescribed in greater detail in the section on the *import system*,\nwhich also describes the various types of packages and modules that\ncan be imported, as well as all the hooks that can be used to\ncustomize the import system. Note that failures in this step may\nindicate either that the module could not be located, *or* that an\nerror occurred while initializing the module, which includes execution\nof the module\'s code.\n\nIf the requested module is retrieved successfully, it will be made\navailable in the local namespace in one of three ways:\n\n* If the module name is followed by "as", then the name following\n "as" is bound directly to the imported module.\n\n* If no other name is specified, and the module being imported is a\n top level module, the module\'s name is bound in the local namespace\n as a reference to the imported module\n\n* If the module being imported is *not* a top level module, then the\n name of the top level package that contains the module is bound in\n the local namespace as a reference to the top level package. The\n imported module must be accessed using its full qualified name\n rather than directly\n\nThe "from" form uses a slightly more complex process:\n\n1. find the module specified in the "from" clause loading and\n initializing it if necessary;\n\n2. for each of the identifiers specified in the "import" clauses:\n\n 1. check if the imported module has an attribute by that name\n\n 2. if not, attempt to import a submodule with that name and then\n check the imported module again for that attribute\n\n 3. if the attribute is not found, "ImportError" is raised.\n\n 4. otherwise, a reference to that value is bound in the local\n namespace, using the name in the "as" clause if it is present,\n otherwise using the attribute name\n\nExamples:\n\n import foo # foo imported and bound locally\n import foo.bar.baz # foo.bar.baz imported, foo bound locally\n import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb\n from foo.bar import baz # foo.bar.baz imported and bound as baz\n from foo import attr # foo imported and foo.attr bound as attr\n\nIf the list of identifiers is replaced by a star ("\'*\'"), all public\nnames defined in the module are bound in the local namespace for the\nscope where the "import" statement occurs.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named "__all__"; if defined, it must\nbe a sequence of strings which are names defined or imported by that\nmodule. The names given in "__all__" are all considered public and\nare required to exist. If "__all__" is not defined, the set of public\nnames includes all names found in the module\'s namespace which do not\nbegin with an underscore character ("\'_\'"). "__all__" should contain\nthe entire public API. It is intended to avoid accidentally exporting\nitems that are not part of the API (such as library modules which were\nimported and used within the module).\n\nThe "from" form with "*" may only occur in a module scope. The wild\ncard form of import --- "import *" --- is only allowed at the module\nlevel. Attempting to use it in class or function definitions will\nraise a "SyntaxError".\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after "from" you\ncan specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n"from . import mod" from a module in the "pkg" package then you will\nend up importing "pkg.mod". If you execute "from ..subpkg2 import mod"\nfrom within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\nspecification for relative imports is contained within **PEP 328**.\n\n"importlib.import_module()" is provided to support applications that\ndetermine which modules need to be loaded dynamically.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python. The future\nstatement is intended to ease migration to future versions of Python\nthat introduce incompatible changes to the language. It allows use of\nthe new features on a per-module basis before the release in which the\nfeature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are "absolute_import",\n"division", "generators", "unicode_literals", "print_function",\n"nested_scopes" and "with_statement". They are all redundant because\nthey are always enabled, and only kept for backwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module "__future__", described later, and it will\nbe imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions "exec()" and\n"compile()" that occur in a module "M" containing a future statement\nwill, by default, use the new syntax or semantics associated with the\nfuture statement. This can be controlled by optional arguments to\n"compile()" --- see the documentation of that function for details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also: **PEP 236** - Back to the __future__\n\n The original proposal for the __future__ mechanism.\n', - 'in': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another. When cross-type\ncomparison is not supported, the comparison method returns\n"NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether a the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', - 'integers': '\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', - 'lambda': '\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda expressions (sometimes called lambda forms) have the same\nsyntactic position as expressions. They are a shorthand to create\nanonymous functions; the expression "lambda arguments: expression"\nyields a function object. The unnamed object behaves like a function\nobject defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda expressions cannot contain\nstatements or annotations.\n', - 'lists': '\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', - 'naming': '\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, a\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\nglobal statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', - 'nonlocal': '\nThe "nonlocal" statement\n************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe "nonlocal" statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a "nonlocal" statement, unlike to those listed in a\n"global" statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a "nonlocal" statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also: **PEP 3104** - Access to Names in Outer Scopes\n\n The specification for the "nonlocal" statement.\n', - 'numbers': '\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator \'"-"\' and the\nliteral "1".\n', - 'numeric-types': '\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, to execute the statement "x += y", where\n *x* is an instance of a class that has an "__iadd__()" method,\n "x.__iadd__(y)" is called. If *x* is an instance of a class that\n does not define a "__iadd__()" method, "x.__add__(y)" and\n "y.__radd__(x)" are considered, as with the evaluation of "x + y".\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: When "__index__()" is defined, "__int__()" should also be\n defined, and both shuld return the same value, in order to have a\n coherent integer type class.\n', - 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'"is"\' operator compares the\nidentity of two objects; the "id()" function returns an integer\nrepresenting its identity.\n\n**CPython implementation detail:** For CPython, "id(x)" is the memory\naddress where "x" is stored.\n\nAn object\'s type determines the operations that the object supports\n(e.g., "does it have a length?") and also defines the possible values\nfor objects of that type. The "type()" function returns an object\'s\ntype (which is an object itself). Like its identity, an object\'s\n*type* is also unchangeable. [1]\n\nThe *value* of some objects can change. Objects whose value can\nchange are said to be *mutable*; objects whose value is unchangeable\nonce they are created are called *immutable*. (The value of an\nimmutable container object that contains a reference to a mutable\nobject can change when the latter\'s value is changed; however the\ncontainer is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the "gc" module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'"try"..."except"\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a "close()" method. Programs\nare strongly recommended to explicitly close such objects. The\n\'"try"..."finally"\' statement and the \'"with"\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after "a = 1; b = 1",\n"a" and "b" may or may not refer to the same object with the value\none, depending on the implementation, but after "c = []; d = []", "c"\nand "d" are guaranteed to refer to two different, unique, newly\ncreated empty lists. (Note that "c = d = []" assigns the same object\nto both "c" and "d".)\n', - 'operator-summary': '\nOperator precedence\n*******************\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| "lambda" | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| "if" -- "else" | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| "or" | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| "and" | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| "not" "x" | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| "in", "not in", "is", "is not", "<", "<=", ">", | Comparisons, including membership |\n| ">=", "!=", "==" | tests and identity tests |\n+-------------------------------------------------+---------------------------------------+\n| "|" | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| "^" | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| "&" | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| "<<", ">>" | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| "+", "-" | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| "*", "/", "//", "%" | Multiplication, division, remainder |\n+-------------------------------------------------+---------------------------------------+\n| "+x", "-x", "~x" | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| "**" | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| "x[index]", "x[index:index]", | Subscription, slicing, call, |\n| "x(arguments...)", "x.attribute" | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| "(expressions...)", "[expressions...]", "{key: | Binding or tuple display, list |\n| value...}", "{expressions...}" | display, dictionary display, set |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While "abs(x%y) < abs(y)" is true mathematically, for floats\n it may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that "-1e-100 % 1e100" have the same\n sign as "1e100", the computed result is "-1e-100 + 1e100", which\n is numerically exactly equal to "1e100". The function\n "math.fmod()" returns a result whose sign matches the sign of the\n first argument instead, and so returns "-1e-100" in this case.\n Which approach is more appropriate depends on the application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for "x//y" to be one larger than "(x-x%y)//y" due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that "divmod(x,y)[0] * y + x % y" be very close\n to "x".\n\n[3] While comparisons between strings make sense at the byte\n level, they may be counter-intuitive to users. For example, the\n strings ""\\u00C7"" and ""\\u0327\\u0043"" compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using "unicodedata.normalize()".\n\n[4] Due to automatic garbage-collection, free lists, and the\n dynamic nature of descriptors, you may notice seemingly unusual\n behaviour in certain uses of the "is" operator, like those\n involving comparisons between instance methods, or constants.\n Check their documentation for more info.\n\n[5] The "%" operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator "**" binds less tightly than an arithmetic\n or bitwise unary operator on its right, that is, "2**-1" is "0.5".\n', - 'pass': '\nThe "pass" statement\n********************\n\n pass_stmt ::= "pass"\n\n"pass" is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', - 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): "-1**2" results in "-1".\n\nThe power operator has the same semantics as the built-in "pow()"\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n"10**2" returns "100", but "10**-2" returns "0.01".\n\nRaising "0.0" to a negative power results in a "ZeroDivisionError".\nRaising a negative number to a fractional power results in a "complex"\nnumber. (In earlier versions it raised a "ValueError".)\n', - 'raise': '\nThe "raise" statement\n*********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, "raise" re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a "RuntimeError" exception is raised indicating\nthat this is an error.\n\nOtherwise, "raise" evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n"BaseException". If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the "__traceback__" attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the "with_traceback()" exception method (which returns\nthe same exception instance, with its traceback set to its argument),\nlike so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe "from" clause is used for exception chaining: if given, the second\n*expression* must be another exception class or instance, which will\nthen be attached to the raised exception as the "__cause__" attribute\n(which is writable). If the raised exception is not handled, both\nexceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s "__context__" attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', - 'return': '\nThe "return" statement\n**********************\n\n return_stmt ::= "return" [expression_list]\n\n"return" may only occur syntactically nested in a function definition,\nnot within a nested class definition.\n\nIf an expression list is present, it is evaluated, else "None" is\nsubstituted.\n\n"return" leaves the current function call with the expression list (or\n"None") as return value.\n\nWhen "return" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nfunction.\n\nIn a generator function, the "return" statement indicates that the\ngenerator is done and will cause "StopIteration" to be raised. The\nreturned value (if any) is used as an argument to construct\n"StopIteration" and becomes the "StopIteration.value" attribute.\n', - 'sequence-types': '\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method "keys()".\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n', - 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as floor division by "pow(2,n)".\nA left shift by *n* bits is defined as multiplication with "pow(2,n)".\n\nNote: In the current implementation, the right-hand operand is\n required to be at most "sys.maxsize". If the right-hand operand is\n larger than "sys.maxsize" an "OverflowError" exception is raised.\n', - 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or "del" statements. The syntax for a slicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same "__getitem__()"\nmethod as normal subscription) with a key that is constructed from the\nslice list, as follows. If the slice list contains at least one\ncomma, the key is a tuple containing the conversion of the slice\nitems; otherwise, the conversion of the lone slice item is the key.\nThe conversion of a slice item that is an expression is that\nexpression. The conversion of a proper slice is a slice object (see\nsection *The standard type hierarchy*) whose "start", "stop" and\n"step" attributes are the values of the expressions given as lower\nbound, upper bound and stride, respectively, substituting "None" for\nmissing expressions.\n', - 'specialattrs': '\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the "dir()" built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in "__mro__".\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found\n in the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list "[1, 2]" is considered equal to\n "[1.0, 2.0]", and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property\n being one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase),\n or "Lt" (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a\n singleton tuple whose only element is the tuple to be formatted.\n', - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named "__getitem__()", and "x" is an instance of this class,\nthen "x[i]" is roughly equivalent to "type(x).__getitem__(x, i)".\nExcept where mentioned, attempts to execute an operation raise an\nexception when no appropriate method is defined (typically\n"AttributeError" or "TypeError").\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n"NodeList" interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])". As a special constraint on\n constructors, no value may be returned; doing so will cause a\n "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing "None" in\n "sys.last_traceback". Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n "gc" module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using "type()". The class body is\nexecuted in a new namespace and the class name is bound locally to the\nresult of "type(name, bases, namespace)".\n\nThe class creation process can be customised by passing the\n"metaclass" keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both "MyClass" and "MySubclass" are instances\nof "Meta":\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then "type()" is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n "type()", then it is used directly as the metaclass\n\n* if an instance of "type()" is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. "type(cls)") of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with "TypeError".\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a "__prepare__" attribute,\nit is called as "namespace = metaclass.__prepare__(name, bases,\n**kwds)" (where the additional keyword arguments, if any, come from\nthe class definition).\n\nIf the metaclass has no "__prepare__" attribute, then the class\nnamespace is initialised as an empty "dict()" instance.\n\nSee also: **PEP 3115** - Metaclasses in Python 3000\n\n Introduced the "__prepare__" namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as "exec(body, globals(),\nnamespace)". The key difference from a normal call to "exec()" is that\nlexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling "metaclass(name, bases,\nnamespace, **kwds)" (the additional keywords passed here are the same\nas those passed to "__prepare__").\n\nThis class object is the one that will be referenced by the zero-\nargument form of "super()". "__class__" is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either "__class__" or "super". This allows the zero argument form\nof "super()" to correctly identify the class being defined based on\nlexical scoping, while the class or instance that was used to make the\ncurrent call is identified based on the first argument passed to the\nmethod.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also: **PEP 3135** - New super\n\n Describes the implicit "__class__" closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n"collections.OrderedDict" to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s "__prepare__()" method which returns an\nempty "collections.OrderedDict". That mapping records the methods and\nattributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s "__new__()" method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called "members".\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n"isinstance()" and "issubclass()" built-in functions.\n\nIn particular, the metaclass "abc.ABCMeta" implements these methods in\norder to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n "isinstance(instance, class)".\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n "issubclass(subclass, class)".\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also: **PEP 3119** - Introducing Abstract Base Classes\n\n Includes the specification for customizing "isinstance()" and\n "issubclass()" behavior through "__instancecheck__()" and\n "__subclasscheck__()", with motivation for this functionality in\n the context of adding Abstract Base Classes (see the "abc"\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method "keys()".\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, to execute the statement "x += y", where\n *x* is an instance of a class that has an "__iadd__()" method,\n "x.__iadd__(y)" is called. If *x* is an instance of a class that\n does not define a "__iadd__()" method, "x.__add__(y)" and\n "y.__radd__(x)" are considered, as with the evaluation of "x + y".\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: When "__index__()" is defined, "__int__()" should also be\n defined, and both shuld return the same value, in order to have a\n coherent integer type class.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as "__hash__()" and "__repr__()" that are implemented by\nall objects, including type objects. If the implicit lookup of these\nmethods used the conventional lookup process, they would fail when\ninvoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe "__getattribute__()" method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the "__getattribute__()" machinery in this fashion provides\nsignificant scope for speed optimisations within the interpreter, at\nthe cost of some flexibility in the handling of special methods (the\nspecial method *must* be set on the class object itself in order to be\nconsistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type,\n under certain controlled conditions. It generally isn\'t a good\n idea though, since it can lead to some very strange behaviour if\n it is handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as "__add__()") fails the operation is not\n supported, which is why the reflected method is not called.\n', - 'string-methods': '\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see "str.format()",\n*Format String Syntax* and *String Formatting*) and the other based on\nC "printf" style formatting that handles a narrower range of types and\nis slightly harder to use correctly, but is often faster for the cases\nit can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the "re" module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter "\'\xc3\x9f\'" is equivalent to ""ss"".\n Since it is already lowercase, "lower()" would do nothing to "\'\xc3\x9f\'";\n "casefold()" converts it to ""ss"".\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is "\'utf-8\'". *errors* may be given to set a different\n error handling scheme. The default for *errors* is "\'strict\'",\n meaning that encoding errors raise a "UnicodeError". Other possible\n values are "\'ignore\'", "\'replace\'", "\'xmlcharrefreplace\'",\n "\'backslashreplace\'" and any other name registered via\n "codecs.register_error()", see section *Codec Base Classes*. For a\n list of possible encodings, see section *Standard Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return "True" if the string ends with the specified *suffix*,\n otherwise return "False". *suffix* can also be a tuple of suffixes\n to look for. With optional *start*, test beginning at that\n position. With optional *end*, stop comparing at that position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab ("\\t"), one or more space characters are inserted in the result\n until the current column is equal to the next tab position. (The\n tab character itself is not copied.) If the character is a newline\n ("\\n") or return ("\\r"), it is copied and the current column is\n reset to zero. Any other character is copied unchanged and the\n current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" if *sub* is not found.\n\n Note: The "find()" method should be used only if you need to know\n the position of *sub*. To check if *sub* is a substring or not,\n use the "in" operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces "{}". Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to "str.format(**mapping)", except that "mapping" is used\n directly and not copied to a "dict". This is useful if for example\n "mapping" is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like "find()", but raise "ValueError" when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character "c"\n is alphanumeric if one of the following returns "True":\n "c.isalpha()", "c.isdecimal()", "c.isdigit()", or "c.isnumeric()".\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use "keyword.iskeyword()" to test for reserved identifiers such as\n "def" and "class".\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when "repr()" is\n invoked on a string. It has no bearing on the handling of strings\n written to "sys.stdout" or "sys.stderr".)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A "TypeError" will be raised if there are\n any non-string values in *iterable*, including "bytes" objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n "str.translate()".\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like "rfind()" but raises "ValueError" when the substring *sub* is\n not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n "None", any whitespace string is a separator. Except for splitting\n from the right, "rsplit()" behaves like "split()" which is\n described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most "maxsplit+1"\n elements). If *maxsplit* is not specified or "-1", then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', \'2\']"). The *sep* argument\n may consist of multiple characters (for example,\n "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', \'3\']"). Splitting an\n empty string with a specified separator returns "[\'\']".\n\n If *sep* is not specified or is "None", a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a "None" separator returns "[]".\n\n For example, "\' 1 2 3 \'.split()" returns "[\'1\', \'2\', \'3\']", and\n "\' 1 2 3 \'.split(None, 1)" returns "[\'1\', \'2 3 \']".\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example, "\'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()" returns "[\'ab\n c\', \'\', \'de fg\', \'kl\']", while the same call with\n "splitlines(True)" returns "[\'ab c\\n\', \'\\n\', \'de fg\\r\', \'kl\\r\\n\']".\n\n Unlike "split()" when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line.\n\nstr.startswith(prefix[, start[, end]])\n\n Return "True" if string starts with the *prefix*, otherwise return\n "False". *prefix* can also be a tuple of prefixes to look for.\n With optional *start*, test string beginning at that position.\n With optional *end*, stop comparing string at that position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or "None", the *chars*\n argument defaults to removing whitespace. The *chars* argument is\n not a prefix or suffix; rather, all combinations of its values are\n stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n "s.swapcase().swapcase() == s".\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or "None". Unmapped\n characters are left untouched. Characters mapped to "None" are\n deleted.\n\n You can use "str.maketrans()" to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom\n character mapping codec using the "codecs" module (see\n "encodings.cp1251" for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that "str.upper().isupper()" might be\n "False" if "s" contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to "len(s)".\n', - 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "R" | "U"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the "stringprefix" or "bytesprefix"\nand the rest of the literal. The source character set is defined by\nthe encoding declaration; it is UTF-8 if no encoding declaration is\ngiven in the source file; see section *Encoding declarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes ("\'") or double quotes ("""). They can also be enclosed\nin matching groups of three single or double quotes (these are\ngenerally referred to as *triple-quoted strings*). The backslash\n("\\") character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with "\'b\'" or "\'B\'"; they produce\nan instance of the "bytes" type instead of the "str" type. They may\nonly contain ASCII characters; bytes with a numeric value of 128 or\ngreater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix unicode strings with a\n"u" prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter "\'r\'" or "\'R\'"; such strings are called *raw strings* and treat\nbackslashes as literal characters. As a result, in string literals,\n"\'\\U\'" and "\'\\u\'" escapes in raw strings are not treated specially.\nGiven that Python 2.x\'s raw unicode literals behave differently than\nPython 3.x\'s the "\'ur\'" syntax is not supported.\n\n New in version 3.3: The "\'rb\'" prefix of raw bytes literals has\n been added as a synonym of "\'br\'".\n\n New in version 3.3: Support for the unicode legacy literal\n ("u\'value\'") was reintroduced to simplify the maintenance of dual\n Python 2.x and 3.x codebases. See **PEP 414** for more information.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either "\'" or """.)\n\nUnless an "\'r\'" or "\'R\'" prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n| "\\ooo" | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| "\\xhh" | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\N{name}" | Character named *name* in the | (4) |\n+-------------------+-----------------------------------+---------+\n| "\\uxxxx" | Character with 16-bit hex value | (5) |\n+-------------------+-----------------------------------+---------+\n| "\\Uxxxxxxxx" | Character with 32-bit hex value | (6) |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the\n byte with the given value. In a string literal, these escapes\n denote a Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can\n be encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way. Exactly eight\n hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, "r"\\""" is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; "r"\\"" is not a valid string literal (even a raw string\ncannot end in an odd number of backslashes). Specifically, *a raw\nstring cannot end in a single backslash* (since the backslash would\nescape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', - 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a "__getitem__()" method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a "__getitem__()"\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that "x[-1]" selects the last item of "x").\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero). Since the support for\nnegative indices and slicing occurs in the object\'s "__getitem__()"\nmethod, subclasses overriding this method will need to explicitly add\nthat support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', - 'truth': '\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an "if" or\n"while" condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* "None"\n\n* "False"\n\n* zero of any numeric type, for example, "0", "0.0", "0j".\n\n* any empty sequence, for example, "\'\'", "()", "[]".\n\n* any empty mapping, for example, "{}".\n\n* instances of user-defined classes, if the class defines a\n "__bool__()" or "__len__()" method, when that method returns the\n integer zero or "bool" value "False". [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn "0" or "False" for false and "1" or "True" for true, unless\notherwise stated. (Important exception: the Boolean operations "or"\nand "and" always return one of their operands.)\n', - 'try': '\nThe "try" statement\n*******************\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be access via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n def f():\n try:\n 1/0\n finally:\n return 42\n\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name "None". It\n is used to signify the absence of a value in many situations, e.g.,\n it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n "NotImplemented". Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal "..." or the\n built-in name "Ellipsis". Its truth value is true.\n\n"numbers.Number"\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n "numbers.Integral"\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers ("int")\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans ("bool")\n These represent the truth values False and True. The two\n objects representing the values "False" and "True" are the\n only Boolean objects. The Boolean type is a subtype of the\n integer type, and Boolean values behave like the values 0 and\n 1, respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ""False"" or\n ""True"" are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n "numbers.Real" ("float")\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n "numbers.Complex" ("complex")\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number "z" can be retrieved through the read-only\n attributes "z.real" and "z.imag".\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function "len()" returns the number of items\n of a sequence. When the length of a sequence is *n*, the index set\n contains the numbers 0, 1, ..., *n*-1. Item *i* of sequence *a* is\n selected by "a[i]".\n\n Sequences also support slicing: "a[i:j]" selects all items with\n index *k* such that *i* "<=" *k* "<" *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: "a[i:j:k]" selects all items of *a* with index *x* where\n "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode\n codepoints. All the codepoints in range "U+0000 - U+10FFFF"\n can be represented in a string. Python doesn\'t have a "chr"\n type, and every character in the string is represented as a\n string object with length "1". The built-in function "ord()"\n converts a character to its codepoint (as an integer);\n "chr()" converts an integer in range "0 - 10FFFF" to the\n corresponding character. "str.encode()" can be used to\n convert a "str" to "bytes" using the given encoding, and\n "bytes.decode()" can be used to achieve the opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like "b\'abc\'") and the built-in function\n "bytes()" can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the "decode()"\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and "del" (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in "bytearray()" constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module "array" provides an additional example of a\n mutable sequence type, as does the "collections" module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function "len()"\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., "1" and\n "1.0"), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n "set()" constructor and can be modified afterwards by several\n methods, such as "add()".\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in "frozenset()" constructor. As a frozenset is immutable\n and *hashable*, it can be used again as an element of another\n set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation "a[k]" selects the item indexed by "k"\n from the mapping "a"; this can be used in expressions and as the\n target of assignments or "del" statements. The built-in function\n "len()" returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., "1" and "1.0")\n then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the "{...}"\n notation (see section *Dictionary displays*).\n\n The extension modules "dbm.ndbm" and "dbm.gnu" provide\n additional examples of mapping types, as does the "collections"\n module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n +===========================+=================================+=============+\n | "__doc__" | The function\'s documentation | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__name__" | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__qualname__" | The function\'s *qualified name* | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__code__" | The code object representing | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n +---------------------------+---------------------------------+-------------+\n | "__dict__" | The namespace supporting | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n +---------------------------+---------------------------------+-------------+\n | "__annotations__" | A dict containing annotations | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__kwdefaults__" | A dict containing defaults for | Writable |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: "__self__" is the class instance\n object, "__func__" is the function object; "__doc__" is the\n method\'s documentation (same as "__func__.__doc__"); "__name__"\n is the method name (same as "__func__.__name__"); "__module__"\n is the name of the module the method was defined in, or "None"\n if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its "__self__" attribute is the instance, and the method object\n is said to be bound. The new method\'s "__func__" attribute is\n the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the "__func__"\n attribute of the new instance is not the original method object\n but its "__func__" attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its "__self__" attribute\n is the class itself, and its "__func__" attribute is the\n function object underlying the class method.\n\n When an instance method object is called, the underlying\n function ("__func__") is called, inserting the class instance\n ("__self__") in front of the argument list. For instance, when\n "C" is a class which contains a definition for a function "f()",\n and "x" is an instance of "C", calling "x.f(1)" is equivalent to\n calling "C.f(x, 1)".\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in "__self__" will actually\n be the class itself, so that calling either "x.f(1)" or "C.f(1)"\n is equivalent to calling "f(C,1)" where "f" is the underlying\n function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "iterator.__next__()" method will cause the\n function to execute until it provides a value using the "yield"\n statement. When the function executes a "return" statement or\n falls off the end, a "StopIteration" exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are "len()" and "math.sin()"\n ("math" is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: "__doc__" is the function\'s documentation\n string, or "None" if unavailable; "__name__" is the function\'s\n name; "__self__" is set to "None" (but see the next item);\n "__module__" is the name of the module the function was defined\n in or "None" if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n "alist.append()", assuming *alist* is a list object. In this\n case, the special read-only attribute "__self__" is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override "__new__()". The arguments of the\n call are passed to "__new__()" and, in the typical case, to\n "__init__()" to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a "__call__()" method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the "import"\n statement (see "import"), or by calling functions such as\n "importlib.import_module()" and built-in "__import__()". A module\n object has a namespace implemented by a dictionary object (this is\n the dictionary referenced by the "__globals__" attribute of\n functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., "m.x" is equivalent\n to "m.__dict__["x"]". A module object does not contain the code\n object used to initialize the module (since it isn\'t needed once\n the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s name;\n "__doc__" is the module\'s documentation string, or "None" if\n unavailable; "__file__" is the pathname of the file from which the\n module was loaded, if it was loaded from a file. The "__file__"\n attribute may be missing for certain types of modules, such as C\n modules that are statically linked into the interpreter; for\n extension modules loaded dynamically from a shared library, it is\n the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., "C.x" is translated to\n "C.__dict__["x"]" (although there are a number of hooks which allow\n for other means of locating attributes). When the attribute name is\n not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n class method object, it is transformed into an instance method\n object whose "__self__" attributes is "C". When it would yield a\n static method object, it is transformed into the object wrapped by\n the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its "__dict__".\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: "__name__" is the class name; "__module__" is\n the module name in which the class was defined; "__dict__" is the\n dictionary containing the class\'s namespace; "__bases__" is a tuple\n (possibly empty or a singleton) containing the base classes, in the\n order of their occurrence in the base class list; "__doc__" is the\n class\'s documentation string, or None if undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose "__self__" attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s "__dict__".\n If no class attribute is found, and the object\'s class has a\n "__getattr__()" method, that is called to satisfy the lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n "__setattr__()" or "__delattr__()" method, this is called instead\n of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: "__dict__" is the attribute dictionary;\n "__class__" is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the "open()" built-in function,\n and also "os.popen()", "os.fdopen()", and the "makefile()" method\n of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n "io.TextIOBase" abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function name;\n "co_argcount" is the number of positional arguments (including\n arguments with default values); "co_nlocals" is the number of\n local variables used by the function (including arguments);\n "co_varnames" is a tuple containing the names of the local\n variables (starting with the argument names); "co_cellvars" is a\n tuple containing the names of local variables that are\n referenced by nested functions; "co_freevars" is a tuple\n containing the names of free variables; "co_code" is a string\n representing the sequence of bytecode instructions; "co_consts"\n is a tuple containing the literals used by the bytecode;\n "co_names" is a tuple containing the names used by the bytecode;\n "co_filename" is the filename from which the code was compiled;\n "co_firstlineno" is the first line number of the function;\n "co_lnotab" is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); "co_stacksize" is the required stack size\n (including local variables); "co_flags" is an integer encoding a\n number of flags for the interpreter.\n\n The following flag bits are defined for "co_flags": bit "0x04"\n is set if the function uses the "*arguments" syntax to accept an\n arbitrary number of positional arguments; bit "0x08" is set if\n the function uses the "**keywords" syntax to accept arbitrary\n keyword arguments; bit "0x20" is set if the function is a\n generator.\n\n Future feature declarations ("from __future__ import division")\n also use bits in "co_flags" to indicate whether a code object\n was compiled with a particular feature enabled: bit "0x2000" is\n set if the function was compiled with future division enabled;\n bits "0x10" and "0x1000" were used in earlier versions of\n Python.\n\n Other bits in "co_flags" are reserved for internal use.\n\n If a code object represents a function, the first item in\n "co_consts" is the documentation string of the function, or\n "None" if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: "f_back" is to the previous stack\n frame (towards the caller), or "None" if this is the bottom\n stack frame; "f_code" is the code object being executed in this\n frame; "f_locals" is the dictionary used to look up local\n variables; "f_globals" is used for global variables;\n "f_builtins" is used for built-in (intrinsic) names; "f_lasti"\n gives the precise instruction (this is an index into the\n bytecode string of the code object).\n\n Special writable attributes: "f_trace", if not "None", is a\n function called at the start of each source code line (this is\n used by the debugger); "f_lineno" is the current line number of\n the frame --- writing to this from within a trace function jumps\n to the given line (only for the bottom-most frame). A debugger\n can implement a Jump command (aka Set Next Statement) by writing\n to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n "RuntimeError" is raised if the frame is currently executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by "sys.exc_info()". When the program contains no\n suitable handler, the stack trace is written (nicely formatted)\n to the standard error stream; if the interpreter is interactive,\n it is also made available to the user as "sys.last_traceback".\n\n Special read-only attributes: "tb_next" is the next level in the\n stack trace (towards the frame where the exception occurred), or\n "None" if there is no next level; "tb_frame" points to the\n execution frame of the current level; "tb_lineno" gives the line\n number where the exception occurred; "tb_lasti" indicates the\n precise instruction. The line number and last instruction in\n the traceback may differ from the line number of its frame\n object if the exception occurred in a "try" statement with no\n matching except clause or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for "__getitem__()"\n methods. They are also created by the built-in "slice()"\n function.\n\n Special read-only attributes: "start" is the lower bound; "stop"\n is the upper bound; "step" is the step value; each is "None" if\n omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n "staticmethod()" constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in "classmethod()" constructor.\n', - 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: "func(argument-list)".\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', - 'typesmapping': '\nMapping Types --- "dict"\n************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin "list", "set", and "tuple" classes, and the "collections" module.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as "1" and "1.0") then they can be used interchangeably to index\nthe same dictionary entry. (Note however, that since computers store\nfloating-point numbers as approximations it is usually unwise to use\nthem as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of "key:\nvalue" pairs within braces, for example: "{\'jack\': 4098, \'sjoerd\':\n4127}" or "{4098: \'jack\', 4127: \'sjoerd\'}", or by the "dict"\nconstructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterator*\n object. Each item in the iterable must itself be an iterator with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to "{"one": 1, "two": 2, "three": 3}":\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a "KeyError" if\n *key* is not in the map.\n\n If a subclass of dict defines a method "__missing__()", if the\n key *key* is not present, the "d[key]" operation calls that\n method with the key *key* as argument. The "d[key]" operation\n then returns or raises whatever is returned or raised by the\n "__missing__(key)" call if the key is not present. No other\n operations or methods invoke "__missing__()". If "__missing__()"\n is not defined, "KeyError" is raised. "__missing__()" must be a\n method; it cannot be an instance variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See "collections.Counter" for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n key not in d\n\n Equivalent to "not key in d".\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iter(d.keys())".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n "fromkeys()" is a class method that returns a new dictionary.\n *value* defaults to "None".\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to "None", so\n that this method never raises a "KeyError".\n\n items()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a "KeyError" is raised.\n\n popitem()\n\n Remove and return an arbitrary "(key, value)" pair from the\n dictionary.\n\n "popitem()" is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling "popitem()" raises a "KeyError".\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to "None".\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return "None".\n\n "update()" accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: "d.update(red=1,\n blue=2)".\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also: "types.MappingProxyType" can be used to create a read-only\n view of a "dict".\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.keys()", "dict.values()" and\n"dict.items()" are *view objects*. They provide a dynamic view on the\ndictionary\'s entries, which means that when the dictionary changes,\nthe view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of "(key, value)") in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of "(value, key)" pairs using\n "zip()": "pairs = zip(d.values(), d.keys())". Another way to\n create the same list is "pairs = [(v, k) for (k, v) in d.items()]".\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a "RuntimeError" or fail to iterate over all entries.\n\nx in dictview\n\n Return "True" if *x* is in the underlying dictionary\'s keys, values\n or items (in the latter case, *x* should be a "(key, value)"\n tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that "(key, value)" pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class "collections.abc.Set" are available (for example, "==",\n"<", or "^").\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', - 'typesmethods': '\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as "append()" on lists)\nand class instance methods. Built-in methods are described with the\ntypes that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the "self"\nargument to the argument list. Bound methods have two special read-\nonly attributes: "m.__self__" is the object on which the method\noperates, and "m.__func__" is the function implementing the method.\nCalling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to\ncalling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object ("meth.__func__"), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an "AttributeError" being raised. In\norder to set a method attribute, you need to explicitly set it on the\nunderlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', - 'typesmodules': '\nModules\n*******\n\nThe only special operation on a module is attribute access: "m.name",\nwhere *m* is a module and *name* accesses a name defined in *m*\'s\nsymbol table. Module attributes can be assigned to. (Note that the\n"import" statement is not, strictly speaking, an operation on a module\nobject; "import foo" does not require a module object named *foo* to\nexist, rather it requires an (external) *definition* for a module\nnamed *foo* somewhere.)\n\nA special attribute of every module is "__dict__". This is the\ndictionary containing the module\'s symbol table. Modifying this\ndictionary will actually change the module\'s symbol table, but direct\nassignment to the "__dict__" attribute is not possible (you can write\n"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but you can\'t\nwrite "m.__dict__ = {}"). Modifying "__dict__" directly is not\nrecommended.\n\nModules built into the interpreter are written like this: "". If loaded from a file, they are written as\n"".\n', - 'typesseq': '\nSequence Types --- "list", "tuple", "range"\n*******************************************\n\nThere are three basic sequence types: lists, tuples, and range\nobjects. Additional sequence types tailored for processing of *binary\ndata* and *text strings* are described in dedicated sections.\n\n\nCommon Sequence Operations\n==========================\n\nThe operations in the following table are supported by most sequence\ntypes, both mutable and immutable. The "collections.abc.Sequence" ABC\nis provided to make it easier to correctly implement these operations\non custom sequence types.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type, *n*, *i*, *j* and *k* are\nintegers and *x* is an arbitrary object that meets any type and value\nrestrictions imposed by *s*.\n\nThe "in" and "not in" operations have the same priorities as the\ncomparison operations. The "+" (concatenation) and "*" (repetition)\noperations have the same priority as the corresponding numeric\noperations.\n\n+----------------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+============================+==================================+============+\n| "x in s" | "True" if an item of *s* is | (1) |\n+----------------------------+----------------------------------+------------+\n| "x not in s" | "False" if an item of *s* is | (1) |\n+----------------------------+----------------------------------+------------+\n| "s + t" | the concatenation of *s* and *t* | (6)(7) |\n+----------------------------+----------------------------------+------------+\n| "s * n" or "n * s" | *n* shallow copies of *s* | (2)(7) |\n+----------------------------+----------------------------------+------------+\n| "s[i]" | *i*th item of *s*, origin 0 | (3) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) |\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) |\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n\nSequences of the same type also support comparisons. In particular,\ntuples and lists are compared lexicographically by comparing\ncorresponding elements. This means that to compare equal, every\nelement must compare equal and the two sequences must be of the same\ntype and have the same length. (For full details see *Comparisons* in\nthe language reference.)\n\nNotes:\n\n1. While the "in" and "not in" operations are used only for simple\n containment testing in the general case, some specialised sequences\n (such as "str", "bytes" and "bytearray") also use them for\n subsequence testing:\n\n >>> "gg" in "eggs"\n True\n\n2. Values of *n* less than "0" are treated as "0" (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that "[[]]" is a one-element list containing\n an empty list, so all three elements of "[[]] * 3" are (pointers\n to) this single empty list. Modifying any of the elements of\n "lists" modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of\n the string: "len(s) + i" or "len(s) + j" is substituted. But note\n that "-0" is still "0".\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that "i <= k < j". If *i* or *j* is\n greater than "len(s)", use "len(s)". If *i* is omitted or "None",\n use "0". If *j* is omitted or "None", use "len(s)". If *i* is\n greater than or equal to *j*, the slice is empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index "x = i + n*k" such that "0 <= n <\n (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k",\n "i+3*k" and so on, stopping when *j* is reached (but never\n including *j*). If *i* or *j* is greater than "len(s)", use\n "len(s)". If *i* or *j* are omitted or "None", they become "end"\n values (which end depends on the sign of *k*). Note, *k* cannot be\n zero. If *k* is "None", it is treated like "1".\n\n6. Concatenating immutable sequences always results in a new\n object. This means that building up a sequence by repeated\n concatenation will have a quadratic runtime cost in the total\n sequence length. To get a linear runtime cost, you must switch to\n one of the alternatives below:\n\n * if concatenating "str" objects, you can build a list and use\n "str.join()" at the end or else write to a "io.StringIO" instance\n and retrieve its value when complete\n\n * if concatenating "bytes" objects, you can similarly use\n "bytes.join()" or "io.BytesIO", or you can do in-place\n concatenation with a "bytearray" object. "bytearray" objects are\n mutable and have an efficient overallocation mechanism\n\n * if concatenating "tuple" objects, extend a "list" instead\n\n * for other types, investigate the relevant class documentation\n\n7. Some sequence types (such as "range") only support item\n sequences that follow specific patterns, and hence don\'t support\n sequence concatenation or repetition.\n\n8. "index" raises "ValueError" when *x* is not found in *s*. When\n supported, the additional arguments to the index method allow\n efficient searching of subsections of the sequence. Passing the\n extra arguments is roughly equivalent to using "s[i:j].index(x)",\n only without copying any data and with the returned index being\n relative to the start of the sequence rather than the start of the\n slice.\n\n\nImmutable Sequence Types\n========================\n\nThe only operation that immutable sequence types generally implement\nthat is not also implemented by mutable sequence types is support for\nthe "hash()" built-in.\n\nThis support allows immutable sequences, such as "tuple" instances, to\nbe used as "dict" keys and stored in "set" and "frozenset" instances.\n\nAttempting to hash an immutable sequence that contains unhashable\nvalues will result in "TypeError".\n\n\nMutable Sequence Types\n======================\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n\n\nLists\n=====\n\nLists are mutable sequences, typically used to store collections of\nhomogeneous items (where the precise degree of similarity will vary by\napplication).\n\nclass class list([iterable])\n\n Lists may be constructed in several ways:\n\n * Using a pair of square brackets to denote the empty list: "[]"\n\n * Using square brackets, separating items with commas: "[a]",\n "[a, b, c]"\n\n * Using a list comprehension: "[x for x in iterable]"\n\n * Using the type constructor: "list()" or "list(iterable)"\n\n The constructor builds a list whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a list, a copy is made and\n returned, similar to "iterable[:]". For example, "list(\'abc\')"\n returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" returns "[1, 2,\n 3]". If no argument is given, the constructor creates a new empty\n list, "[]".\n\n Many other operations also produce lists, including the "sorted()"\n built-in.\n\n Lists implement all of the *common* and *mutable* sequence\n operations. Lists also provide the following additional method:\n\n sort(*, key=None, reverse=None)\n\n This method sorts the list in place, using only "<" comparisons\n between items. Exceptions are not suppressed - if any comparison\n operations fail, the entire sort operation will fail (and the\n list will likely be left in a partially modified state).\n\n "sort()" accepts two arguments that can only be passed by\n keyword (*keyword-only arguments*):\n\n *key* specifies a function of one argument that is used to\n extract a comparison key from each list element (for example,\n "key=str.lower"). The key corresponding to each item in the list\n is calculated once and then used for the entire sorting process.\n The default value of "None" means that list items are sorted\n directly without calculating a separate key value.\n\n The "functools.cmp_to_key()" utility is available to convert a\n 2.x style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n This method modifies the sequence in place for economy of space\n when sorting a large sequence. To remind users that it operates\n by side effect, it does not return the sorted sequence (use\n "sorted()" to explicitly request a new sorted list instance).\n\n The "sort()" method is guaranteed to be stable. A sort is\n stable if it guarantees not to change the relative order of\n elements that compare equal --- this is helpful for sorting in\n multiple passes (for example, sort by department, then by salary\n grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises "ValueError" if it can detect\n that the list has been mutated during a sort.\n\n\nTuples\n======\n\nTuples are immutable sequences, typically used to store collections of\nheterogeneous data (such as the 2-tuples produced by the "enumerate()"\nbuilt-in). Tuples are also used for cases where an immutable sequence\nof homogeneous data is needed (such as allowing storage in a "set" or\n"dict" instance).\n\nclass class tuple([iterable])\n\n Tuples may be constructed in a number of ways:\n\n * Using a pair of parentheses to denote the empty tuple: "()"\n\n * Using a trailing comma for a singleton tuple: "a," or "(a,)"\n\n * Separating items with commas: "a, b, c" or "(a, b, c)"\n\n * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)"\n\n The constructor builds a tuple whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a tuple, it is returned\n unchanged. For example, "tuple(\'abc\')" returns "(\'a\', \'b\', \'c\')"\n and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is\n given, the constructor creates a new empty tuple, "()".\n\n Note that it is actually the comma which makes a tuple, not the\n parentheses. The parentheses are optional, except in the empty\n tuple case, or when they are needed to avoid syntactic ambiguity.\n For example, "f(a, b, c)" is a function call with three arguments,\n while "f((a, b, c))" is a function call with a 3-tuple as the sole\n argument.\n\n Tuples implement all of the *common* sequence operations.\n\nFor heterogeneous collections of data where access by name is clearer\nthan access by index, "collections.namedtuple()" may be a more\nappropriate choice than a simple tuple object.\n\n\nRanges\n======\n\nThe "range" type represents an immutable sequence of numbers and is\ncommonly used for looping a specific number of times in "for" loops.\n\nclass class range(stop)\nclass class range(start, stop[, step])\n\n The arguments to the range constructor must be integers (either\n built-in "int" or any object that implements the "__index__"\n special method). If the *step* argument is omitted, it defaults to\n "1". If the *start* argument is omitted, it defaults to "0". If\n *step* is zero, "ValueError" is raised.\n\n For a positive *step*, the contents of a range "r" are determined\n by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] <\n stop".\n\n For a negative *step*, the contents of the range are still\n determined by the formula "r[i] = start + step*i", but the\n constraints are "i >= 0" and "r[i] > stop".\n\n A range object will be empty if "r[0]" does not meet the value\n constraint. Ranges do support negative indices, but these are\n interpreted as indexing from the end of the sequence determined by\n the positive indices.\n\n Ranges containing absolute values larger than "sys.maxsize" are\n permitted but some features (such as "len()") may raise\n "OverflowError".\n\n Range examples:\n\n >>> list(range(10))\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n >>> list(range(1, 11))\n [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n >>> list(range(0, 30, 5))\n [0, 5, 10, 15, 20, 25]\n >>> list(range(0, 10, 3))\n [0, 3, 6, 9]\n >>> list(range(0, -10, -1))\n [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n >>> list(range(0))\n []\n >>> list(range(1, 0))\n []\n\n Ranges implement all of the *common* sequence operations except\n concatenation and repetition (due to the fact that range objects\n can only represent sequences that follow a strict pattern and\n repetition and concatenation will usually violate that pattern).\n\nThe advantage of the "range" type over a regular "list" or "tuple" is\nthat a "range" object will always take the same (small) amount of\nmemory, no matter the size of the range it represents (as it only\nstores the "start", "stop" and "step" values, calculating individual\nitems and subranges as needed).\n\nRange objects implement the "collections.abc.Sequence" ABC, and\nprovide features such as containment tests, element index lookup,\nslicing and support for negative indices (see *Sequence Types ---\nlist, tuple, range*):\n\n>>> r = range(0, 20, 2)\n>>> r\nrange(0, 20, 2)\n>>> 11 in r\nFalse\n>>> 10 in r\nTrue\n>>> r.index(10)\n5\n>>> r[5]\n10\n>>> r[:5]\nrange(0, 10, 2)\n>>> r[-1]\n18\n\nTesting range objects for equality with "==" and "!=" compares them as\nsequences. That is, two range objects are considered equal if they\nrepresent the same sequence of values. (Note that two range objects\nthat compare equal might have different "start", "stop" and "step"\nattributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3,\n2) == range(0, 4, 2)".)\n\nChanged in version 3.2: Implement the Sequence ABC. Support slicing\nand negative indices. Test "int" objects for membership in constant\ntime instead of iterating through all items.\n\nChanged in version 3.3: Define \'==\' and \'!=\' to compare range objects\nbased on the sequence of values they define (instead of comparing\nbased on object identity).\n\nNew in version 3.3: The "start", "stop" and "step" attributes.\n', - 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n', - 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary "-" (minus) operator yields the negation of its numeric\nargument.\n\nThe unary "+" (plus) operator yields its numeric argument unchanged.\n\nThe unary "~" (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of "x" is defined as\n"-(x+1)". It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n"TypeError" exception is raised.\n', - 'while': '\nThe "while" statement\n*********************\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n', - 'with': '\nThe "with" statement\n********************\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', - 'yield': '\nThe "yield" statement\n*********************\n\n yield_stmt ::= yield_expression\n\nA "yield" statement is semantically equivalent to a *yield\nexpression*. The yield statement can be used to omit the parentheses\nthat would otherwise be required in the equivalent yield expression\nstatement. For example, the yield statements\n\n yield \n yield from \n\nare equivalent to the yield expression statements\n\n (yield )\n (yield from )\n\nYield expressions and statements are only used when defining a\n*generator* function, and are only used in the body of the generator\nfunction. Using yield in a function definition is sufficient to cause\nthat definition to create a generator function instead of a normal\nfunction.\n\nFor full details of "yield" semantics, refer to the *Yield\nexpressions* section.\n'} +# Autogenerated by Sphinx on Sat Feb 7 15:53:56 2015 +topics = {'assert': u'\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', + 'assignment': u'\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for\n*attributeref*, *subscription*, and *slicing*.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the target\n sequence allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nAlthough the definition of assignment implies that overlaps between\nthe left-hand side and the right-hand side are \'simultanenous\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables occur left-to-right, sometimes\nresulting in confusion. For instance, the following program prints\n"[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2 # i is updated, then x[i] is updated\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'atom-identifiers': u'\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n', + 'atom-literals': u"\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", + 'attribute-access': u'\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\nThe attribute "__objclass__" is interpreted by the "inspect" module as\nspecifying the class where this object was defined (setting this\nappropriately can assist in runtime introspection of dynamic class\nattributes). For callables, it may indicate that an instance of the\ngiven type (or a subclass) is expected or required as the first\npositional argument (for example, CPython sets this attribute for\nunbound methods that are implemented in C).\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. *__slots__*\n reserves space for the declared variables and prevents the\n automatic creation of *__dict__* and *__weakref__* for each\n instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'attribute-references': u'\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier. This\nproduction can be customized by overriding the "__getattr__()" method.\nIf this attribute is not available, the exception "AttributeError" is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', + 'augassign': u'\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'binary': u'\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr |\n m_expr "//" u_expr| m_expr "/" u_expr |\n m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe "*" (multiplication) operator yields the product of its arguments.\nThe arguments must either both be numbers, or one argument must be an\ninteger and the other must be a sequence. In the former case, the\nnumbers are converted to a common type and then multiplied together.\nIn the latter case, sequence repetition is performed; a negative\nrepetition factor yields an empty sequence.\n\nThe "@" (at) operator is intended to be used for matrix\nmultiplication. No builtin Python types implement this operator.\n\nNew in version 3.5.\n\nThe "/" (division) and "//" (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Division of integers yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the "ZeroDivisionError" exception.\n\nThe "%" (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n"ZeroDivisionError" exception. The arguments may be floating point\nnumbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals "4*0.7 +\n0.34".) The modulo operator always yields a result with the same sign\nas its second operand (or zero); the absolute value of the result is\nstrictly smaller than the absolute value of the second operand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: "x == (x//y)*y + (x%y)". Floor division and modulo are also\nconnected with the built-in function "divmod()": "divmod(x, y) ==\n(x//y, x%y)". [2].\n\nIn addition to performing the modulo operation on numbers, the "%"\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *printf-style String Formatting*.\n\nThe floor division operator, the modulo operator, and the "divmod()"\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the "abs()" function if appropriate.\n\nThe "+" (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both be sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe "-" (subtraction) operator yields the difference of its arguments.\nThe numeric arguments are first converted to a common type.\n', + 'bitwise': u'\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe "&" operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe "^" operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe "|" operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', + 'bltin-code-objects': u'\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin "compile()" function and can be extracted from function objects\nthrough their "__code__" attribute. See also the "code" module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the "exec()" or "eval()" built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', + 'bltin-ellipsis-object': u'\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the\n"Ellipsis" singleton.\n\nIt is written as "Ellipsis" or "...".\n', + 'bltin-null-object': u'\nThe Null Object\n***************\n\nThis object is returned by functions that don\'t explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named "None" (a built-in name). "type(None)()" produces the\nsame singleton.\n\nIt is written as "None".\n', + 'bltin-type-objects': u'\nType Objects\n************\n\nType objects represent the various object types. An object\'s type is\naccessed by the built-in function "type()". There are no special\noperations on types. The standard module "types" defines names for\nall standard built-in types.\n\nTypes are written like this: "".\n', + 'booleans': u'\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: "False", "None", numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a "__bool__()" method.\n\nThe operator "not" yields "True" if its argument is false, "False"\notherwise.\n\nThe expression "x and y" first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression "x or y" first evaluates *x*; if *x* is true, its value\nis returned; otherwise, *y* is evaluated and the resulting value is\nreturned.\n\n(Note that neither "and" nor "or" restrict the value and type they\nreturn to "False" and "True", but rather return the last evaluated\nargument. This is sometimes useful, e.g., if "s" is a string that\nshould be replaced by a default value if it is empty, the expression\n"s or \'foo\'" yields the desired value. Because "not" has to create a\nnew value, it returns a boolean value regardless of the type of its\nargument (for example, "not \'foo\'" produces "False" rather than "\'\'".)\n', + 'break': u'\nThe "break" statement\n*********************\n\n break_stmt ::= "break"\n\n"break" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition within that\nloop.\n\nIt terminates the nearest enclosing loop, skipping the optional "else"\nclause if the loop has one.\n\nIf a "for" loop is terminated by "break", the loop control target\nkeeps its current value.\n\nWhen "break" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nloop.\n', + 'callable-types': u'\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n', + 'calls': u'\nCalls\n*****\n\nA call calls a callable object (e.g., a *function*) with a possibly\nempty series of *arguments*:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nAn optional trailing comma may be present after the positional and\nkeyword arguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n"__call__()" method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal *parameter* lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a "TypeError" exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is "None", it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a "TypeError"\nexception is raised. Otherwise, the list of filled slots is used as\nthe argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use "PyArg_ParseTuple()" to parse\ntheir arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "*identifier" is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "**identifier" is present; in this case, that formal\nparameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax "*expression" appears in the function call, "expression"\nmust evaluate to an iterable. Elements from this iterable are treated\nas if they were additional positional arguments; if there are\npositional arguments *x1*, ..., *xN*, and "expression" evaluates to a\nsequence *y1*, ..., *yM*, this is equivalent to a call with M+N\npositional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the "*expression" syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the "**expression" argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the "*expression" syntax\nto be used in the same call, so in practice this confusion does not\narise.\n\nIf the syntax "**expression" appears in the function call,\n"expression" must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both "expression" and as an explicit keyword argument, a\n"TypeError" exception is raised.\n\nFormal parameters using the syntax "*identifier" or "**identifier"\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly "None", unless it raises an\nexception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a "return"\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a "__call__()" method; the effect is then the\n same as if that method was called.\n', + 'class': u'\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', + 'comparisons': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', + 'compound': u'\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe "if", "while" and "for" statements implement traditional control\nflow constructs. "try" specifies exception handlers and/or cleanup\ncode for a group of statements, while the "with" statement allows the\nexecution of initialization and finalization code around a block of\ncode. Function and class definitions are also syntactically compound\nstatements.\n\nA compound statement consists of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of a suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which "if" clause a following "else" clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n"print()" calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a "NEWLINE" possibly followed by a\n"DEDENT". Also note that optional continuation clauses always begin\nwith a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling "else"\' problem is solved in Python by\nrequiring nested "if" statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe "if" statement\n==================\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n\n\nThe "while" statement\n=====================\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n\n\nThe "for" statement\n===================\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe "try" statement\n===================\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe "with" statement\n====================\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', + 'context-managers': u'\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', + 'continue': u'\nThe "continue" statement\n************************\n\n continue_stmt ::= "continue"\n\n"continue" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition or "finally"\nclause within that loop. It continues with the next cycle of the\nnearest enclosing loop.\n\nWhen "continue" passes control out of a "try" statement with a\n"finally" clause, that "finally" clause is executed before really\nstarting the next loop cycle.\n', + 'conversions': u'\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works as follows:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the\n other is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string as a\nleft argument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', + 'customization': u'\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called after the instance has been created (by "__new__()"), but\n before it is returned to the caller. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])".\n\n Because "__new__()" and "__init__()" work together in constructing\n objects ("__new__()" to create it, and "__init__()" to customise\n it), no non-"None" value may be returned by "__init__()"; doing so\n will cause a "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the second can be resolved by freeing the reference to the\n traceback object when it is no longer useful, and the third can\n be resolved by storing "None" in "sys.last_traceback". Circular\n references which are garbage are detected and cleaned up when the\n cyclic garbage collector is enabled (it\'s on by default). Refer\n to the documentation for the "gc" module for more information\n about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\n Changed in version 3.4: The __format__ method of "object" itself\n raises a "TypeError" if passed any non-empty string.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n', + 'debugger': u'\n"pdb" --- The Python Debugger\n*****************************\n\n**Source code:** Lib/pdb.py\n\n======================================================================\n\nThe module "pdb" defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n"Pdb". This is currently undocumented but easily understood by reading\nthe source. The extension interface uses the modules "bdb" and "cmd".\n\nThe debugger\'s prompt is "(Pdb)". Typical usage to run a program under\ncontrol of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\nChanged in version 3.3: Tab-completion via the "readline" module is\navailable for commands and command arguments, e.g. the current global\nand local names are offered as arguments of the "p" command.\n\n"pdb.py" can also be invoked as a script to debug other scripts. For\nexample:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: "pdb.py" now accepts a "-c" option that executes\ncommands as if given in a ".pdbrc" file, see *Debugger Commands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the "continue" command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type "continue", or you can\n step through the statement using "step" or "next" (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module "__main__" is used. (See the\n explanation of the built-in "exec()" or "eval()" functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When "runeval()" returns, it returns the\n value of the expression. Otherwise this function is similar to\n "run()".\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When "runcall()" returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n "sys.last_traceback".\n\nThe "run*" functions and "set_trace()" are aliases for instantiating\nthe "Pdb" class and calling the method of the same name. If you want\nto access further features, you have to do this yourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n "Pdb" is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying "cmd.Cmd" class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n "continue" command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n"h(elp)" means that either "h" or "help" can be used to enter the help\ncommand (but not "he" or "hel", nor "H" or "Help" or "HELP").\nArguments to commands must be separated by whitespace (spaces or\ntabs). Optional arguments are enclosed in square brackets ("[]") in\nthe command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n("|").\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a "list" command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint ("!"). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by ";;".\n(A single ";" is not used as it is the separator for multiple commands\nin a line that is passed to the Python parser.) No intelligence is\napplied to separating the commands; the input is split at the first\n";;" pair, even if it is in the middle of a quoted string.\n\nIf a file ".pdbrc" exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ".pdbrc" can now contain commands that\ncontinue debugging, such as "continue" or "next". Previously, these\ncommands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. "help pdb"\n displays the full documentation (the docstring of the "pdb"\n module). Since the *command* argument must be an identifier, "help\n exec" must be entered to get help on the "!" command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on "sys.path". Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for "break".\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just "end" to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) p some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with "end"; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between "next" and "step"\n is that "step" stops inside a called function, while "next"\n executes called functions at (nearly) full speed, only stopping at\n the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a "for" loop or out\n of a "finally" clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With "." as argument, list 11 lines around the current line. With\n one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by "->". If an\n exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ">>", if it differs\n from the current line.\n\n New in version 3.2: The ">>" marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for "list".\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\n Note: "print()" can also be used, but is not a debugger command\n --- this executes the Python "print()" function.\n\npp expression\n\n Like the "p" command, except the value of the expression is pretty-\n printed using the "pprint" module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the "code" module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by "%1", "%2", and so on, while "%*" is replaced by all\n the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ".pdbrc" file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n "global" statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with "shlex" and the result is used as the new\n "sys.argv". History, breakpoints, actions and debugger options are\n preserved. "restart" is an alias for "run".\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module\n is determined by the "__name__" in the frame globals.\n', + 'del': u'\nThe "del" statement\n*******************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a "global"\nstatement in the same code block. If the name is unbound, a\n"NameError" exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2: Previously it was illegal to delete a name\nfrom the local namespace if it occurs as a free variable in a nested\nblock.\n', + 'dict': u'\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', + 'dynamic-features': u'\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'else': u'\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', + 'exceptions': u'\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', + 'execmodel': u'\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\nas a command line argument to the interpreter) is a code block. A\nscript command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, an\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\n"global" statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', + 'exprlists': u'\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: "()".)\n', + 'floating': u'\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, "077e010" is legal, and denotes the same number\nas "77e10". The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator "-" and the\nliteral "1".\n', + 'for': u'\nThe "for" statement\n*******************\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order returned by the iterator. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there is no next\nitem.\n\nThe for-loop makes assignments to the variables(s) in the target list.\nThis overwrites all previous assignments to those variables including\nthose made in the suite of the for-loop:\n\n for i in range(10):\n print(i)\n i = 5 # this will not affect the for-loop\n # because i will be overwritten with the next\n # index in the range\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, they will not have been assigned to at\nall by the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', + 'formatstrings': u'\nFormat String Syntax\n********************\n\nThe "str.format()" method and the "Formatter" class share the same\nsyntax for format strings (although in the case of "Formatter",\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n"{}". Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n"{{" and "}}".\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point "\'!\'", and a *format_spec*, which is\npreceded by a colon "\':\'". These specify a non-default format for the\nreplacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings "\'10\'" or\n"\':-]\'") within a format string. The *arg_name* can be followed by any\nnumber of index or attribute expressions. An expression of the form\n"\'.name\'" selects the named attribute using "getattr()", while an\nexpression of the form "\'[index]\'" does an index lookup using\n"__getitem__()".\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so "\'{} {}\'" is equivalent to "\'{0} {1}\'".\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the "__format__()"\nmethod of the value itself. However, in some cases it is desirable to\nforce a type to be formatted as a string, overriding its own\ndefinition of formatting. By converting the value to a string before\ncalling "__format__()", the normal formatting logic is bypassed.\n\nThree conversion flags are currently supported: "\'!s\'" which calls\n"str()" on the value, "\'!r\'" which calls "repr()" and "\'!a\'" which\ncalls "ascii()".\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in "format()" function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string ("""") produces\nthe same result as if you had called "str()" on the value. A non-empty\nformat string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nIf a valid *align* value is specified, it can be preceded by a *fill*\ncharacter that can be any character and defaults to a space if\nomitted. Note that it is not possible to use "{" and "}" as *fill*\nchar while using the "str.format()" method; this limitation however\ndoesn\'t affect the "format()" function.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'<\'" | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | "\'>\'" | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | "\'=\'" | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | "\'^\'" | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'+\'" | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | "\'-\'" | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe "\'#\'" option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective "\'0b\'", "\'0o\'", or\n"\'0x\'" to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for "\'g\'" and "\'G\'"\nconversions, trailing zeros are not removed from the result.\n\nThe "\',\'" option signals the use of a comma for a thousands separator.\nFor a locale aware separator, use the "\'n\'" integer presentation type\ninstead.\n\nChanged in version 3.1: Added the "\',\'" option (see also **PEP 378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nPreceding the *width* field by a zero ("\'0\'") character enables sign-\naware zero-padding for numeric types. This is equivalent to a *fill*\ncharacter of "\'0\'" with an *alignment* type of "\'=\'".\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with "\'f\'" and "\'F\'", or before and after the decimal point\nfor a floating point value formatted with "\'g\'" or "\'G\'". For non-\nnumber types the field indicates the maximum field size - in other\nwords, how many characters will be used from the field content. The\n*precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'s\'" | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'s\'". |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'b\'" | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | "\'c\'" | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | "\'d\'" | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | "\'o\'" | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | "\'x\'" | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | "\'X\'" | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'d\'", except that it uses the |\n | | current locale setting to insert the appropriate number |\n | | separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'d\'". |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except "\'n\'"\nand None). When doing so, "float()" is used to convert the integer to\na floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'e\'" | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n | | The default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'E\'" | Exponent notation. Same as "\'e\'" except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | "\'f\'" | Fixed point. Displays the number as a fixed-point number. |\n | | The default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'F\'" | Fixed point. Same as "\'f\'", but converts "nan" to "NAN" |\n | | and "inf" to "INF". |\n +-----------+------------------------------------------------------------+\n | "\'g\'" | General format. For a given precision "p >= 1", this |\n | | rounds the number to "p" significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type "\'e\'" and precision "p-1" |\n | | would have exponent "exp". Then if "-4 <= exp < p", the |\n | | number is formatted with presentation type "\'f\'" and |\n | | precision "p-1-exp". Otherwise, the number is formatted |\n | | with presentation type "\'e\'" and precision "p-1". In both |\n | | cases insignificant trailing zeros are removed from the |\n | | significand, and the decimal point is also removed if |\n | | there are no remaining digits following it. Positive and |\n | | negative infinity, positive and negative zero, and nans, |\n | | are formatted as "inf", "-inf", "0", "-0" and "nan" |\n | | respectively, regardless of the precision. A precision of |\n | | "0" is treated as equivalent to a precision of "1". The |\n | | default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'G\'" | General format. Same as "\'g\'" except switches to "\'E\'" if |\n | | the number gets too large. The representations of infinity |\n | | and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'g\'", except that it uses the |\n | | current locale setting to insert the appropriate number |\n | | separator characters. |\n +-----------+------------------------------------------------------------+\n | "\'%\'" | Percentage. Multiplies the number by 100 and displays in |\n | | fixed ("\'f\'") format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to "\'g\'", except that fixed-point notation, when |\n | | used, has at least one digit past the decimal point. The |\n | | default precision is as high as needed to represent the |\n | | particular value. The overall effect is to match the |\n | | output of "str()" as altered by the other format |\n | | modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old "%"-formatting.\n\nIn most of the cases the syntax is similar to the old "%"-formatting,\nwith the addition of the "{}" and with ":" used instead of "%". For\nexample, "\'%03.2f\'" can be translated to "\'{:03.2f}\'".\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing "%s" and "%r":\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing "%+f", "%-f", and "% f" and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing "%x" and "%o" and converting the value to different bases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12): #doctest: +NORMALIZE_WHITESPACE\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', + 'function': u'\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n | "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n', + 'global': u'\nThe "global" statement\n**********************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe "global" statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without "global", although free variables may refer to\nglobals without being declared global.\n\nNames listed in a "global" statement must not be used in the same code\nblock textually preceding that "global" statement.\n\nNames listed in a "global" statement must not be defined as formal\nparameters or in a "for" loop control target, "class" definition,\nfunction definition, or "import" statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the two restrictions, but programs should not abuse this\nfreedom, as future implementations may enforce them or silently change\nthe meaning of the program.\n\n**Programmer\'s note:** the "global" is a directive to the parser. It\napplies only to code parsed at the same time as the "global"\nstatement. In particular, a "global" statement contained in a string\nor code object supplied to the built-in "exec()" function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by "global" statements in the\ncode containing the function call. The same applies to the "eval()"\nand "compile()" functions.\n', + 'id-classes': u'\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'identifiers': u'\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters "A" through "Z", the underscore "_" and, except for the first\ncharacter, the digits "0" through "9".\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n"unicodedata" module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'if': u'\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', + 'imaginary': u'\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., "(3+4j)". Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', + 'import': u'\nThe "import" statement\n**********************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nThe basic import statement (no "from" clause) is executed in two\nsteps:\n\n1. find a module, loading and initializing it if necessary\n\n2. define a name or names in the local namespace for the scope\n where the "import" statement occurs.\n\nWhen the statement contains multiple clauses (separated by commas) the\ntwo steps are carried out separately for each clause, just as though\nthe clauses had been separated out into individiual import statements.\n\nThe details of the first step, finding and loading modules are\ndescribed in greater detail in the section on the *import system*,\nwhich also describes the various types of packages and modules that\ncan be imported, as well as all the hooks that can be used to\ncustomize the import system. Note that failures in this step may\nindicate either that the module could not be located, *or* that an\nerror occurred while initializing the module, which includes execution\nof the module\'s code.\n\nIf the requested module is retrieved successfully, it will be made\navailable in the local namespace in one of three ways:\n\n* If the module name is followed by "as", then the name following\n "as" is bound directly to the imported module.\n\n* If no other name is specified, and the module being imported is a\n top level module, the module\'s name is bound in the local namespace\n as a reference to the imported module\n\n* If the module being imported is *not* a top level module, then the\n name of the top level package that contains the module is bound in\n the local namespace as a reference to the top level package. The\n imported module must be accessed using its full qualified name\n rather than directly\n\nThe "from" form uses a slightly more complex process:\n\n1. find the module specified in the "from" clause, loading and\n initializing it if necessary;\n\n2. for each of the identifiers specified in the "import" clauses:\n\n 1. check if the imported module has an attribute by that name\n\n 2. if not, attempt to import a submodule with that name and then\n check the imported module again for that attribute\n\n 3. if the attribute is not found, "ImportError" is raised.\n\n 4. otherwise, a reference to that value is stored in the local\n namespace, using the name in the "as" clause if it is present,\n otherwise using the attribute name\n\nExamples:\n\n import foo # foo imported and bound locally\n import foo.bar.baz # foo.bar.baz imported, foo bound locally\n import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb\n from foo.bar import baz # foo.bar.baz imported and bound as baz\n from foo import attr # foo imported and foo.attr bound as attr\n\nIf the list of identifiers is replaced by a star ("\'*\'"), all public\nnames defined in the module are bound in the local namespace for the\nscope where the "import" statement occurs.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named "__all__"; if defined, it must\nbe a sequence of strings which are names defined or imported by that\nmodule. The names given in "__all__" are all considered public and\nare required to exist. If "__all__" is not defined, the set of public\nnames includes all names found in the module\'s namespace which do not\nbegin with an underscore character ("\'_\'"). "__all__" should contain\nthe entire public API. It is intended to avoid accidentally exporting\nitems that are not part of the API (such as library modules which were\nimported and used within the module).\n\nThe wild card form of import --- "from module import *" --- is only\nallowed at the module level. Attempting to use it in class or\nfunction definitions will raise a "SyntaxError".\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after "from" you\ncan specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n"from . import mod" from a module in the "pkg" package then you will\nend up importing "pkg.mod". If you execute "from ..subpkg2 import mod"\nfrom within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\nspecification for relative imports is contained within **PEP 328**.\n\n"importlib.import_module()" is provided to support applications that\ndetermine dynamically the modules to be loaded.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python where the feature\nbecomes standard.\n\nThe future statement is intended to ease migration to future versions\nof Python that introduce incompatible changes to the language. It\nallows use of the new features on a per-module basis before the\nrelease in which the feature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are "absolute_import",\n"division", "generators", "unicode_literals", "print_function",\n"nested_scopes" and "with_statement". They are all redundant because\nthey are always enabled, and only kept for backwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module "__future__", described later, and it will\nbe imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions "exec()" and\n"compile()" that occur in a module "M" containing a future statement\nwill, by default, use the new syntax or semantics associated with the\nfuture statement. This can be controlled by optional arguments to\n"compile()" --- see the documentation of that function for details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also: **PEP 236** - Back to the __future__\n\n The original proposal for the __future__ mechanism.\n', + 'in': u'\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of differing types depends on whether either of\nthe types provide explicit support for the comparison. Most numeric\ntypes can be compared with one another. When cross-type comparison is\nnot supported, the comparison method returns "NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', + 'integers': u'\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', + 'lambda': u'\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda expressions (sometimes called lambda forms) are used to create\nanonymous functions. The expression "lambda arguments: expression"\nyields a function object. The unnamed object behaves like a function\nobject defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda expressions cannot contain\nstatements or annotations.\n', + 'lists': u'\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', + 'naming': u'\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\nas a command line argument to the interpreter) is a code block. A\nscript command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, an\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\n"global" statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'nonlocal': u'\nThe "nonlocal" statement\n************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe "nonlocal" statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope excluding\nglobals. This is important because the default behavior for binding is\nto search the local namespace first. The statement allows\nencapsulated code to rebind variables outside of the local scope\nbesides the global (module) scope.\n\nNames listed in a "nonlocal" statement, unlike those listed in a\n"global" statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a "nonlocal" statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also: **PEP 3104** - Access to Names in Outer Scopes\n\n The specification for the "nonlocal" statement.\n', + 'numbers': u'\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator \'"-"\' and the\nliteral "1".\n', + 'numeric-types': u'\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__matmul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "@", "/", "//", "%", "divmod()",\n "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, to\n evaluate the expression "x + y", where *x* is an instance of a\n class that has an "__add__()" method, "x.__add__(y)" is called.\n The "__divmod__()" method should be the equivalent to using\n "__floordiv__()" and "__mod__()"; it should not be related to\n "__truediv__()". Note that "__pow__()" should be defined to accept\n an optional third argument if the ternary version of the built-in\n "pow()" function is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rmatmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "@", "/", "//", "%", "divmod()",\n "pow()", "**", "<<", ">>", "&", "^", "|") with reflected (swapped)\n operands. These functions are only called if the left operand does\n not support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__imatmul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", "**=",\n "<<=", ">>=", "&=", "^=", "|="). These methods should attempt to\n do the operation in-place (modifying *self*) and return the result\n (which could be, but does not have to be, *self*). If a specific\n method is not defined, the augmented assignment falls back to the\n normal methods. For instance, if *x* is an instance of a class\n with an "__iadd__()" method, "x += y" is equivalent to "x =\n x.__iadd__(y)" . Otherwise, "x.__add__(y)" and "y.__radd__(x)" are\n considered, as with the evaluation of "x + y". In certain\n situations, augmented assignment can result in unexpected errors\n (see *Why does a_tuple[i] += [\'item\'] raise an exception when the\n addition works?*), but this behavior is in fact part of the data\n model.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: In order to have a coherent integer type class, when\n "__index__()" is defined "__int__()" should also be defined, and\n both should return the same value.\n', + 'objects': u'\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'"is"\' operator compares the\nidentity of two objects; the "id()" function returns an integer\nrepresenting its identity.\n\n**CPython implementation detail:** For CPython, "id(x)" is the memory\naddress where "x" is stored.\n\nAn object\'s type determines the operations that the object supports\n(e.g., "does it have a length?") and also defines the possible values\nfor objects of that type. The "type()" function returns an object\'s\ntype (which is an object itself). Like its identity, an object\'s\n*type* is also unchangeable. [1]\n\nThe *value* of some objects can change. Objects whose value can\nchange are said to be *mutable*; objects whose value is unchangeable\nonce they are created are called *immutable*. (The value of an\nimmutable container object that contains a reference to a mutable\nobject can change when the latter\'s value is changed; however the\ncontainer is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the "gc" module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (so\nyou should always close files explicitly).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'"try"..."except"\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a "close()" method. Programs\nare strongly recommended to explicitly close such objects. The\n\'"try"..."finally"\' statement and the \'"with"\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after "a = 1; b = 1",\n"a" and "b" may or may not refer to the same object with the value\none, depending on the implementation, but after "c = []; d = []", "c"\nand "d" are guaranteed to refer to two different, unique, newly\ncreated empty lists. (Note that "c = d = []" assigns the same object\nto both "c" and "d".)\n', + 'operator-summary': u'\nOperator precedence\n*******************\n\nThe following table summarizes the operator precedence in Python, from\nlowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for exponentiation, which\ngroups from right to left).\n\nNote that comparisons, membership tests, and identity tests, all have\nthe same precedence and have a left-to-right chaining feature as\ndescribed in the *Comparisons* section.\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| "lambda" | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| "if" -- "else" | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| "or" | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| "and" | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| "not" "x" | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| "in", "not in", "is", "is not", "<", "<=", ">", | Comparisons, including membership |\n| ">=", "!=", "==" | tests and identity tests |\n+-------------------------------------------------+---------------------------------------+\n| "|" | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| "^" | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| "&" | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| "<<", ">>" | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| "+", "-" | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| "*", "@", "/", "//", "%" | Multiplication, matrix multiplication |\n| | division, remainder [5] |\n+-------------------------------------------------+---------------------------------------+\n| "+x", "-x", "~x" | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| "**" | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| "x[index]", "x[index:index]", | Subscription, slicing, call, |\n| "x(arguments...)", "x.attribute" | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| "(expressions...)", "[expressions...]", "{key: | Binding or tuple display, list |\n| value...}", "{expressions...}" | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While "abs(x%y) < abs(y)" is true mathematically, for floats\n it may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that "-1e-100 % 1e100" have the same\n sign as "1e100", the computed result is "-1e-100 + 1e100", which\n is numerically exactly equal to "1e100". The function\n "math.fmod()" returns a result whose sign matches the sign of the\n first argument instead, and so returns "-1e-100" in this case.\n Which approach is more appropriate depends on the application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for "x//y" to be one larger than "(x-x%y)//y" due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that "divmod(x,y)[0] * y + x % y" be very close\n to "x".\n\n[3] While comparisons between strings make sense at the byte\n level, they may be counter-intuitive to users. For example, the\n strings ""\\u00C7"" and ""\\u0327\\u0043"" compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using "unicodedata.normalize()".\n\n[4] Due to automatic garbage-collection, free lists, and the\n dynamic nature of descriptors, you may notice seemingly unusual\n behaviour in certain uses of the "is" operator, like those\n involving comparisons between instance methods, or constants.\n Check their documentation for more info.\n\n[5] The "%" operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator "**" binds less tightly than an arithmetic\n or bitwise unary operator on its right, that is, "2**-1" is "0.5".\n', + 'pass': u'\nThe "pass" statement\n********************\n\n pass_stmt ::= "pass"\n\n"pass" is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', + 'power': u'\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): "-1**2" results in "-1".\n\nThe power operator has the same semantics as the built-in "pow()"\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n"10**2" returns "100", but "10**-2" returns "0.01".\n\nRaising "0.0" to a negative power results in a "ZeroDivisionError".\nRaising a negative number to a fractional power results in a "complex"\nnumber. (In earlier versions it raised a "ValueError".)\n', + 'raise': u'\nThe "raise" statement\n*********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, "raise" re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a "RuntimeError" exception is raised indicating\nthat this is an error.\n\nOtherwise, "raise" evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n"BaseException". If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the "__traceback__" attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the "with_traceback()" exception method (which returns\nthe same exception instance, with its traceback set to its argument),\nlike so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe "from" clause is used for exception chaining: if given, the second\n*expression* must be another exception class or instance, which will\nthen be attached to the raised exception as the "__cause__" attribute\n(which is writable). If the raised exception is not handled, both\nexceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler or a "finally" clause: the previous exception is\nthen attached as the new exception\'s "__context__" attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', + 'return': u'\nThe "return" statement\n**********************\n\n return_stmt ::= "return" [expression_list]\n\n"return" may only occur syntactically nested in a function definition,\nnot within a nested class definition.\n\nIf an expression list is present, it is evaluated, else "None" is\nsubstituted.\n\n"return" leaves the current function call with the expression list (or\n"None") as return value.\n\nWhen "return" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nfunction.\n\nIn a generator function, the "return" statement indicates that the\ngenerator is done and will cause "StopIteration" to be raised. The\nreturned value (if any) is used as an argument to construct\n"StopIteration" and becomes the "StopIteration.value" attribute.\n', + 'sequence-types': u'\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__missing__(self, key)\n\n Called by "dict"."__getitem__()" to implement "self[key]" for dict\n subclasses when key is not in the dictionary.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n', + 'shifting': u'\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as floor division by "pow(2,n)".\nA left shift by *n* bits is defined as multiplication with "pow(2,n)".\n\nNote: In the current implementation, the right-hand operand is\n required to be at most "sys.maxsize". If the right-hand operand is\n larger than "sys.maxsize" an "OverflowError" exception is raised.\n', + 'slicings': u'\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or "del" statements. The syntax for a slicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary is indexed\n(using the same "__getitem__()" method as normal subscription) with a\nkey that is constructed from the slice list, as follows. If the slice\nlist contains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n"start", "stop" and "step" attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting "None" for missing expressions.\n', + 'specialattrs': u'\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the "dir()" built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in "__mro__".\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found\n in the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list "[1, 2]" is considered equal to\n "[1.0, 2.0]", and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property\n being one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase),\n or "Lt" (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a\n singleton tuple whose only element is the tuple to be formatted.\n', + 'specialnames': u'\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named "__getitem__()", and "x" is an instance of this class,\nthen "x[i]" is roughly equivalent to "type(x).__getitem__(x, i)".\nExcept where mentioned, attempts to execute an operation raise an\nexception when no appropriate method is defined (typically\n"AttributeError" or "TypeError").\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n"NodeList" interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called after the instance has been created (by "__new__()"), but\n before it is returned to the caller. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])".\n\n Because "__new__()" and "__init__()" work together in constructing\n objects ("__new__()" to create it, and "__init__()" to customise\n it), no non-"None" value may be returned by "__init__()"; doing so\n will cause a "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the second can be resolved by freeing the reference to the\n traceback object when it is no longer useful, and the third can\n be resolved by storing "None" in "sys.last_traceback". Circular\n references which are garbage are detected and cleaned up when the\n cyclic garbage collector is enabled (it\'s on by default). Refer\n to the documentation for the "gc" module for more information\n about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\n Changed in version 3.4: The __format__ method of "object" itself\n raises a "TypeError" if passed any non-empty string.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\nThe attribute "__objclass__" is interpreted by the "inspect" module as\nspecifying the class where this object was defined (setting this\nappropriately can assist in runtime introspection of dynamic class\nattributes). For callables, it may indicate that an instance of the\ngiven type (or a subclass) is expected or required as the first\npositional argument (for example, CPython sets this attribute for\nunbound methods that are implemented in C).\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. *__slots__*\n reserves space for the declared variables and prevents the\n automatic creation of *__dict__* and *__weakref__* for each\n instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using "type()". The class body is\nexecuted in a new namespace and the class name is bound locally to the\nresult of "type(name, bases, namespace)".\n\nThe class creation process can be customised by passing the\n"metaclass" keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both "MyClass" and "MySubclass" are instances\nof "Meta":\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then "type()" is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n "type()", then it is used directly as the metaclass\n\n* if an instance of "type()" is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. "type(cls)") of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with "TypeError".\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a "__prepare__" attribute,\nit is called as "namespace = metaclass.__prepare__(name, bases,\n**kwds)" (where the additional keyword arguments, if any, come from\nthe class definition).\n\nIf the metaclass has no "__prepare__" attribute, then the class\nnamespace is initialised as an empty "dict()" instance.\n\nSee also: **PEP 3115** - Metaclasses in Python 3000\n\n Introduced the "__prepare__" namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as "exec(body, globals(),\nnamespace)". The key difference from a normal call to "exec()" is that\nlexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling "metaclass(name, bases,\nnamespace, **kwds)" (the additional keywords passed here are the same\nas those passed to "__prepare__").\n\nThis class object is the one that will be referenced by the zero-\nargument form of "super()". "__class__" is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either "__class__" or "super". This allows the zero argument form\nof "super()" to correctly identify the class being defined based on\nlexical scoping, while the class or instance that was used to make the\ncurrent call is identified based on the first argument passed to the\nmethod.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also: **PEP 3135** - New super\n\n Describes the implicit "__class__" closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n"collections.OrderedDict" to remember the order that class variables\nare defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s "__prepare__()" method which returns an\nempty "collections.OrderedDict". That mapping records the methods and\nattributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s "__new__()" method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called "members".\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n"isinstance()" and "issubclass()" built-in functions.\n\nIn particular, the metaclass "abc.ABCMeta" implements these methods in\norder to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n "isinstance(instance, class)".\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n "issubclass(subclass, class)".\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also: **PEP 3119** - Introducing Abstract Base Classes\n\n Includes the specification for customizing "isinstance()" and\n "issubclass()" behavior through "__instancecheck__()" and\n "__subclasscheck__()", with motivation for this functionality in\n the context of adding Abstract Base Classes (see the "abc"\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__missing__(self, key)\n\n Called by "dict"."__getitem__()" to implement "self[key]" for dict\n subclasses when key is not in the dictionary.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__matmul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "@", "/", "//", "%", "divmod()",\n "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, to\n evaluate the expression "x + y", where *x* is an instance of a\n class that has an "__add__()" method, "x.__add__(y)" is called.\n The "__divmod__()" method should be the equivalent to using\n "__floordiv__()" and "__mod__()"; it should not be related to\n "__truediv__()". Note that "__pow__()" should be defined to accept\n an optional third argument if the ternary version of the built-in\n "pow()" function is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rmatmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "@", "/", "//", "%", "divmod()",\n "pow()", "**", "<<", ">>", "&", "^", "|") with reflected (swapped)\n operands. These functions are only called if the left operand does\n not support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__imatmul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", "**=",\n "<<=", ">>=", "&=", "^=", "|="). These methods should attempt to\n do the operation in-place (modifying *self*) and return the result\n (which could be, but does not have to be, *self*). If a specific\n method is not defined, the augmented assignment falls back to the\n normal methods. For instance, if *x* is an instance of a class\n with an "__iadd__()" method, "x += y" is equivalent to "x =\n x.__iadd__(y)" . Otherwise, "x.__add__(y)" and "y.__radd__(x)" are\n considered, as with the evaluation of "x + y". In certain\n situations, augmented assignment can result in unexpected errors\n (see *Why does a_tuple[i] += [\'item\'] raise an exception when the\n addition works?*), but this behavior is in fact part of the data\n model.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: In order to have a coherent integer type class, when\n "__index__()" is defined "__int__()" should also be defined, and\n both should return the same value.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as "__hash__()" and "__repr__()" that are implemented by\nall objects, including type objects. If the implicit lookup of these\nmethods used the conventional lookup process, they would fail when\ninvoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe "__getattribute__()" method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the "__getattribute__()" machinery in this fashion provides\nsignificant scope for speed optimisations within the interpreter, at\nthe cost of some flexibility in the handling of special methods (the\nspecial method *must* be set on the class object itself in order to be\nconsistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type,\n under certain controlled conditions. It generally isn\'t a good\n idea though, since it can lead to some very strange behaviour if\n it is handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as "__add__()") fails the operation is not\n supported, which is why the reflected method is not called.\n', + 'string-methods': u'\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see "str.format()",\n*Format String Syntax* and *String Formatting*) and the other based on\nC "printf" style formatting that handles a narrower range of types and\nis slightly harder to use correctly, but is often faster for the cases\nit can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the "re" module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter "\'\xdf\'" is equivalent to ""ss"".\n Since it is already lowercase, "lower()" would do nothing to "\'\xdf\'";\n "casefold()" converts it to ""ss"".\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is an ASCII space). The\n original string is returned if *width* is less than or equal to\n "len(s)".\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is "\'utf-8\'". *errors* may be given to set a different\n error handling scheme. The default for *errors* is "\'strict\'",\n meaning that encoding errors raise a "UnicodeError". Other possible\n values are "\'ignore\'", "\'replace\'", "\'xmlcharrefreplace\'",\n "\'backslashreplace\'" and any other name registered via\n "codecs.register_error()", see section *Error Handlers*. For a list\n of possible encodings, see section *Standard Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return "True" if the string ends with the specified *suffix*,\n otherwise return "False". *suffix* can also be a tuple of suffixes\n to look for. With optional *start*, test beginning at that\n position. With optional *end*, stop comparing at that position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab ("\\t"), one or more space characters are inserted in the result\n until the current column is equal to the next tab position. (The\n tab character itself is not copied.) If the character is a newline\n ("\\n") or return ("\\r"), it is copied and the current column is\n reset to zero. Any other character is copied unchanged and the\n current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" if *sub* is not found.\n\n Note: The "find()" method should be used only if you need to know\n the position of *sub*. To check if *sub* is a substring or not,\n use the "in" operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces "{}". Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to "str.format(**mapping)", except that "mapping" is used\n directly and not copied to a "dict". This is useful if for example\n "mapping" is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like "find()", but raise "ValueError" when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character "c"\n is alphanumeric if one of the following returns "True":\n "c.isalpha()", "c.isdecimal()", "c.isdigit()", or "c.isnumeric()".\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use "keyword.iskeyword()" to test for reserved identifiers such as\n "def" and "class".\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when "repr()" is\n invoked on a string. It has no bearing on the handling of strings\n written to "sys.stdout" or "sys.stderr".)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A "TypeError" will be raised if there are\n any non-string values in *iterable*, including "bytes" objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is an ASCII\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n "str.translate()".\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like "rfind()" but raises "ValueError" when the substring *sub* is\n not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is an ASCII\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n "None", any whitespace string is a separator. Except for splitting\n from the right, "rsplit()" behaves like "split()" which is\n described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most "maxsplit+1"\n elements). If *maxsplit* is not specified or "-1", then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', \'2\']"). The *sep* argument\n may consist of multiple characters (for example,\n "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', \'3\']"). Splitting an\n empty string with a specified separator returns "[\'\']".\n\n For example:\n\n >>> \'1,2,3\'.split(\',\')\n [\'1\', \'2\', \'3\']\n >>> \'1,2,3\'.split(\',\', maxsplit=1)\n [\'1\', \'2,3\']\n >>> \'1,2,,3,\'.split(\',\')\n [\'1\', \'2\', \'\', \'3\', \'\']\n\n If *sep* is not specified or is "None", a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a "None" separator returns "[]".\n\n For example:\n\n >>> \'1 2 3\'.split()\n [\'1\', \'2\', \'3\']\n >>> \'1 2 3\'.split(maxsplit=1)\n [\'1\', \'2 3\']\n >>> \' 1 2 3 \'.split()\n [\'1\', \'2\', \'3\']\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example:\n\n >>> \'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()\n [\'ab c\', \'\', \'de fg\', \'kl\']\n >>> \'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines(keepends=True)\n [\'ab c\\n\', \'\\n\', \'de fg\\r\', \'kl\\r\\n\']\n\n Unlike "split()" when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line:\n\n >>> "".splitlines()\n []\n >>> "One line\\n".splitlines()\n [\'One line\']\n\n For comparison, "split(\'\\n\')" gives:\n\n >>> \'\'.split(\'\\n\')\n [\'\']\n >>> \'Two lines\\n\'.split(\'\\n\')\n [\'Two lines\', \'\']\n\nstr.startswith(prefix[, start[, end]])\n\n Return "True" if string starts with the *prefix*, otherwise return\n "False". *prefix* can also be a tuple of prefixes to look for.\n With optional *start*, test string beginning at that position.\n With optional *end*, stop comparing string at that position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or "None", the *chars*\n argument defaults to removing whitespace. The *chars* argument is\n not a prefix or suffix; rather, all combinations of its values are\n stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n "s.swapcase().swapcase() == s".\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n For example:\n\n >>> \'Hello world\'.title()\n \'Hello World\'\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or "None". Unmapped\n characters are left untouched. Characters mapped to "None" are\n deleted.\n\n You can use "str.maketrans()" to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom\n character mapping codec using the "codecs" module (see\n "encodings.cp1251" for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that "str.upper().isupper()" might be\n "False" if "s" contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return a copy of the string left filled with ASCII "\'0\'" digits to\n make a string of length *width*. A leading sign prefix ("\'+\'"/"\'-\'"\n is handled by inserting the padding *after* the sign character\n rather than before. The original string is returned if *width* is\n less than or equal to "len(s)".\n\n For example:\n\n >>> "42".zfill(5)\n \'00042\'\n >>> "-42".zfill(5)\n \'-0042\'\n', + 'strings': u'\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "R" | "U"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the "stringprefix" or "bytesprefix"\nand the rest of the literal. The source character set is defined by\nthe encoding declaration; it is UTF-8 if no encoding declaration is\ngiven in the source file; see section *Encoding declarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes ("\'") or double quotes ("""). They can also be enclosed\nin matching groups of three single or double quotes (these are\ngenerally referred to as *triple-quoted strings*). The backslash\n("\\") character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with "\'b\'" or "\'B\'"; they produce\nan instance of the "bytes" type instead of the "str" type. They may\nonly contain ASCII characters; bytes with a numeric value of 128 or\ngreater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix string literals with a\n"u" prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter "\'r\'" or "\'R\'"; such strings are called *raw strings* and treat\nbackslashes as literal characters. As a result, in string literals,\n"\'\\U\'" and "\'\\u\'" escapes in raw strings are not treated specially.\nGiven that Python 2.x\'s raw unicode literals behave differently than\nPython 3.x\'s the "\'ur\'" syntax is not supported.\n\nNew in version 3.3: The "\'rb\'" prefix of raw bytes literals has been\nadded as a synonym of "\'br\'".\n\nNew in version 3.3: Support for the unicode legacy literal\n("u\'value\'") was reintroduced to simplify the maintenance of dual\nPython 2.x and 3.x codebases. See **PEP 414** for more information.\n\nIn triple-quoted literals, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the literal. (A "quote" is the character used to open the\nliteral, i.e. either "\'" or """.)\n\nUnless an "\'r\'" or "\'R\'" prefix is present, escape sequences in string\nand bytes literals are interpreted according to rules similar to those\nused by Standard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\newline" | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| "\\\\" | Backslash ("\\") | |\n+-------------------+-----------------------------------+---------+\n| "\\\'" | Single quote ("\'") | |\n+-------------------+-----------------------------------+---------+\n| "\\"" | Double quote (""") | |\n+-------------------+-----------------------------------+---------+\n| "\\a" | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| "\\b" | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| "\\f" | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| "\\n" | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| "\\r" | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| "\\t" | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| "\\v" | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| "\\ooo" | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| "\\xhh" | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\N{name}" | Character named *name* in the | (4) |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| "\\uxxxx" | Character with 16-bit hex value | (5) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| "\\Uxxxxxxxx" | Character with 32-bit hex value | (6) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the\n byte with the given value. In a string literal, these escapes\n denote a Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can\n be encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way. Exactly eight\n hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the result*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw literal, quotes can be escaped with a backslash, but the\nbackslash remains in the result; for example, "r"\\""" is a valid\nstring literal consisting of two characters: a backslash and a double\nquote; "r"\\"" is not a valid string literal (even a raw string cannot\nend in an odd number of backslashes). Specifically, *a raw literal\ncannot end in a single backslash* (since the backslash would escape\nthe following quote character). Note also that a single backslash\nfollowed by a newline is interpreted as those two characters as part\nof the literal, *not* as a line continuation.\n', + 'subscriptions': u'\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription\n(lists or dictionaries for example). User-defined objects can support\nsubscription by defining a "__getitem__()" method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a "__getitem__()"\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that "x[-1]" selects the last item of "x").\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero). Since the support for\nnegative indices and slicing occurs in the object\'s "__getitem__()"\nmethod, subclasses overriding this method will need to explicitly add\nthat support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', + 'truth': u'\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an "if" or\n"while" condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* "None"\n\n* "False"\n\n* zero of any numeric type, for example, "0", "0.0", "0j".\n\n* any empty sequence, for example, "\'\'", "()", "[]".\n\n* any empty mapping, for example, "{}".\n\n* instances of user-defined classes, if the class defines a\n "__bool__()" or "__len__()" method, when that method returns the\n integer zero or "bool" value "False". [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn "0" or "False" for false and "1" or "True" for true, unless\notherwise stated. (Important exception: the Boolean operations "or"\nand "and" always return one of their operands.)\n', + 'try': u'\nThe "try" statement\n*******************\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be accessed via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n >>> def f():\n ... try:\n ... 1/0\n ... finally:\n ... return 42\n ...\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n', + 'types': u'\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name "None". It\n is used to signify the absence of a value in many situations, e.g.,\n it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n "NotImplemented". Numeric methods and rich comparison methods\n should return this value if they do not implement the operation for\n the operands provided. (The interpreter will then try the\n reflected operation, or some other fallback, depending on the\n operator.) Its truth value is true.\n\n See *Implementing the arithmetic operations* for more details.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal "..." or the\n built-in name "Ellipsis". Its truth value is true.\n\n"numbers.Number"\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n "numbers.Integral"\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers ("int")\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans ("bool")\n These represent the truth values False and True. The two\n objects representing the values "False" and "True" are the\n only Boolean objects. The Boolean type is a subtype of the\n integer type, and Boolean values behave like the values 0 and\n 1, respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ""False"" or\n ""True"" are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n "numbers.Real" ("float")\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these are\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n "numbers.Complex" ("complex")\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number "z" can be retrieved through the read-only\n attributes "z.real" and "z.imag".\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function "len()" returns the number of items\n of a sequence. When the length of a sequence is *n*, the index set\n contains the numbers 0, 1, ..., *n*-1. Item *i* of sequence *a* is\n selected by "a[i]".\n\n Sequences also support slicing: "a[i:j]" selects all items with\n index *k* such that *i* "<=" *k* "<" *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: "a[i:j:k]" selects all items of *a* with index *x* where\n "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode code\n points. All the code points in the range "U+0000 - U+10FFFF"\n can be represented in a string. Python doesn\'t have a "char"\n type; instead, every code point in the string is represented\n as a string object with length "1". The built-in function\n "ord()" converts a code point from its string form to an\n integer in the range "0 - 10FFFF"; "chr()" converts an\n integer in the range "0 - 10FFFF" to the corresponding length\n "1" string object. "str.encode()" can be used to convert a\n "str" to "bytes" using the given text encoding, and\n "bytes.decode()" can be used to achieve the opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like "b\'abc\'") and the built-in function\n "bytes()" can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the "decode()"\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and "del" (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in "bytearray()" constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module "array" provides an additional example of a\n mutable sequence type, as does the "collections" module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function "len()"\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., "1" and\n "1.0"), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n "set()" constructor and can be modified afterwards by several\n methods, such as "add()".\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in "frozenset()" constructor. As a frozenset is immutable\n and *hashable*, it can be used again as an element of another\n set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation "a[k]" selects the item indexed by "k"\n from the mapping "a"; this can be used in expressions and as the\n target of assignments or "del" statements. The built-in function\n "len()" returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., "1" and "1.0")\n then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the "{...}"\n notation (see section *Dictionary displays*).\n\n The extension modules "dbm.ndbm" and "dbm.gnu" provide\n additional examples of mapping types, as does the "collections"\n module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | "__doc__" | The function\'s documentation | Writable |\n | | string, or "None" if | |\n | | unavailable; not inherited by | |\n | | subclasses | |\n +---------------------------+---------------------------------+-------------+\n | "__name__" | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__qualname__" | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n | | function was defined in, or | |\n | | "None" if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or "None" if no arguments have | |\n | | a default value | |\n +---------------------------+---------------------------------+-------------+\n | "__code__" | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | "__dict__" | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n | | contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | "__annotations__" | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | and "\'return\'" for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | "__kwdefaults__" | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: "__self__" is the class instance\n object, "__func__" is the function object; "__doc__" is the\n method\'s documentation (same as "__func__.__doc__"); "__name__"\n is the method name (same as "__func__.__name__"); "__module__"\n is the name of the module the method was defined in, or "None"\n if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its "__self__" attribute is the instance, and the method object\n is said to be bound. The new method\'s "__func__" attribute is\n the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the "__func__"\n attribute of the new instance is not the original method object\n but its "__func__" attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its "__self__" attribute\n is the class itself, and its "__func__" attribute is the\n function object underlying the class method.\n\n When an instance method object is called, the underlying\n function ("__func__") is called, inserting the class instance\n ("__self__") in front of the argument list. For instance, when\n "C" is a class which contains a definition for a function "f()",\n and "x" is an instance of "C", calling "x.f(1)" is equivalent to\n calling "C.f(x, 1)".\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in "__self__" will actually\n be the class itself, so that calling either "x.f(1)" or "C.f(1)"\n is equivalent to calling "f(C,1)" where "f" is the underlying\n function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "iterator.__next__()" method will cause the\n function to execute until it provides a value using the "yield"\n statement. When the function executes a "return" statement or\n falls off the end, a "StopIteration" exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are "len()" and "math.sin()"\n ("math" is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: "__doc__" is the function\'s documentation\n string, or "None" if unavailable; "__name__" is the function\'s\n name; "__self__" is set to "None" (but see the next item);\n "__module__" is the name of the module the function was defined\n in or "None" if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n "alist.append()", assuming *alist* is a list object. In this\n case, the special read-only attribute "__self__" is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override "__new__()". The arguments of the\n call are passed to "__new__()" and, in the typical case, to\n "__init__()" to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a "__call__()" method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the "import"\n statement (see "import"), or by calling functions such as\n "importlib.import_module()" and built-in "__import__()". A module\n object has a namespace implemented by a dictionary object (this is\n the dictionary referenced by the "__globals__" attribute of\n functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., "m.x" is equivalent\n to "m.__dict__["x"]". A module object does not contain the code\n object used to initialize the module (since it isn\'t needed once\n the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s name;\n "__doc__" is the module\'s documentation string, or "None" if\n unavailable; "__file__" is the pathname of the file from which the\n module was loaded, if it was loaded from a file. The "__file__"\n attribute may be missing for certain types of modules, such as C\n modules that are statically linked into the interpreter; for\n extension modules loaded dynamically from a shared library, it is\n the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., "C.x" is translated to\n "C.__dict__["x"]" (although there are a number of hooks which allow\n for other means of locating attributes). When the attribute name is\n not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n https://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n class method object, it is transformed into an instance method\n object whose "__self__" attributes is "C". When it would yield a\n static method object, it is transformed into the object wrapped by\n the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its "__dict__".\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: "__name__" is the class name; "__module__" is\n the module name in which the class was defined; "__dict__" is the\n dictionary containing the class\'s namespace; "__bases__" is a tuple\n (possibly empty or a singleton) containing the base classes, in the\n order of their occurrence in the base class list; "__doc__" is the\n class\'s documentation string, or None if undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose "__self__" attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s "__dict__".\n If no class attribute is found, and the object\'s class has a\n "__getattr__()" method, that is called to satisfy the lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n "__setattr__()" or "__delattr__()" method, this is called instead\n of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: "__dict__" is the attribute dictionary;\n "__class__" is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the "open()" built-in function,\n and also "os.popen()", "os.fdopen()", and the "makefile()" method\n of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n "io.TextIOBase" abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function name;\n "co_argcount" is the number of positional arguments (including\n arguments with default values); "co_nlocals" is the number of\n local variables used by the function (including arguments);\n "co_varnames" is a tuple containing the names of the local\n variables (starting with the argument names); "co_cellvars" is a\n tuple containing the names of local variables that are\n referenced by nested functions; "co_freevars" is a tuple\n containing the names of free variables; "co_code" is a string\n representing the sequence of bytecode instructions; "co_consts"\n is a tuple containing the literals used by the bytecode;\n "co_names" is a tuple containing the names used by the bytecode;\n "co_filename" is the filename from which the code was compiled;\n "co_firstlineno" is the first line number of the function;\n "co_lnotab" is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); "co_stacksize" is the required stack size\n (including local variables); "co_flags" is an integer encoding a\n number of flags for the interpreter.\n\n The following flag bits are defined for "co_flags": bit "0x04"\n is set if the function uses the "*arguments" syntax to accept an\n arbitrary number of positional arguments; bit "0x08" is set if\n the function uses the "**keywords" syntax to accept arbitrary\n keyword arguments; bit "0x20" is set if the function is a\n generator.\n\n Future feature declarations ("from __future__ import division")\n also use bits in "co_flags" to indicate whether a code object\n was compiled with a particular feature enabled: bit "0x2000" is\n set if the function was compiled with future division enabled;\n bits "0x10" and "0x1000" were used in earlier versions of\n Python.\n\n Other bits in "co_flags" are reserved for internal use.\n\n If a code object represents a function, the first item in\n "co_consts" is the documentation string of the function, or\n "None" if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: "f_back" is to the previous stack\n frame (towards the caller), or "None" if this is the bottom\n stack frame; "f_code" is the code object being executed in this\n frame; "f_locals" is the dictionary used to look up local\n variables; "f_globals" is used for global variables;\n "f_builtins" is used for built-in (intrinsic) names; "f_lasti"\n gives the precise instruction (this is an index into the\n bytecode string of the code object).\n\n Special writable attributes: "f_trace", if not "None", is a\n function called at the start of each source code line (this is\n used by the debugger); "f_lineno" is the current line number of\n the frame --- writing to this from within a trace function jumps\n to the given line (only for the bottom-most frame). A debugger\n can implement a Jump command (aka Set Next Statement) by writing\n to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n "RuntimeError" is raised if the frame is currently executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by "sys.exc_info()". When the program contains no\n suitable handler, the stack trace is written (nicely formatted)\n to the standard error stream; if the interpreter is interactive,\n it is also made available to the user as "sys.last_traceback".\n\n Special read-only attributes: "tb_next" is the next level in the\n stack trace (towards the frame where the exception occurred), or\n "None" if there is no next level; "tb_frame" points to the\n execution frame of the current level; "tb_lineno" gives the line\n number where the exception occurred; "tb_lasti" indicates the\n precise instruction. The line number and last instruction in\n the traceback may differ from the line number of its frame\n object if the exception occurred in a "try" statement with no\n matching except clause or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for "__getitem__()"\n methods. They are also created by the built-in "slice()"\n function.\n\n Special read-only attributes: "start" is the lower bound; "stop"\n is the upper bound; "step" is the step value; each is "None" if\n omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n "staticmethod()" constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in "classmethod()" constructor.\n', + 'typesfunctions': u'\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: "func(argument-list)".\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', + 'typesmapping': u'\nMapping Types --- "dict"\n************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin "list", "set", and "tuple" classes, and the "collections" module.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as "1" and "1.0") then they can be used interchangeably to index\nthe same dictionary entry. (Note however, that since computers store\nfloating-point numbers as approximations it is usually unwise to use\nthem as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of "key:\nvalue" pairs within braces, for example: "{\'jack\': 4098, \'sjoerd\':\n4127}" or "{4098: \'jack\', 4127: \'sjoerd\'}", or by the "dict"\nconstructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterable*\n object. Each item in the iterable must itself be an iterable with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to "{"one": 1, "two": 2, "three": 3}":\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a "KeyError" if\n *key* is not in the map.\n\n If a subclass of dict defines a method "__missing__()" and *key*\n is not present, the "d[key]" operation calls that method with\n the key *key* as argument. The "d[key]" operation then returns\n or raises whatever is returned or raised by the\n "__missing__(key)" call. No other operations or methods invoke\n "__missing__()". If "__missing__()" is not defined, "KeyError"\n is raised. "__missing__()" must be a method; it cannot be an\n instance variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n The example above shows part of the implementation of\n "collections.Counter". A different "__missing__" method is used\n by "collections.defaultdict".\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n key not in d\n\n Equivalent to "not key in d".\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iter(d.keys())".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n "fromkeys()" is a class method that returns a new dictionary.\n *value* defaults to "None".\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to "None", so\n that this method never raises a "KeyError".\n\n items()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a "KeyError" is raised.\n\n popitem()\n\n Remove and return an arbitrary "(key, value)" pair from the\n dictionary.\n\n "popitem()" is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling "popitem()" raises a "KeyError".\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to "None".\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return "None".\n\n "update()" accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: "d.update(red=1,\n blue=2)".\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also: "types.MappingProxyType" can be used to create a read-only\n view of a "dict".\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.keys()", "dict.values()" and\n"dict.items()" are *view objects*. They provide a dynamic view on the\ndictionary\'s entries, which means that when the dictionary changes,\nthe view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of "(key, value)") in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of "(value, key)" pairs using\n "zip()": "pairs = zip(d.values(), d.keys())". Another way to\n create the same list is "pairs = [(v, k) for (k, v) in d.items()]".\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a "RuntimeError" or fail to iterate over all entries.\n\nx in dictview\n\n Return "True" if *x* is in the underlying dictionary\'s keys, values\n or items (in the latter case, *x* should be a "(key, value)"\n tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that "(key, value)" pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class "collections.abc.Set" are available (for example, "==",\n"<", or "^").\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', + 'typesmethods': u'\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as "append()" on lists)\nand class instance methods. Built-in methods are described with the\ntypes that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the "self"\nargument to the argument list. Bound methods have two special read-\nonly attributes: "m.__self__" is the object on which the method\noperates, and "m.__func__" is the function implementing the method.\nCalling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to\ncalling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object ("meth.__func__"), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an "AttributeError" being raised. In\norder to set a method attribute, you need to explicitly set it on the\nunderlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', + 'typesmodules': u'\nModules\n*******\n\nThe only special operation on a module is attribute access: "m.name",\nwhere *m* is a module and *name* accesses a name defined in *m*\'s\nsymbol table. Module attributes can be assigned to. (Note that the\n"import" statement is not, strictly speaking, an operation on a module\nobject; "import foo" does not require a module object named *foo* to\nexist, rather it requires an (external) *definition* for a module\nnamed *foo* somewhere.)\n\nA special attribute of every module is "__dict__". This is the\ndictionary containing the module\'s symbol table. Modifying this\ndictionary will actually change the module\'s symbol table, but direct\nassignment to the "__dict__" attribute is not possible (you can write\n"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but you can\'t\nwrite "m.__dict__ = {}"). Modifying "__dict__" directly is not\nrecommended.\n\nModules built into the interpreter are written like this: "". If loaded from a file, they are written as\n"".\n', + 'typesseq': u'\nSequence Types --- "list", "tuple", "range"\n*******************************************\n\nThere are three basic sequence types: lists, tuples, and range\nobjects. Additional sequence types tailored for processing of *binary\ndata* and *text strings* are described in dedicated sections.\n\n\nCommon Sequence Operations\n==========================\n\nThe operations in the following table are supported by most sequence\ntypes, both mutable and immutable. The "collections.abc.Sequence" ABC\nis provided to make it easier to correctly implement these operations\non custom sequence types.\n\nThis table lists the sequence operations sorted in ascending priority.\nIn the table, *s* and *t* are sequences of the same type, *n*, *i*,\n*j* and *k* are integers and *x* is an arbitrary object that meets any\ntype and value restrictions imposed by *s*.\n\nThe "in" and "not in" operations have the same priorities as the\ncomparison operations. The "+" (concatenation) and "*" (repetition)\noperations have the same priority as the corresponding numeric\noperations.\n\n+----------------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+============================+==================================+============+\n| "x in s" | "True" if an item of *s* is | (1) |\n| | equal to *x*, else "False" | |\n+----------------------------+----------------------------------+------------+\n| "x not in s" | "False" if an item of *s* is | (1) |\n| | equal to *x*, else "True" | |\n+----------------------------+----------------------------------+------------+\n| "s + t" | the concatenation of *s* and *t* | (6)(7) |\n+----------------------------+----------------------------------+------------+\n| "s * n" or "n * s" | *n* shallow copies of *s* | (2)(7) |\n| | concatenated | |\n+----------------------------+----------------------------------+------------+\n| "s[i]" | *i*th item of *s*, origin 0 | (3) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+----------------------------+----------------------------------+------------+\n| "len(s)" | length of *s* | |\n+----------------------------+----------------------------------+------------+\n| "min(s)" | smallest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "max(s)" | largest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) |\n| | *x* in *s* (at or after index | |\n| | *i* and before index *j*) | |\n+----------------------------+----------------------------------+------------+\n| "s.count(x)" | total number of occurrences of | |\n| | *x* in *s* | |\n+----------------------------+----------------------------------+------------+\n\nSequences of the same type also support comparisons. In particular,\ntuples and lists are compared lexicographically by comparing\ncorresponding elements. This means that to compare equal, every\nelement must compare equal and the two sequences must be of the same\ntype and have the same length. (For full details see *Comparisons* in\nthe language reference.)\n\nNotes:\n\n1. While the "in" and "not in" operations are used only for simple\n containment testing in the general case, some specialised sequences\n (such as "str", "bytes" and "bytearray") also use them for\n subsequence testing:\n\n >>> "gg" in "eggs"\n True\n\n2. Values of *n* less than "0" are treated as "0" (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that "[[]]" is a one-element list containing\n an empty list, so all three elements of "[[]] * 3" are (pointers\n to) this single empty list. Modifying any of the elements of\n "lists" modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of\n the string: "len(s) + i" or "len(s) + j" is substituted. But note\n that "-0" is still "0".\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that "i <= k < j". If *i* or *j* is\n greater than "len(s)", use "len(s)". If *i* is omitted or "None",\n use "0". If *j* is omitted or "None", use "len(s)". If *i* is\n greater than or equal to *j*, the slice is empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index "x = i + n*k" such that "0 <= n <\n (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k",\n "i+3*k" and so on, stopping when *j* is reached (but never\n including *j*). If *i* or *j* is greater than "len(s)", use\n "len(s)". If *i* or *j* are omitted or "None", they become "end"\n values (which end depends on the sign of *k*). Note, *k* cannot be\n zero. If *k* is "None", it is treated like "1".\n\n6. Concatenating immutable sequences always results in a new\n object. This means that building up a sequence by repeated\n concatenation will have a quadratic runtime cost in the total\n sequence length. To get a linear runtime cost, you must switch to\n one of the alternatives below:\n\n * if concatenating "str" objects, you can build a list and use\n "str.join()" at the end or else write to a "io.StringIO" instance\n and retrieve its value when complete\n\n * if concatenating "bytes" objects, you can similarly use\n "bytes.join()" or "io.BytesIO", or you can do in-place\n concatenation with a "bytearray" object. "bytearray" objects are\n mutable and have an efficient overallocation mechanism\n\n * if concatenating "tuple" objects, extend a "list" instead\n\n * for other types, investigate the relevant class documentation\n\n7. Some sequence types (such as "range") only support item\n sequences that follow specific patterns, and hence don\'t support\n sequence concatenation or repetition.\n\n8. "index" raises "ValueError" when *x* is not found in *s*. When\n supported, the additional arguments to the index method allow\n efficient searching of subsections of the sequence. Passing the\n extra arguments is roughly equivalent to using "s[i:j].index(x)",\n only without copying any data and with the returned index being\n relative to the start of the sequence rather than the start of the\n slice.\n\n\nImmutable Sequence Types\n========================\n\nThe only operation that immutable sequence types generally implement\nthat is not also implemented by mutable sequence types is support for\nthe "hash()" built-in.\n\nThis support allows immutable sequences, such as "tuple" instances, to\nbe used as "dict" keys and stored in "set" and "frozenset" instances.\n\nAttempting to hash an immutable sequence that contains unhashable\nvalues will result in "TypeError".\n\n\nMutable Sequence Types\n======================\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | appends *x* to the end of the | |\n| | sequence (same as | |\n| | "s[len(s):len(s)] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n| | as "del s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n| | (same as "s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(t)" | extends *s* with the contents of | |\n| | *t* (same as "s[len(s):len(s)] = | |\n| | t") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | "s[i:i] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n| | where "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n\n\nLists\n=====\n\nLists are mutable sequences, typically used to store collections of\nhomogeneous items (where the precise degree of similarity will vary by\napplication).\n\nclass class list([iterable])\n\n Lists may be constructed in several ways:\n\n * Using a pair of square brackets to denote the empty list: "[]"\n\n * Using square brackets, separating items with commas: "[a]",\n "[a, b, c]"\n\n * Using a list comprehension: "[x for x in iterable]"\n\n * Using the type constructor: "list()" or "list(iterable)"\n\n The constructor builds a list whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a list, a copy is made and\n returned, similar to "iterable[:]". For example, "list(\'abc\')"\n returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" returns "[1, 2,\n 3]". If no argument is given, the constructor creates a new empty\n list, "[]".\n\n Many other operations also produce lists, including the "sorted()"\n built-in.\n\n Lists implement all of the *common* and *mutable* sequence\n operations. Lists also provide the following additional method:\n\n sort(*, key=None, reverse=None)\n\n This method sorts the list in place, using only "<" comparisons\n between items. Exceptions are not suppressed - if any comparison\n operations fail, the entire sort operation will fail (and the\n list will likely be left in a partially modified state).\n\n "sort()" accepts two arguments that can only be passed by\n keyword (*keyword-only arguments*):\n\n *key* specifies a function of one argument that is used to\n extract a comparison key from each list element (for example,\n "key=str.lower"). The key corresponding to each item in the list\n is calculated once and then used for the entire sorting process.\n The default value of "None" means that list items are sorted\n directly without calculating a separate key value.\n\n The "functools.cmp_to_key()" utility is available to convert a\n 2.x style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n This method modifies the sequence in place for economy of space\n when sorting a large sequence. To remind users that it operates\n by side effect, it does not return the sorted sequence (use\n "sorted()" to explicitly request a new sorted list instance).\n\n The "sort()" method is guaranteed to be stable. A sort is\n stable if it guarantees not to change the relative order of\n elements that compare equal --- this is helpful for sorting in\n multiple passes (for example, sort by department, then by salary\n grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises "ValueError" if it can detect\n that the list has been mutated during a sort.\n\n\nTuples\n======\n\nTuples are immutable sequences, typically used to store collections of\nheterogeneous data (such as the 2-tuples produced by the "enumerate()"\nbuilt-in). Tuples are also used for cases where an immutable sequence\nof homogeneous data is needed (such as allowing storage in a "set" or\n"dict" instance).\n\nclass class tuple([iterable])\n\n Tuples may be constructed in a number of ways:\n\n * Using a pair of parentheses to denote the empty tuple: "()"\n\n * Using a trailing comma for a singleton tuple: "a," or "(a,)"\n\n * Separating items with commas: "a, b, c" or "(a, b, c)"\n\n * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)"\n\n The constructor builds a tuple whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a tuple, it is returned\n unchanged. For example, "tuple(\'abc\')" returns "(\'a\', \'b\', \'c\')"\n and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is\n given, the constructor creates a new empty tuple, "()".\n\n Note that it is actually the comma which makes a tuple, not the\n parentheses. The parentheses are optional, except in the empty\n tuple case, or when they are needed to avoid syntactic ambiguity.\n For example, "f(a, b, c)" is a function call with three arguments,\n while "f((a, b, c))" is a function call with a 3-tuple as the sole\n argument.\n\n Tuples implement all of the *common* sequence operations.\n\nFor heterogeneous collections of data where access by name is clearer\nthan access by index, "collections.namedtuple()" may be a more\nappropriate choice than a simple tuple object.\n\n\nRanges\n======\n\nThe "range" type represents an immutable sequence of numbers and is\ncommonly used for looping a specific number of times in "for" loops.\n\nclass class range(stop)\nclass class range(start, stop[, step])\n\n The arguments to the range constructor must be integers (either\n built-in "int" or any object that implements the "__index__"\n special method). If the *step* argument is omitted, it defaults to\n "1". If the *start* argument is omitted, it defaults to "0". If\n *step* is zero, "ValueError" is raised.\n\n For a positive *step*, the contents of a range "r" are determined\n by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] <\n stop".\n\n For a negative *step*, the contents of the range are still\n determined by the formula "r[i] = start + step*i", but the\n constraints are "i >= 0" and "r[i] > stop".\n\n A range object will be empty if "r[0]" does not meet the value\n constraint. Ranges do support negative indices, but these are\n interpreted as indexing from the end of the sequence determined by\n the positive indices.\n\n Ranges containing absolute values larger than "sys.maxsize" are\n permitted but some features (such as "len()") may raise\n "OverflowError".\n\n Range examples:\n\n >>> list(range(10))\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n >>> list(range(1, 11))\n [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n >>> list(range(0, 30, 5))\n [0, 5, 10, 15, 20, 25]\n >>> list(range(0, 10, 3))\n [0, 3, 6, 9]\n >>> list(range(0, -10, -1))\n [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n >>> list(range(0))\n []\n >>> list(range(1, 0))\n []\n\n Ranges implement all of the *common* sequence operations except\n concatenation and repetition (due to the fact that range objects\n can only represent sequences that follow a strict pattern and\n repetition and concatenation will usually violate that pattern).\n\nThe advantage of the "range" type over a regular "list" or "tuple" is\nthat a "range" object will always take the same (small) amount of\nmemory, no matter the size of the range it represents (as it only\nstores the "start", "stop" and "step" values, calculating individual\nitems and subranges as needed).\n\nRange objects implement the "collections.abc.Sequence" ABC, and\nprovide features such as containment tests, element index lookup,\nslicing and support for negative indices (see *Sequence Types ---\nlist, tuple, range*):\n\n>>> r = range(0, 20, 2)\n>>> r\nrange(0, 20, 2)\n>>> 11 in r\nFalse\n>>> 10 in r\nTrue\n>>> r.index(10)\n5\n>>> r[5]\n10\n>>> r[:5]\nrange(0, 10, 2)\n>>> r[-1]\n18\n\nTesting range objects for equality with "==" and "!=" compares them as\nsequences. That is, two range objects are considered equal if they\nrepresent the same sequence of values. (Note that two range objects\nthat compare equal might have different "start", "stop" and "step"\nattributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3,\n2) == range(0, 4, 2)".)\n\nChanged in version 3.2: Implement the Sequence ABC. Support slicing\nand negative indices. Test "int" objects for membership in constant\ntime instead of iterating through all items.\n\nChanged in version 3.3: Define \'==\' and \'!=\' to compare range objects\nbased on the sequence of values they define (instead of comparing\nbased on object identity).\n\nNew in version 3.3: The "start", "stop" and "step" attributes.\n', + 'typesseq-mutable': u'\nMutable Sequence Types\n**********************\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | appends *x* to the end of the | |\n| | sequence (same as | |\n| | "s[len(s):len(s)] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n| | as "del s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n| | (same as "s[:]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(t)" | extends *s* with the contents of | |\n| | *t* (same as "s[len(s):len(s)] = | |\n| | t") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | "s[i:i] = [x]") | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n| | where "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n', + 'unary': u'\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary "-" (minus) operator yields the negation of its numeric\nargument.\n\nThe unary "+" (plus) operator yields its numeric argument unchanged.\n\nThe unary "~" (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of "x" is defined as\n"-(x+1)". It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n"TypeError" exception is raised.\n', + 'while': u'\nThe "while" statement\n*********************\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n', + 'with': u'\nThe "with" statement\n********************\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', + 'yield': u'\nThe "yield" statement\n*********************\n\n yield_stmt ::= yield_expression\n\nA "yield" statement is semantically equivalent to a *yield\nexpression*. The yield statement can be used to omit the parentheses\nthat would otherwise be required in the equivalent yield expression\nstatement. For example, the yield statements\n\n yield \n yield from \n\nare equivalent to the yield expression statements\n\n (yield )\n (yield from )\n\nYield expressions and statements are only used when defining a\n*generator* function, and are only used in the body of the generator\nfunction. Using yield in a function definition is sufficient to cause\nthat definition to create a generator function instead of a normal\nfunction.\n\nFor full details of "yield" semantics, refer to the *Yield\nexpressions* section.\n'} -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:08:17 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:08:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_a_copyright_notice_tha?= =?utf-8?q?t_still_said_2014=2E?= Message-ID: <20150208220746.69881.10507@psf.io> https://hg.python.org/cpython/rev/5d4b6a57d5fd changeset: 94564:5d4b6a57d5fd tag: v3.5.0a1 user: Larry Hastings date: Sat Feb 07 16:04:29 2015 -0800 summary: Fix a copyright notice that still said 2014. files: Doc/README.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/README.txt b/Doc/README.txt --- a/Doc/README.txt +++ b/Doc/README.txt @@ -128,7 +128,7 @@ as long as you don't change or remove the copyright notice: ---------------------------------------------------------------------- -Copyright (c) 2000-2014 Python Software Foundation. +Copyright (c) 2000-2015 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:08:17 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:08:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Added_tag_v3=2E5=2E0a1_for?= =?utf-8?q?_changeset_5d4b6a57d5fd?= Message-ID: <20150208220746.51396.43802@psf.io> https://hg.python.org/cpython/rev/af285e031bca changeset: 94565:af285e031bca user: Larry Hastings date: Sat Feb 07 16:05:05 2015 -0800 summary: Added tag v3.5.0a1 for changeset 5d4b6a57d5fd files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -142,3 +142,4 @@ c0e311e010fcb5bae8d87ca22051cd0845ea0ca0 v3.4.1 8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 +5d4b6a57d5fd7564bf73f3db0e46fe5eeb00bcd8 v3.5.0a1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:08:18 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:08:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Post-release_updates_for_P?= =?utf-8?q?ython_3=2E5=2E0a1=2E?= Message-ID: <20150208220746.51398.50853@psf.io> https://hg.python.org/cpython/rev/db77970dcabb changeset: 94566:db77970dcabb user: Larry Hastings date: Sun Feb 08 14:07:14 2015 -0800 summary: Post-release updates for Python 3.5.0a1. files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.5.0a1" +#define PY_VERSION "3.5.0a1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.5 alpha 2? +================================= + +Release date: 2015-03-08 + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.5 alpha 1? ================================= -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:08:17 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:08:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogTWVyZ2Uu?= Message-ID: <20150208220746.50305.82226@psf.io> https://hg.python.org/cpython/rev/b5a953ffb2be changeset: 94567:b5a953ffb2be parent: 94566:db77970dcabb parent: 94556:5ea093a41198 user: Larry Hastings date: Sun Feb 08 14:07:35 2015 -0800 summary: Merge. files: Doc/make.bat | 18 ++- Makefile.pre.in | 1 + Tools/msi/buildrelease.bat | 57 ++++++++-- Tools/msi/bundle/bundle.targets | 4 +- Tools/msi/get_wix.py | 2 +- Tools/msi/msi.props | 1 - Tools/msi/testrelease.bat | 100 ++++++++++++++++++++ 7 files changed, 158 insertions(+), 25 deletions(-) diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -8,13 +8,17 @@ if "%SPHINXBUILD%" EQU "" set SPHINXBUILD=sphinx-build if "%PYTHON%" EQU "" set PYTHON=py -if "%HTMLHELP%" EQU "" ( - where hhc 2>nul >"%TEMP%\hhc.loc" - if errorlevel 1 dir "..\externals\hhc.exe" /s/b > "%TEMP%\hhc.loc" - if errorlevel 1 echo Cannot find HHC on PATH or in externals & exit /B 1 - set /P HTMLHELP= < "%TEMP%\hhc.loc" - del "%TEMP%\hhc.loc" -) +if "%1" NEQ "htmlhelp" goto :skiphhcsearch +if exist "%HTMLHELP%" goto :skiphhcsearch + +rem Search for HHC in likely places +set HTMLHELP= +where hhc /q && set HTMLHELP=hhc && goto :skiphhcsearch +where /R ..\externals hhc > "%TEMP%\hhc.loc" 2> nul && set /P HTMLHELP= < "%TEMP%\hhc.loc" & del "%TEMP%\hhc.loc" +if not exist "%HTMLHELP%" where /R "%ProgramFiles(x86)%" hhc > "%TEMP%\hhc.loc" 2> nul && set /P HTMLHELP= < "%TEMP%\hhc.loc" & del "%TEMP%\hhc.loc" +if not exist "%HTMLHELP%" where /R "%ProgramFiles%" hhc > "%TEMP%\hhc.loc" 2> nul && set /P HTMLHELP= < "%TEMP%\hhc.loc" & del "%TEMP%\hhc.loc" +if not exist "%HTMLHELP%" echo Cannot find HHC on PATH or in externals & exit /B 1 +:skiphhcsearch if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/extensions/patchlevel.py`) do set DISTVERSION=%%v diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1143,6 +1143,7 @@ test/audiodata \ test/capath test/data \ test/cjkencodings test/decimaltestdata test/xmltestdata \ + test/eintrdata \ test/imghdrdata \ test/subprocessdata test/sndhdrdata test/support \ test/tracedmodules test/encoded_modules \ diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -22,17 +22,25 @@ set BUILDX86= set BUILDX64= set TARGET=Rebuild +set TESTTARGETDIR= :CheckOpts +if "%1" EQU "-h" goto Help if "%1" EQU "-c" (set CERTNAME=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--certificate" (set CERTNAME=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-o" (set OUTDIR=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--out" (set OUTDIR=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-D" (set SKIPDOC=1) && shift && goto CheckOpts +if "%1" EQU "--skip-doc" (set SKIPDOC=1) && shift && goto CheckOpts if "%1" EQU "-B" (set SKIPBUILD=1) && shift && goto CheckOpts +if "%1" EQU "--skip-build" (set SKIPBUILD=1) && shift && goto CheckOpts if "%1" EQU "--download" (set DOWNLOAD_URL=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--test" (set TESTTARGETDIR=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-b" (set TARGET=Build) && shift && goto CheckOpts -if '%1' EQU '-x86' (set BUILDX86=1) && shift && goto CheckOpts -if '%1' EQU '-x64' (set BUILDX64=1) && shift && goto CheckOpts +if "%1" EQU "--build" (set TARGET=Build) && shift && goto CheckOpts +if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1) @@ -40,21 +48,21 @@ if "%SKIPBUILD%" EQU "1" goto skipdoc if "%SKIPDOC%" EQU "1" goto skipdoc +if not defined PYTHON where py -q || echo Cannot find py on path and PYTHON is not set. && exit /B 1 +if not defined SPHINXBUILD where sphinx-build -q || echo Cannot find sphinx-build on path and SPHINXBUILD is not set. && exit /B 1 call "%D%..\..\doc\make.bat" htmlhelp if errorlevel 1 goto :eof :skipdoc -where hg >nul 2>nul -if errorlevel 1 echo Cannot find hg on PATH & exit /B 1 +where hg /q || echo Cannot find Mercurial on PATH && exit /B 1 -where dlltool 2>nul >"%TEMP%\dlltool.loc" -if errorlevel 1 dir "%D%..\..\externals\dlltool.exe" /s/b > "%TEMP%\dlltool.loc" -if errorlevel 1 echo Cannot find binutils on PATH or in externals & exit /B 1 -set /P DLLTOOL= < "%TEMP%\dlltool.loc" -set PATH=%PATH%;%DLLTOOL:~,-12% -set DLLTOOL= -del "%TEMP%\dlltool.loc" - +where dlltool /q && goto skipdlltoolsearch +set _DLLTOOL_PATH= +where /R "%D%..\..\externals" dlltool > "%TEMP%\dlltool.loc" 2> nul && set /P _DLLTOOL_PATH= < "%TEMP%\dlltool.loc" & del "%TEMP%\dlltool.loc" +if not exist "%_DLLTOOL_PATH%" echo Cannot find binutils on PATH or in external && exit /B 1 +for %%f in (%_DLLTOOL_PATH%) do set PATH=%PATH%;%%~dpf +set _DLLTOOL_PATH= +:skipdlltoolsearch if defined BUILDX86 ( call :build x86 @@ -66,6 +74,10 @@ if errorlevel 1 exit /B ) +if defined TESTTARGETDIR ( + call "%D%testrelease.bat" -t "%TESTTARGETDIR%" +) + exit /B 0 :build @@ -88,14 +100,12 @@ set RELEASE_URI=%RELEASE_URI_X64% ) -echo on if exist "%BUILD%en-us" ( echo Deleting %BUILD%en-us rmdir /q/s "%BUILD%en-us" if errorlevel 1 exit /B ) -echo on if exist "%D%obj\Release_%OBJDIR_PLAT%" ( echo Deleting "%D%obj\Release_%OBJDIR_PLAT%" rmdir /q/s "%D%obj\Release_%OBJDIR_PLAT%" @@ -132,3 +142,22 @@ copy /Y "%BUILD%en-us\*.msi" "%OUTDIR%\%OUTDIR_PLAT%" ) +exit /B 0 + +:Help +echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--skip-build] +echo [--skip-doc] [--download DOWNLOAD URL] [--test TARGETDIR] [-h] +echo. +echo --out (-o) Specify an additional output directory for installers +echo -x86 Build x86 installers +echo -x64 Build x64 installers +echo --build (-b) Incrementally build Python rather than rebuilding +echo --skip-build (-B) Do not build Python (just do the installers) +echo --skip-doc (-D) Do not build documentation +echo --download Specify the full download URL for MSIs (should include {2}) +echo --test Specify the test directory to run the installer tests +echo -h Display this help information +echo. +echo If no architecture is specified, all architectures will be built. +echo If --test is not specified, the installer tests are not run. +echo. \ No newline at end of file diff --git a/Tools/msi/bundle/bundle.targets b/Tools/msi/bundle/bundle.targets --- a/Tools/msi/bundle/bundle.targets +++ b/Tools/msi/bundle/bundle.targets @@ -14,8 +14,8 @@ $(OutputPath)en-us\ $(OutputPath) - $(DownloadUrlBase.TrimEnd(`/`))/$(PythonVersion)/$(ArchName)/{2} - $(DefineConstants);DownloadUrl=$(DownloadUrl) + $(DownloadUrlBase.TrimEnd(`/`))/$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)/$(ArchName)$(ReleaseLevelName)/ + $(DefineConstants);DownloadUrl=$(DownloadUrl){2} $(DefineConstants);DownloadUrl={2} diff --git a/Tools/msi/get_wix.py b/Tools/msi/get_wix.py --- a/Tools/msi/get_wix.py +++ b/Tools/msi/get_wix.py @@ -22,7 +22,7 @@ print("Cannot find project root") sys.exit(1) -WIX_BINARIES_ZIP = 'http://wixtoolset.org/downloads/v3.10.1124.0/wix310-binaries.zip' +WIX_BINARIES_ZIP = 'http://wixtoolset.org/downloads/v3.10.0.1403/wix310-binaries.zip' TARGET_BIN_ZIP = EXTERNALS_DIR / "wix.zip" TARGET_BIN_DIR = EXTERNALS_DIR / "wix" diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props --- a/Tools/msi/msi.props +++ b/Tools/msi/msi.props @@ -69,7 +69,6 @@ MajorVersionNumber=$(MajorVersionNumber); MinorVersionNumber=$(MinorVersionNumber); UpgradeMinimumVersion=$(MajorVersionNumber).$(MinorVersionNumber).0.0; - UpgradeMaximumVersion=$(MajorVersionNumber).$(MinorVersionNumber).150.0; NextMajorVersionNumber=$(MajorVersionNumber).$([msbuild]::Add($(MinorVersionNumber), 1)).0.0; PyDebugExt=$(PyDebugExt); diff --git a/Tools/msi/testrelease.bat b/Tools/msi/testrelease.bat new file mode 100644 --- /dev/null +++ b/Tools/msi/testrelease.bat @@ -0,0 +1,100 @@ + at setlocal + at echo off + +set D=%~dp0 +set PCBUILD=%D%..\..\PCBuild\ + +set TARGETDIR=%TEMP% +set TESTX86= +set TESTX64= +set TESTALLUSER= +set TESTPERUSER= + +:CheckOpts +if "%1" EQU "-h" goto Help +if "%1" EQU "-x86" (set TESTX86=1) && shift && goto CheckOpts +if "%1" EQU "-x64" (set TESTX64=1) && shift && goto CheckOpts +if "%1" EQU "-t" (set TARGETDIR=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "--target" (set TARGETDIR=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "-a" (set TESTALLUSER=1) && shift && goto CheckOpts +if "%1" EQU "--alluser" (set TESTALLUSER=1) && shift && goto CheckOpts +if "%1" EQU "-p" (set TESTPERUSER=1) && shift && goto CheckOpts +if "%1" EQU "--peruser" (set TESTPERUSER=1) && shift && goto CheckOpts + +if not defined TESTX86 if not defined TESTX64 (set TESTX86=1) && (set TESTX64=1) +if not defined TESTALLUSER if not defined TESTPERUSER (set TESTALLUSER=1) && (set TESTPERUSER=1) + + +if defined TESTX86 ( + for %%f in ("%PCBUILD%win32\en-us\*.exe") do ( + if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" "InstallAllUsers=1 CompileAll=1" + if errorlevel 1 exit /B + if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" "InstallAllUsers=0 CompileAll=0" + if errorlevel 1 exit /B + ) +) + +if defined TESTX64 ( + for %%f in ("%PCBUILD%amd64\en-us\*.exe") do ( + if defined TESTALLUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-alluser" "InstallAllUsers=1 CompileAll=1" + if errorlevel 1 exit /B + if defined TESTPERUSER call :test "%%~ff" "%TARGETDIR%\%%~nf-peruser" "InstallAllUsers=0 CompileAll=0" + if errorlevel 1 exit /B + ) +) + +exit /B 0 + +:test + at setlocal + at echo on + + at if not exist "%~1" exit /B 1 + + at set EXITCODE=0 + at echo Installing %1 into %2 +"%~1" /passive /log "%~2\install\log.txt" TargetDir="%~2\Python" Include_debug=1 Include_symbols=1 %~3 + + at if not errorlevel 1 ( + @echo Printing version + "%~2\Python\python.exe" -c "import sys; print(sys.version)" > "%~2\version.txt" 2>&1 +) + at if not errorlevel 1 ( + @echo Installing package + "%~2\Python\python.exe" -m pip install azure > "%~2\pip.txt" 2>&1 + @if not errorlevel 1 ( + "%~2\Python\python.exe" -m pip uninstall -y azure python-dateutil six >> "%~2\pip.txt" 2>&1 + ) +) + at if not errorlevel 1 ( + @echo Testing Tcl/tk + @set TCL_LIBRARY=%~2\Python\tcl\tcl8.6 + "%~2\Python\python.exe" -m test -uall -v test_ttk_guionly test_tk test_idle > "%~2\tcltk.txt" 2>&1 + @set TCL_LIBRARY= +) + + at set EXITCODE=%ERRORLEVEL% + + at for /d %%f in ("%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Python*") do @dir "%%~ff\*.lnk" /s/b > "%~2\startmenu.txt" 2>&1 + at for /d %%f in ("%APPDATA%\Microsoft\Windows\Start Menu\Programs\Python*") do @dir "%%~ff\*.lnk" /s/b >> "%~2\startmenu.txt" 2>&1 + + at echo Result was %EXITCODE% + at echo Removing %1 +"%~1" /passive /uninstall /log "%~2\uninstall\log.txt" + + at echo off +exit /B %EXITCODE% + +:Help +echo testrelease.bat [--target TARGET] [-x86] [-x64] [--alluser] [--peruser] [-h] +echo. +echo --target (-t) Specify the target directory for installs and logs +echo -x86 Run tests for x86 installers +echo -x64 Run tests for x64 installers +echo --alluser (-a) Run tests for all-user installs (requires Administrator) +echo --peruser (-p) Run tests for per-user installs +echo -h Display this help information +echo. +echo If no test architecture is specified, all architectures will be tested. +echo If no install type is selected, all install types will be tested. +echo. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 8 23:08:18 2015 From: python-checkins at python.org (larry.hastings) Date: Sun, 08 Feb 2015 22:08:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Release_bump_for_3=2E5=2E0?= =?utf-8?b?YTEu?= Message-ID: <20150208220745.69883.59189@psf.io> https://hg.python.org/cpython/rev/6560393f9afa changeset: 94563:6560393f9afa user: Larry Hastings date: Sat Feb 07 16:00:55 2015 -0800 summary: Release bump for 3.5.0a1. files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-3.5.spec | 2 +- README | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 5 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 0 +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.5.0a0" +#define PY_VERSION "3.5.0a1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.5.0a0" +__version__ = "3.5.0a1" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.5.0a0" +IDLE_VERSION = "3.5.0a1" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ What's New in Python 3.5 alpha 1? ================================= -Release date: TBA +Release date: 2015-02-08 Core and Builtins ----------------- diff --git a/Misc/RPM/python-3.5.spec b/Misc/RPM/python-3.5.spec --- a/Misc/RPM/python-3.5.spec +++ b/Misc/RPM/python-3.5.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.5.0a0 +%define version 3.5.0a1 %define libvers 3.5 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -175,7 +175,7 @@ --------------------------------- Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013, 2014 Python Software Foundation. All rights reserved. +2012, 2013, 2014, 2015 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 9 08:04:50 2015 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 Feb 2015 07:04:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE3ODk2?= =?utf-8?q?=3A_Update_msi=2Epy_to_new_externals_dir=2E?= Message-ID: <20150209070438.69897.74241@psf.io> https://hg.python.org/cpython/rev/7d22dbf3a0dc changeset: 94568:7d22dbf3a0dc branch: 3.4 parent: 94561:70449fbe5d4c user: Martin v. L?wis date: Mon Feb 09 07:51:32 2015 +0100 summary: Issue #17896: Update msi.py to new externals dir. files: Tools/msi/msi.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -929,9 +929,9 @@ ("Tk", "tk8*", "license.terms"), ("Tix", "tix-*", "license.terms")): out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name) - dirs = glob.glob(srcdir+"/../"+pat) + dirs = glob.glob(srcdir+"/externals/"+pat) if not dirs: - raise ValueError, "Could not find "+srcdir+"/../"+pat + raise ValueError, "Could not find "+srcdir+"/externals/"+pat if len(dirs) > 2 and not snapshot: raise ValueError, "Multiple copies of "+pat dir = dirs[0] @@ -1115,7 +1115,7 @@ lib.start_component("TkDLLs", tcltk) lib.add_file("_tkinter.pyd") dlls.append("_tkinter.pyd") - tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix)) + tcldir = os.path.normpath(srcdir+("/externals/tcltk%s/bin" % tclsuffix)) for f in glob.glob1(tcldir, "*.dll"): lib.add_file(f, src=os.path.join(tcldir, f)) # check whether there are any unknown extensions @@ -1140,7 +1140,7 @@ lib.add_file('libpython%s%s.a' % (major, minor)) if have_tcl: # Add Tcl/Tk - tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')] + tcldirs = [(root, 'externals/tcltk%s/lib' % tclsuffix, 'tcl')] tcltk.set_current() while tcldirs: parent, phys, dir = tcldirs.pop() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 9 08:04:50 2015 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 Feb 2015 07:04:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4?= Message-ID: <20150209070438.69885.75664@psf.io> https://hg.python.org/cpython/rev/bb47dfb12269 changeset: 94569:bb47dfb12269 parent: 94567:b5a953ffb2be parent: 94568:7d22dbf3a0dc user: Martin v. L?wis date: Mon Feb 09 08:03:46 2015 +0100 summary: Merge with 3.4 files: .hgtags | 291 ++++++++++++++++++++++--------------------- 1 files changed, 146 insertions(+), 145 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1,145 +1,146 @@ -64cc5439e10a6fdf984effaf0141e94fa4cc1004 v0.9.8 -78a7ed6953025e7ecdde9585099b01a6ae40b76a v0.9.9 -b15b8cc9b8d10e0352a0b8b7e8d51fa309db6df3 v1.0.1 -0326b5d61445ee3a8d3de28119f9652cb72d2e3f v1.0.2 -832615ec07646e310c85316b8ba6bc9b17ad3547 v1.1 -9895475d18c7b5f32adaf78f71886ae041e4d10c v1.1.1 -16eb4c51ee97169046340998e850a63c65225b0a v1.2b1 -b45c688756d04fb84d4a0d518fc3d7e3cb25fa8d v1.2b2 -9e82daf7605bad7976a9abc997cb5e0abe434078 v1.2b3 -065e31cf5862e27521cf5725b003aed211f091b2 v1.2b4 -e72257e655454d569468da8b1189e0ec336f3536 v1.2 -e63d83f8275853aaaa3d1972cb86564505e65583 v1.3b1 -7d743c865a9aa6bde8b603e32e0542031bba3c33 v1.3 -4fc85c82cc222554ae6b9c0b87776ed5f2b70c6e v1.4b1 -129f1299d4e97e884bbbbdd00baf101d178973e6 v1.4b2 -44a82ac654a4175569deed8e8a94b0cc8edee08d v1.4b3 -db49494c93dc73de06d5721c74eab533a947a92c v1.4 -062aed8a4ce2c91c81b80e29f02faff1cf5a761b v1.5a1 -c9498ac988372575cf7028b86395b900c9b0a840 v1.5a2 -dc5c968ec992aab3d40a7189df0c443d1c7a1a68 v1.5a3 -746654a0af680c7d9b814b210a026eb91bec9533 v1.5a4 -8ff58b5730f06be08fbbdc2bf592226f7a736201 v1.5b1 -eb78658d819fb0af09a8e6f9bedcb670805ed5f6 v1.5b2 -84461011a1a0ab402e352f06748f29fb5b5559e5 v1.5 -44aba4d26b01fbae0403efe654f9fd0347606732 v1.5.1 -fed63ccbe6dc3ac663bfe97a2f7006b1b28568f9 v1.5.2a1 -21d71f2e27248a0f4e393d0fc321ecf9b89321d2 v1.5.2a2 -f08c7a2a56f80741f5f192fd0ebe0b0967a203cf v1.5.2b1 -8fe7ec4b4fc1518fcac89e6bf674fbbce16150a9 v1.5.2b2 -39fb0dcc83dc375c1565ba65dbce0ed59b1359c9 v1.5.2c1 -61c91c7f101bab3149adfcd5646ae40e048de712 v1.5.2 -605eb9326ffe1fd1e43f40e2338d6652ab449fdf v1.6a1 -011bee8fd9f7f4da457ec71596484fb0882c0614 v1.6a2 -35c4fc1414a59888614b9be784a25f233ba67984 v2.0b1 -55bba197d4870cdae62aeca00e20240a756b84f8 v2.0b2 -e276329cce036a5f9e9d3451256dca5984e543dc v2.0c1 -2fa4e35083e02342ca014bf5bfba46aecb816c31 v2.0 -b60831eeab5a06dd3c5e8297a99e39297aa8794b v2.1a1 -b382f1f07ec6b2c95551658b30c6139eeb32077a v2.1a2 -d0c830db5e68edd4aaa3401216e610c9ff145826 v2.1b1 -b59a536ae1ef3774fd85c17f623e8926b7b6c095 v2.1b2 -d611276e9ad53b5d32d1e8065e1d811c32f7d96f v2.1c1 -ff065e674af6c9ab895bd9eff7d9e9039a376c7d v2.1c2 -020e95d8180d7943fe54701e1db0a7d7d87e2b1e v2.1 -08796a137f1ada2462f7a3177306df5f67a767e1 v2.2a3 -d054c29647f90bccb8345bd779bca1eecf2dd7f2 v2.3c1 -fce5c9e9abc722394cb2e909b7e2a39080d4448e v2.3c2 -92ca658fd420095b6284c9ce6e9082a80285ec9c v2.4a1 -055fc6955f3c6522bfeb7ed4c671c97d5baaaac2 v2.4a2 -186b72550e53533ef6175f6411f932c1298193d7 v2.4a3 -53cff04283855adf88ed0c0fd3698827ca843637 v2.4b1 -7e387a9dcc79954a77695adef8b593da35be1214 v2.4b2 -ff80d8bbef6e13426c8a85d7f9d837b8f8f89834 v2.4c1 -f31e18d313c7a4fc66914b2d27e130a0f72c0b69 v2.4 -cd3f783cd08a16781e236c0b9cb5717d1d995fa9 v3.0a1 -65e82140e281bf26f2e22eda05a7f9956c420f8b v3.0a2 -df15827f34881b9af0936350813ced5c123c8230 v3.0a3 -15f773f7300e372c56a21d59fe49ca26955a6477 v3.0a4 -e35935475153377d6727d64e6c52f72c3b84015b v3.0a5 -a335c4d643b1cfe14197a9ef195c9b2804f608fc v3.0b1 -16ec4bb14a68ea428acf09ebf0c92981da2646f3 v3.0b2 -509e30a7968e01be329ec121540b3e755fc4e566 v3.0b3 -507ede9c7f7f475dfafbd4a52c22d767d10a2bc0 v3.0rc1 -8fae465a39627b590385462e6095eb63af45240a v3.0rc2 -e83a60c69d53f5551a306e77a6d38e9b11485496 v3.0rc3 -bc1ce368986e45b1faf96f93995df46bcd75e7b8 v3.1a1 -ee430e5075db2adf8124e6b94916a89ca41d3171 v3.1a2 -b63020797f9678adaf4d2c3e26574a9eef2ef028 v3.1b1 -4353fd0843cb31b356adc50f93d220e2e7255ef2 v3.1rc1 -0b87e438e1b53e3f812cad963a7fdb65d198ba2f v3.1rc2 -a69a031ac1402dede8b1ef80096436bca6d371f3 v3.1 -35efb1054ec6ceca72017a587263cb6a9257340b v3.1.1rc1 -8b9c0f573ab29c41c6c5fdcca82a1fe0ff5355af v3.1.1 -149b8b87514d10416b598884db5f74651f625b38 v3.1.2rc1 -960efa327c5d9c18df995437b0ac550cb89c9f85 v3.1.2 -d18e9d71f369d8211f6ac87252c6d3211f9bd09f v3.1.3rc1 -a4f75773c0060cee38b0bb651a7aba6f56b0e996 v3.1.3 -32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1 -c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4 -ee26aca3219cf4bb0b93352e83edcc9cb28c7802 v3.1.5rc1 -75db2bc69fc9a3e4801e94e3e19801cb096208d8 v3.1.5rc2 -7395330e495ec3316862ca1f6ce0aaf7bdf6785b v3.1.5 -b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1 -56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2 -da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3 -d92a5b850f5e56808bedc01723906ed64c5e6e2e v3.2a4 -b635cea94195780c8716e236479af319bcc26253 v3.2b1 -e3af5f3a7904c0d5343ec9633ea66e7acfd23a66 v3.2b2 -865d5b24bf28ca41b536befc326407c03e74a4d5 v3.2rc1 -acf3e24dd0d0dfd1e20c907d696d3da965a8f56f v3.2rc2 -18c1f52896501c7ee13b038454a39acb45a87979 v3.2rc3 -a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 -8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 -cfa9364997c7f2e67b9cbb45c3a5fa3bba4e4999 v3.2.1rc1 -5df549718fb4841ff521fe051f6b54f290fad5d8 v3.2.1rc2 -ac1f7e5c05104d557d5acd922e95625ba5d1fe10 v3.2.1 -c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 -137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 -7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 -428f05cb7277e1d42bb9dd8d1af6b6270ebc6112 v3.2.3rc2 -3d0686d90f55a78f96d9403da2c52dc2411419d0 v3.2.3 -b2cb7bc1edb8493c0a78f9331eae3e8fba6a881d v3.2.4rc1 -1e10bdeabe3de02f038a63c001911561ac1d13a7 v3.2.4 -cef745775b6583446572cffad704100983db2bea v3.2.5 -51382a5598ec96119cb84594572901c9c964dc3c v3.2.6rc1 -0bd5f4f14de965ca8e44c6e3965fee106176cfc4 v3.2.6 -f1a9a6505731714f0e157453ff850e3b71615c45 v3.3.0a1 -2f69db52d6de306cdaef0a0cc00cc823fb350b01 v3.3.0a2 -0b53b70a40a00013505eb35e3660057b62be77be v3.3.0a3 -7c51388a3aa7ce76a8541bbbdfc05d2d259a162c v3.3.0a4 -e15c554cd43eb23bc0a528a4e8741da9bbec9607 v3.3.0b1 -4972a8f1b2aa3d7cdd64dc96aa7fa112fe1ea343 v3.3.0b2 -8bb5c7bc46ba43804480f3e328e1fa956672c885 v3.3.0rc1 -88a0792e8ba3e4916b24c7e7a522c277d326d66e v3.3.0rc2 -c191d21cefafb3832c45570e84854e309aa62eaa v3.3.0rc3 -bd8afb90ebf28ba4edc901d4a235f75e7bbc79fd v3.3.0 -92c2cfb924055ce68c4f78f836dcfe688437ceb8 v3.3.1rc1 -d9893d13c6289aa03d33559ec67f97dcbf5c9e3c v3.3.1 -d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2 -fd53c500f8b80f54f3ecedec9da2e8c7e52a6888 v3.3.3rc1 -d32442c0e60dfbd71234e807d3d1dedd227495a9 v3.3.3rc2 -c3896275c0f61b2510a6c7e6c458a750359a91b8 v3.3.3 -fa92f5f940c6c0d839d7f0611e4b717606504a3c v3.3.4rc1 -7ff62415e4263c432c8acf6e424224209211eadb v3.3.4 -9ec811df548ed154a9bf9815383a916d6df31b98 v3.3.5rc1 -ca5635efe090f78806188ac2758f9948596aa8b2 v3.3.5rc2 -62cf4e77f78564714e7ea3d4bf1479ca1fbd0758 v3.3.5 -51317c9786f54267975abf2e9c502e6aaaa4a249 v3.3.6rc1 -971fec30da1fc5bf2b9fb28e09812a5127014211 v3.3.6 -46535f65e7f3bcdcf176f36d34bc1fed719ffd2b v3.4.0a1 -9265a2168e2cb2a84785d8717792acc661e6b692 v3.4.0a2 -dd9cdf90a5073510877e9dd5112f8e6cf20d5e89 v3.4.0a3 -e245b0d7209bb6d0e19316e1e2af1aa9c2139104 v3.4.0a4 -3405dc9a6afaa0a06dd1f6f182ec5c998dce6f5f v3.4.0b1 -ba32913eb13ec545a46dd0ce18035b6c416f0d78 v3.4.0b2 -a97ce3ecc96af79bd2e1ac66ce48d9138e0ca749 v3.4.0b3 -5e088cea8660677969113741c1313d570d977e02 v3.4.0rc1 -a300712ed38c9a242b736c44e806caea25a6dc05 v3.4.0rc2 -8a81cdab3e9d521daaef989fade94b16455fc3b8 v3.4.0rc3 -04f714765c13824c3bc2835d7b008908862e083a v3.4.0 -c67a19e11a7191baf30f313bf55e2e0b6c6f574e v3.4.1rc1 -c0e311e010fcb5bae8d87ca22051cd0845ea0ca0 v3.4.1 -8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 -ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 -5d4b6a57d5fd7564bf73f3db0e46fe5eeb00bcd8 v3.5.0a1 +64cc5439e10a6fdf984effaf0141e94fa4cc1004 v0.9.8 +78a7ed6953025e7ecdde9585099b01a6ae40b76a v0.9.9 +b15b8cc9b8d10e0352a0b8b7e8d51fa309db6df3 v1.0.1 +0326b5d61445ee3a8d3de28119f9652cb72d2e3f v1.0.2 +832615ec07646e310c85316b8ba6bc9b17ad3547 v1.1 +9895475d18c7b5f32adaf78f71886ae041e4d10c v1.1.1 +16eb4c51ee97169046340998e850a63c65225b0a v1.2b1 +b45c688756d04fb84d4a0d518fc3d7e3cb25fa8d v1.2b2 +9e82daf7605bad7976a9abc997cb5e0abe434078 v1.2b3 +065e31cf5862e27521cf5725b003aed211f091b2 v1.2b4 +e72257e655454d569468da8b1189e0ec336f3536 v1.2 +e63d83f8275853aaaa3d1972cb86564505e65583 v1.3b1 +7d743c865a9aa6bde8b603e32e0542031bba3c33 v1.3 +4fc85c82cc222554ae6b9c0b87776ed5f2b70c6e v1.4b1 +129f1299d4e97e884bbbbdd00baf101d178973e6 v1.4b2 +44a82ac654a4175569deed8e8a94b0cc8edee08d v1.4b3 +db49494c93dc73de06d5721c74eab533a947a92c v1.4 +062aed8a4ce2c91c81b80e29f02faff1cf5a761b v1.5a1 +c9498ac988372575cf7028b86395b900c9b0a840 v1.5a2 +dc5c968ec992aab3d40a7189df0c443d1c7a1a68 v1.5a3 +746654a0af680c7d9b814b210a026eb91bec9533 v1.5a4 +8ff58b5730f06be08fbbdc2bf592226f7a736201 v1.5b1 +eb78658d819fb0af09a8e6f9bedcb670805ed5f6 v1.5b2 +84461011a1a0ab402e352f06748f29fb5b5559e5 v1.5 +44aba4d26b01fbae0403efe654f9fd0347606732 v1.5.1 +fed63ccbe6dc3ac663bfe97a2f7006b1b28568f9 v1.5.2a1 +21d71f2e27248a0f4e393d0fc321ecf9b89321d2 v1.5.2a2 +f08c7a2a56f80741f5f192fd0ebe0b0967a203cf v1.5.2b1 +8fe7ec4b4fc1518fcac89e6bf674fbbce16150a9 v1.5.2b2 +39fb0dcc83dc375c1565ba65dbce0ed59b1359c9 v1.5.2c1 +61c91c7f101bab3149adfcd5646ae40e048de712 v1.5.2 +605eb9326ffe1fd1e43f40e2338d6652ab449fdf v1.6a1 +011bee8fd9f7f4da457ec71596484fb0882c0614 v1.6a2 +35c4fc1414a59888614b9be784a25f233ba67984 v2.0b1 +55bba197d4870cdae62aeca00e20240a756b84f8 v2.0b2 +e276329cce036a5f9e9d3451256dca5984e543dc v2.0c1 +2fa4e35083e02342ca014bf5bfba46aecb816c31 v2.0 +b60831eeab5a06dd3c5e8297a99e39297aa8794b v2.1a1 +b382f1f07ec6b2c95551658b30c6139eeb32077a v2.1a2 +d0c830db5e68edd4aaa3401216e610c9ff145826 v2.1b1 +b59a536ae1ef3774fd85c17f623e8926b7b6c095 v2.1b2 +d611276e9ad53b5d32d1e8065e1d811c32f7d96f v2.1c1 +ff065e674af6c9ab895bd9eff7d9e9039a376c7d v2.1c2 +020e95d8180d7943fe54701e1db0a7d7d87e2b1e v2.1 +08796a137f1ada2462f7a3177306df5f67a767e1 v2.2a3 +d054c29647f90bccb8345bd779bca1eecf2dd7f2 v2.3c1 +fce5c9e9abc722394cb2e909b7e2a39080d4448e v2.3c2 +92ca658fd420095b6284c9ce6e9082a80285ec9c v2.4a1 +055fc6955f3c6522bfeb7ed4c671c97d5baaaac2 v2.4a2 +186b72550e53533ef6175f6411f932c1298193d7 v2.4a3 +53cff04283855adf88ed0c0fd3698827ca843637 v2.4b1 +7e387a9dcc79954a77695adef8b593da35be1214 v2.4b2 +ff80d8bbef6e13426c8a85d7f9d837b8f8f89834 v2.4c1 +f31e18d313c7a4fc66914b2d27e130a0f72c0b69 v2.4 +cd3f783cd08a16781e236c0b9cb5717d1d995fa9 v3.0a1 +65e82140e281bf26f2e22eda05a7f9956c420f8b v3.0a2 +df15827f34881b9af0936350813ced5c123c8230 v3.0a3 +15f773f7300e372c56a21d59fe49ca26955a6477 v3.0a4 +e35935475153377d6727d64e6c52f72c3b84015b v3.0a5 +a335c4d643b1cfe14197a9ef195c9b2804f608fc v3.0b1 +16ec4bb14a68ea428acf09ebf0c92981da2646f3 v3.0b2 +509e30a7968e01be329ec121540b3e755fc4e566 v3.0b3 +507ede9c7f7f475dfafbd4a52c22d767d10a2bc0 v3.0rc1 +8fae465a39627b590385462e6095eb63af45240a v3.0rc2 +e83a60c69d53f5551a306e77a6d38e9b11485496 v3.0rc3 +bc1ce368986e45b1faf96f93995df46bcd75e7b8 v3.1a1 +ee430e5075db2adf8124e6b94916a89ca41d3171 v3.1a2 +b63020797f9678adaf4d2c3e26574a9eef2ef028 v3.1b1 +4353fd0843cb31b356adc50f93d220e2e7255ef2 v3.1rc1 +0b87e438e1b53e3f812cad963a7fdb65d198ba2f v3.1rc2 +a69a031ac1402dede8b1ef80096436bca6d371f3 v3.1 +35efb1054ec6ceca72017a587263cb6a9257340b v3.1.1rc1 +8b9c0f573ab29c41c6c5fdcca82a1fe0ff5355af v3.1.1 +149b8b87514d10416b598884db5f74651f625b38 v3.1.2rc1 +960efa327c5d9c18df995437b0ac550cb89c9f85 v3.1.2 +d18e9d71f369d8211f6ac87252c6d3211f9bd09f v3.1.3rc1 +a4f75773c0060cee38b0bb651a7aba6f56b0e996 v3.1.3 +32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1 +c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4 +ee26aca3219cf4bb0b93352e83edcc9cb28c7802 v3.1.5rc1 +75db2bc69fc9a3e4801e94e3e19801cb096208d8 v3.1.5rc2 +7395330e495ec3316862ca1f6ce0aaf7bdf6785b v3.1.5 +b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1 +56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2 +da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3 +d92a5b850f5e56808bedc01723906ed64c5e6e2e v3.2a4 +b635cea94195780c8716e236479af319bcc26253 v3.2b1 +e3af5f3a7904c0d5343ec9633ea66e7acfd23a66 v3.2b2 +865d5b24bf28ca41b536befc326407c03e74a4d5 v3.2rc1 +acf3e24dd0d0dfd1e20c907d696d3da965a8f56f v3.2rc2 +18c1f52896501c7ee13b038454a39acb45a87979 v3.2rc3 +a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 +8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 +cfa9364997c7f2e67b9cbb45c3a5fa3bba4e4999 v3.2.1rc1 +5df549718fb4841ff521fe051f6b54f290fad5d8 v3.2.1rc2 +ac1f7e5c05104d557d5acd922e95625ba5d1fe10 v3.2.1 +c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 +137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 +7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 +428f05cb7277e1d42bb9dd8d1af6b6270ebc6112 v3.2.3rc2 +3d0686d90f55a78f96d9403da2c52dc2411419d0 v3.2.3 +b2cb7bc1edb8493c0a78f9331eae3e8fba6a881d v3.2.4rc1 +1e10bdeabe3de02f038a63c001911561ac1d13a7 v3.2.4 +cef745775b6583446572cffad704100983db2bea v3.2.5 +51382a5598ec96119cb84594572901c9c964dc3c v3.2.6rc1 +0bd5f4f14de965ca8e44c6e3965fee106176cfc4 v3.2.6 +f1a9a6505731714f0e157453ff850e3b71615c45 v3.3.0a1 +2f69db52d6de306cdaef0a0cc00cc823fb350b01 v3.3.0a2 +0b53b70a40a00013505eb35e3660057b62be77be v3.3.0a3 +7c51388a3aa7ce76a8541bbbdfc05d2d259a162c v3.3.0a4 +e15c554cd43eb23bc0a528a4e8741da9bbec9607 v3.3.0b1 +4972a8f1b2aa3d7cdd64dc96aa7fa112fe1ea343 v3.3.0b2 +8bb5c7bc46ba43804480f3e328e1fa956672c885 v3.3.0rc1 +88a0792e8ba3e4916b24c7e7a522c277d326d66e v3.3.0rc2 +c191d21cefafb3832c45570e84854e309aa62eaa v3.3.0rc3 +bd8afb90ebf28ba4edc901d4a235f75e7bbc79fd v3.3.0 +92c2cfb924055ce68c4f78f836dcfe688437ceb8 v3.3.1rc1 +d9893d13c6289aa03d33559ec67f97dcbf5c9e3c v3.3.1 +d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2 +fd53c500f8b80f54f3ecedec9da2e8c7e52a6888 v3.3.3rc1 +d32442c0e60dfbd71234e807d3d1dedd227495a9 v3.3.3rc2 +c3896275c0f61b2510a6c7e6c458a750359a91b8 v3.3.3 +fa92f5f940c6c0d839d7f0611e4b717606504a3c v3.3.4rc1 +7ff62415e4263c432c8acf6e424224209211eadb v3.3.4 +9ec811df548ed154a9bf9815383a916d6df31b98 v3.3.5rc1 +ca5635efe090f78806188ac2758f9948596aa8b2 v3.3.5rc2 +62cf4e77f78564714e7ea3d4bf1479ca1fbd0758 v3.3.5 +51317c9786f54267975abf2e9c502e6aaaa4a249 v3.3.6rc1 +971fec30da1fc5bf2b9fb28e09812a5127014211 v3.3.6 +46535f65e7f3bcdcf176f36d34bc1fed719ffd2b v3.4.0a1 +9265a2168e2cb2a84785d8717792acc661e6b692 v3.4.0a2 +dd9cdf90a5073510877e9dd5112f8e6cf20d5e89 v3.4.0a3 +e245b0d7209bb6d0e19316e1e2af1aa9c2139104 v3.4.0a4 +3405dc9a6afaa0a06dd1f6f182ec5c998dce6f5f v3.4.0b1 +ba32913eb13ec545a46dd0ce18035b6c416f0d78 v3.4.0b2 +a97ce3ecc96af79bd2e1ac66ce48d9138e0ca749 v3.4.0b3 +5e088cea8660677969113741c1313d570d977e02 v3.4.0rc1 +a300712ed38c9a242b736c44e806caea25a6dc05 v3.4.0rc2 +8a81cdab3e9d521daaef989fade94b16455fc3b8 v3.4.0rc3 +04f714765c13824c3bc2835d7b008908862e083a v3.4.0 +c67a19e11a7191baf30f313bf55e2e0b6c6f574e v3.4.1rc1 +c0e311e010fcb5bae8d87ca22051cd0845ea0ca0 v3.4.1 +8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 +ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 +69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 +5d4b6a57d5fd7564bf73f3db0e46fe5eeb00bcd8 v3.5.0a1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 9 08:11:22 2015 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 Feb 2015 07:11:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4?= Message-ID: <20150209071121.108391.92342@psf.io> https://hg.python.org/cpython/rev/86b59ac81111 changeset: 94571:86b59ac81111 parent: 94569:bb47dfb12269 parent: 94570:84a05605caeb user: Martin v. L?wis date: Mon Feb 09 08:10:32 2015 +0100 summary: Merge with 3.4 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 9 08:11:22 2015 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 09 Feb 2015 07:11:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Amend_b8ebf381?= =?utf-8?q?390f=3A_find_patchlevel=2Epy_in_extensions=2E?= Message-ID: <20150209071121.52854.82799@psf.io> https://hg.python.org/cpython/rev/84a05605caeb changeset: 94570:84a05605caeb branch: 3.4 parent: 94568:7d22dbf3a0dc user: Martin v. L?wis date: Mon Feb 09 08:07:12 2015 +0100 summary: Amend b8ebf381390f: find patchlevel.py in extensions. files: Doc/make.bat | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -12,7 +12,7 @@ if NOT DEFINED ProgramFiles(x86) set _PRGMFLS=%ProgramFiles% if "%HTMLHELP%" EQU "" set HTMLHELP=%_PRGMFLS%\HTML Help Workshop\hhc.exe -if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/patchlevel.py`) do set DISTVERSION=%%v +if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/extensions/patchlevel.py`) do set DISTVERSION=%%v if "%BUILDDIR%" EQU "" set BUILDDIR=build -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Feb 9 09:53:53 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 09 Feb 2015 09:53:53 +0100 Subject: [Python-checkins] Daily reference leaks (b5a953ffb2be): sum=3 Message-ID: results for b5a953ffb2be on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog45Etal', '-x'] From python-checkins at python.org Mon Feb 9 10:04:03 2015 From: python-checkins at python.org (nick.coghlan) Date: Mon, 09 Feb 2015 09:04:03 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_Kallithea_PEPs_with_ch?= =?utf-8?q?ange_to_my_availability?= Message-ID: <20150209090351.51390.22507@psf.io> https://hg.python.org/peps/rev/12d44a2d7c59 changeset: 5693:12d44a2d7c59 user: Nick Coghlan date: Mon Feb 09 19:03:43 2015 +1000 summary: Update Kallithea PEPs with change to my availability files: pep-0462.txt | 61 ++++++++++++--------------------------- pep-0474.txt | 20 +++++++++++++ 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/pep-0462.txt b/pep-0462.txt --- a/pep-0462.txt +++ b/pep-0462.txt @@ -337,7 +337,7 @@ few years), the merge queue would allow that developer to focus more of their time on reviewing patches and helping the other contributors at the sprint, since accepting a patch for inclusion would now be a single click -in the Rietveld UI, rather than the relatively time consuming process that +in the Kallithea UI, rather than the relatively time consuming process that it is currently. Even when multiple core developers are present, it is better to enable them to spend their time and effort on interacting with the other sprint participants than it is on things that are sufficiently @@ -381,13 +381,6 @@ Contributor Licensing Agreement, which may require further development to link contributor accounts between the Kallithea instance and Roundup. -We would likely also want to improve the existing patch handling, -in particular looking at how the Roundup/Reitveld integration handles cases -where it can't figure out a suitable base version to use when generating -the review (if Rietveld gains the ability to nominate a particular target -repository and branch for a patch, then this may be relatively easy to -resolve). - Some of the existing Zuul triggers work by monitoring for particular comments (in particular, recheck/reverify comments to ask Zuul to try merging a change again if it was previously rejected due to an unrelated intermittent @@ -636,33 +629,21 @@ time as volunteers worked their way through the many technical and social challenges involved. -Accordingly, one possible outcome of this proposal may be a recommendation -to the PSF to investigate how to sustain direct investment in ongoing paid -development on CPython workflow tools, similar to the ongoing funded -development that supports the continuous integration infrastructure for -OpenStack. Some possible approaches include: +Fortunately, as several aspects of this proposal and PEP 474 align with +various workflow improvements under consideration for Red Hat's +`Beaker `__ open source hardware integration +testing system and other work-related projects, I have arranged to be able +to devote ~1 day a week to working on CPython infrastructure projects. -* the PSF funding part-time or contract based development on CPython workflow - tools, either on an ad hoc basic through the existing grants program, or - on a more permanent basis, collaborating with the CPython core development - team to determine the scope of the desired improvements. -* discussing a possible partnership with the OpenStack Foundation to - collaborate on shared tool development that ultimately benefits both - organisations (for example, the OpenStack infrastructure team aren't - especially happy with the maintainability challenges posed by Gerrit, so - improvements to Rietveld to make it a viable candidate for replacing - Gerrit may be something they would be interested in). -* PSF (and OpenStack) sponsor members allocating part-time or full-time - staff to work on improving the CPython workflow tools, similar to the way - such staff are allocated to improving OpenStack workflow tools. - -Note that this model of directing paid development efforts at improving the -tools that support the contributions of volunteers is also one of the -known ways to incorporate funded development into a primarily volunteer -driven project without creating resentment between unpaid and paid -contributors: it's harder to resent people that are being paid specifically -to make the tools, workflow and general experience more pleasant for the -unpaid contributors. +Together with Rackspace's existing contributions to maintaining the +pypi.python.org infrastructure, I personally believe this arrangement is +indicative of a more general recognition amongst CPython redistributors and +major users of the merit in helping to sustain upstream infrastructure +through direct contributions of developer time, rather than expecting +volunteer contributors to maintain that infrastructure entirely in their +spare time or funding it indirectly through the PSF (with the additional +management overhead that would entail). I consider this a positive trend, and +one that I will continue to encourage as best I can. Open Questions @@ -673,18 +654,14 @@ Are the Kallithea and Zuul development communities open to the kind of collaboration that would be needed to make this effort a success? -Assuming we do want to do it (or something like it), how is the work going -to get done? Do we try to get it done solely as a volunteer effort? Do we -put together a grant proposal for the PSF board to consider (assuming we can -find people willing and available to do the work)? - -Do we approach the OpenStack Foundation for assistance, since +While I've arranged to spend some of my own work time on this, do we want to +approach the OpenStack Foundation for additional assistance, since we're a key dependency of OpenStack itself, Zuul is a creation of the OpenStack infrastructure team, and the available development resources for OpenStack currently dwarf those for CPython? -Do those of us working for Python redistributors and major users (including -me), attempt to make the business case to our superiors for investing +Are other interested folks working for Python redistributors and major users +also in a position to make a business case to their superiors for investing developer time in supporting this effort? diff --git a/pep-0474.txt b/pep-0474.txt --- a/pep-0474.txt +++ b/pep-0474.txt @@ -203,6 +203,26 @@ python.org web site. +Funding of development +---------------------- + +As several aspects of this proposal and PEP 462 align with various workflow +improvements under consideration for Red Hat's +`Beaker `__ open source hardware integration +testing system and other work-related projects, I have arranged to be able +to devote ~1 day a week to working on CPython infrastructure projects. + +Together with Rackspace's existing contributions to maintaining the +pypi.python.org infrastructure, I personally believe this arrangement is +indicative of a more general recognition amongst CPython redistributors and +major users of the merit in helping to sustain upstream infrastructure +through direct contributions of developer time, rather than expecting +volunteer contributors to maintain that infrastructure entirely in their +spare time or funding it indirectly through the PSF (with the additional +management overhead that would entail). I consider this a positive trend, and +one that I will continue to encourage as best I can. + + Technical Concerns and Challenges ================================= -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Feb 9 13:48:37 2015 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 09 Feb 2015 12:48:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Mirco-optimizations_to_red?= =?utf-8?q?uce_register_spills_and_reloads_observed_on_CLANG_and?= Message-ID: <20150209124834.50335.39056@psf.io> https://hg.python.org/cpython/rev/dc820b44ce21 changeset: 94572:dc820b44ce21 user: Raymond Hettinger date: Mon Feb 09 06:48:29 2015 -0600 summary: Mirco-optimizations to reduce register spills and reloads observed on CLANG and GCC. files: Objects/setobject.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -84,8 +84,9 @@ return set_lookkey(so, key, hash); if (cmp > 0) /* likely */ return entry; + mask = so->mask; /* help avoid a register spill */ } - if (entry->key == dummy && freeslot == NULL) + if (entry->hash == -1 && freeslot == NULL) freeslot = entry; if (i + LINEAR_PROBES <= mask) { @@ -111,8 +112,9 @@ return set_lookkey(so, key, hash); if (cmp > 0) return entry; + mask = so->mask; } - if (entry->key == dummy && freeslot == NULL) + if (entry->hash == -1 && freeslot == NULL) freeslot = entry; } } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 9 20:49:10 2015 From: python-checkins at python.org (vinay.sajip) Date: Mon, 09 Feb 2015 19:49:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Added_respect=5Fhandler=5F?= =?utf-8?q?level_to_QueueListener=2E?= Message-ID: <20150209194910.50311.67784@psf.io> https://hg.python.org/cpython/rev/e548ab4ce71d changeset: 94573:e548ab4ce71d user: Vinay Sajip date: Mon Feb 09 19:49:00 2015 +0000 summary: Added respect_handler_level to QueueListener. files: Doc/howto/logging-cookbook.rst | 9 +++++++++ Doc/library/logging.handlers.rst | 11 +++++++++-- Lib/logging/handlers.py | 14 ++++++++++---- Lib/test/test_logging.py | 19 +++++++++++++++++++ Misc/NEWS | 3 +++ 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -325,6 +325,15 @@ MainThread: Look out! +.. versionchanged:: 3.5 + Prior to Python 3.5, the :class:`QueueListener` always passed every message + received from the queue to every handler it was initialized with. (This was + because it was assumed that level filtering was all done on the other side, + where the queue is filled.) From 3.5 onwards, this behaviour can be changed + by passing a keyword argument ``respect_handler_level=True`` to the + listener's constructor. When this is done, the listener compares the level + of each message with the handler's level, and only passes a message to a + handler if it's appropriate to do so. .. _network-logging: diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -953,13 +953,20 @@ possible, while any potentially slow operations (such as sending an email via :class:`SMTPHandler`) are done on a separate thread. -.. class:: QueueListener(queue, *handlers) +.. class:: QueueListener(queue, *handlers, respect_handler_level=False) Returns a new instance of the :class:`QueueListener` class. The instance is initialized with the queue to send messages to and a list of handlers which will handle entries placed on the queue. The queue can be any queue- like object; it's passed as-is to the :meth:`dequeue` method, which needs - to know how to get messages from it. + to know how to get messages from it. If ``respect_handler_level`` is ``True``, + a handler's level is respected (compared with the level for the message) when + deciding whether to pass messages to that handler; otherwise, the behaviour + is as in previous Python versions - to always pass each message to each + handler. + + .. versionchanged:: 3.5 + The ``respect_handler_levels`` argument was added. .. method:: dequeue(block) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1,4 +1,4 @@ -# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved. +# Copyright 2001-2015 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, @@ -18,7 +18,7 @@ Additional handlers for the logging package for Python. The core package is based on PEP 282 and comments thereto in comp.lang.python. -Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved. +Copyright (C) 2001-2015 Vinay Sajip. All Rights Reserved. To use, simply 'import logging.handlers' and log away! """ @@ -1350,7 +1350,7 @@ """ _sentinel = None - def __init__(self, queue, *handlers): + def __init__(self, queue, *handlers, respect_handler_level=False): """ Initialise an instance with the specified queue and handlers. @@ -1359,6 +1359,7 @@ self.handlers = handlers self._stop = threading.Event() self._thread = None + self.respect_handler_level = respect_handler_level def dequeue(self, block): """ @@ -1399,7 +1400,12 @@ """ record = self.prepare(record) for handler in self.handlers: - handler.handle(record) + if not self.respect_handler_level: + process = True + else: + process = record.levelno >= handler.level + if process: + handler.handle(record) def _monitor(self): """ diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3006,6 +3006,25 @@ self.assertTrue(handler.matches(levelno=logging.WARNING, message='1')) self.assertTrue(handler.matches(levelno=logging.ERROR, message='2')) self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='3')) + handler.close() + + # Now test with respect_handler_level set + + handler = support.TestHandler(support.Matcher()) + handler.setLevel(logging.CRITICAL) + listener = logging.handlers.QueueListener(self.queue, handler, + respect_handler_level=True) + listener.start() + try: + self.que_logger.warning(self.next_message()) + self.que_logger.error(self.next_message()) + self.que_logger.critical(self.next_message()) + finally: + listener.stop() + self.assertFalse(handler.matches(levelno=logging.WARNING, message='4')) + self.assertFalse(handler.matches(levelno=logging.ERROR, message='5')) + self.assertTrue(handler.matches(levelno=logging.CRITICAL, message='6')) + ZERO = datetime.timedelta(0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- logging.handlers.QueueListener now takes a respect_handler_level keyword + argument which, if set to True, will pass messages to handlers taking handler + levels into account. What's New in Python 3.5 alpha 1? ================================= -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 10 03:00:18 2015 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 10 Feb 2015 02:00:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_add_overflow_c?= =?utf-8?q?hecking_=28closes_=2323361=29?= Message-ID: <20150210020004.51390.8411@psf.io> https://hg.python.org/cpython/rev/ab2e79c6cf6b changeset: 94574:ab2e79c6cf6b branch: 3.3 parent: 94476:356ed025dbae user: Benjamin Peterson date: Mon Feb 09 20:58:12 2015 -0500 summary: add overflow checking (closes #23361) files: Misc/NEWS | 2 ++ Modules/_winapi.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,8 @@ Library ------- +- Issue #23361: Fix possible overflow in Windows subprocess creation code. + - Issue #23363: Fix possible overflow in itertools.permutations. - Issue #23364: Fix possible overflow in itertools.product. diff --git a/Modules/_winapi.c b/Modules/_winapi.c --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -513,13 +513,23 @@ "environment can only contain strings"); goto error; } + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(value) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ } - buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4)); - if (! buffer) + buffer = PyMem_NEW(Py_UCS4, totalsize); + if (! buffer) { + PyErr_NoMemory(); goto error; + } p = buffer; end = buffer + totalsize; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 10 03:00:17 2015 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 10 Feb 2015 02:00:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjMzNjEp?= Message-ID: <20150210020005.50305.55619@psf.io> https://hg.python.org/cpython/rev/76170e33f251 changeset: 94576:76170e33f251 parent: 94573:e548ab4ce71d parent: 94575:b82cc9180a78 user: Benjamin Peterson date: Mon Feb 09 21:00:00 2015 -0500 summary: merge 3.4 (#23361) files: Misc/NEWS | 2 ++ Modules/_winapi.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #23361: Fix possible overflow in Windows subprocess creation code. + - logging.handlers.QueueListener now takes a respect_handler_level keyword argument which, if set to True, will pass messages to handlers taking handler levels into account. diff --git a/Modules/_winapi.c b/Modules/_winapi.c --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -670,13 +670,23 @@ "environment can only contain strings"); goto error; } + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(value) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ } - buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4)); - if (! buffer) + buffer = PyMem_NEW(Py_UCS4, totalsize); + if (! buffer) { + PyErr_NoMemory(); goto error; + } p = buffer; end = buffer + totalsize; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 10 03:00:20 2015 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 10 Feb 2015 02:00:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3_=28=2323361=29?= Message-ID: <20150210020005.51406.36510@psf.io> https://hg.python.org/cpython/rev/b82cc9180a78 changeset: 94575:b82cc9180a78 branch: 3.4 parent: 94570:84a05605caeb parent: 94574:ab2e79c6cf6b user: Benjamin Peterson date: Mon Feb 09 20:58:52 2015 -0500 summary: merge 3.3 (#23361) files: Misc/NEWS | 1 + Modules/_winapi.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,7 @@ Library ------- +- Issue #23361: Fix possible overflow in Windows subprocess creation code. What's New in Python 3.4.3rc1? ============================== diff --git a/Modules/_winapi.c b/Modules/_winapi.c --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -535,13 +535,23 @@ "environment can only contain strings"); goto error; } + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(value) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ } - buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4)); - if (! buffer) + buffer = PyMem_NEW(Py_UCS4, totalsize); + if (! buffer) { + PyErr_NoMemory(); goto error; + } p = buffer; end = buffer + totalsize; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 10 07:48:43 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 10 Feb 2015 06:48:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDIx?= =?utf-8?q?=3A_Fixed_compression_in_tarfile_CLI=2E__Patch_by_wdv4758h=2E?= Message-ID: <20150210064802.69879.12719@psf.io> https://hg.python.org/cpython/rev/2a06379f6562 changeset: 94577:2a06379f6562 branch: 3.4 parent: 94575:b82cc9180a78 user: Serhiy Storchaka date: Tue Feb 10 08:45:53 2015 +0200 summary: Issue #23421: Fixed compression in tarfile CLI. Patch by wdv4758h. files: Lib/tarfile.py | 16 ++++++++-------- Lib/test/test_tarfile.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2491,16 +2491,16 @@ _, ext = os.path.splitext(tar_name) compressions = { # gz - 'gz': 'gz', - 'tgz': 'gz', + '.gz': 'gz', + '.tgz': 'gz', # xz - 'xz': 'xz', - 'txz': 'xz', + '.xz': 'xz', + '.txz': 'xz', # bz2 - 'bz2': 'bz2', - 'tbz': 'bz2', - 'tbz2': 'bz2', - 'tb2': 'bz2', + '.bz2': 'bz2', + '.tbz': 'bz2', + '.tbz2': 'bz2', + '.tb2': 'bz2', } tar_mode = 'w:' + compressions[ext] if ext in compressions else 'w' tar_files = args.create diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1994,6 +1994,21 @@ finally: support.unlink(tar_name) + def test_create_command_compressed(self): + files = [support.findfile('tokenize_tests.txt'), + support.findfile('tokenize_tests-no-coding-cookie-' + 'and-utf8-bom-sig-only.txt')] + for filetype in (GzipTest, Bz2Test, LzmaTest): + if not filetype.open: + continue + try: + tar_name = tmpname + '.' + filetype.suffix + out = self.tarfilecmd('-c', tar_name, *files) + with filetype.taropen(tar_name) as tar: + tar.getmembers() + finally: + support.unlink(tar_name) + def test_extract_command(self): self.make_simple_tarfile(tmpname) for opt in '-e', '--extract': diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,8 +13,11 @@ Library ------- +- Issue #23421: Fixed compression in tarfile CLI. Patch by wdv4758h. + - Issue #23361: Fix possible overflow in Windows subprocess creation code. + What's New in Python 3.4.3rc1? ============================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 10 07:48:43 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 10 Feb 2015 06:48:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323421=3A_Fixed_compression_in_tarfile_CLI=2E__P?= =?utf-8?q?atch_by_wdv4758h=2E?= Message-ID: <20150210064803.52880.52999@psf.io> https://hg.python.org/cpython/rev/5b70eb1cfad0 changeset: 94578:5b70eb1cfad0 parent: 94576:76170e33f251 parent: 94577:2a06379f6562 user: Serhiy Storchaka date: Tue Feb 10 08:47:10 2015 +0200 summary: Issue #23421: Fixed compression in tarfile CLI. Patch by wdv4758h. files: Lib/tarfile.py | 16 ++++++++-------- Lib/test/test_tarfile.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2494,16 +2494,16 @@ _, ext = os.path.splitext(tar_name) compressions = { # gz - 'gz': 'gz', - 'tgz': 'gz', + '.gz': 'gz', + '.tgz': 'gz', # xz - 'xz': 'xz', - 'txz': 'xz', + '.xz': 'xz', + '.txz': 'xz', # bz2 - 'bz2': 'bz2', - 'tbz': 'bz2', - 'tbz2': 'bz2', - 'tb2': 'bz2', + '.bz2': 'bz2', + '.tbz': 'bz2', + '.tbz2': 'bz2', + '.tb2': 'bz2', } tar_mode = 'w:' + compressions[ext] if ext in compressions else 'w' tar_files = args.create diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -2006,6 +2006,21 @@ finally: support.unlink(tar_name) + def test_create_command_compressed(self): + files = [support.findfile('tokenize_tests.txt'), + support.findfile('tokenize_tests-no-coding-cookie-' + 'and-utf8-bom-sig-only.txt')] + for filetype in (GzipTest, Bz2Test, LzmaTest): + if not filetype.open: + continue + try: + tar_name = tmpname + '.' + filetype.suffix + out = self.tarfilecmd('-c', tar_name, *files) + with filetype.taropen(tar_name) as tar: + tar.getmembers() + finally: + support.unlink(tar_name) + def test_extract_command(self): self.make_simple_tarfile(tmpname) for opt in '-e', '--extract': diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,12 +13,15 @@ Library ------- +- Issue #23421: Fixed compression in tarfile CLI. Patch by wdv4758h. + - Issue #23361: Fix possible overflow in Windows subprocess creation code. - logging.handlers.QueueListener now takes a respect_handler_level keyword argument which, if set to True, will pass messages to handlers taking handler levels into account. + What's New in Python 3.5 alpha 1? ================================= -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Tue Feb 10 09:28:27 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 10 Feb 2015 09:28:27 +0100 Subject: [Python-checkins] Daily reference leaks (76170e33f251): sum=3 Message-ID: results for 76170e33f251 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogkQWWuJ', '-x'] From python-checkins at python.org Tue Feb 10 14:51:17 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 Feb 2015 13:51:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20150210135117.108381.11413@psf.io> https://hg.python.org/cpython/rev/f4d49881e5d1 changeset: 94580:f4d49881e5d1 parent: 94578:5b70eb1cfad0 parent: 94579:645f3d750be1 user: Victor Stinner date: Tue Feb 10 14:49:56 2015 +0100 summary: Merge 3.4 (asyncio) files: Lib/asyncio/base_subprocess.py | 7 +- Lib/test/test_asyncio/test_subprocess.py | 55 ++++++++++++ 2 files changed, 61 insertions(+), 1 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -93,7 +93,12 @@ continue proto.pipe.close() - if self._proc is not None and self._returncode is None: + if (self._proc is not None + # the child process finished? + and self._returncode is None + # the child process finished but the transport was not notified yet? + and self._proc.poll() is None + ): if self._loop.get_debug(): logger.warning('Close running child process: kill %r', self) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -349,6 +349,61 @@ self.loop.run_until_complete(cancel_make_transport()) test_utils.run_briefly(self.loop) + def test_close_kill_running(self): + @asyncio.coroutine + def kill_running(): + create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + *PROGRAM_BLOCKED) + transport, protocol = yield from create + proc = transport.get_extra_info('subprocess') + proc.kill = mock.Mock() + returncode = transport.get_returncode() + transport.close() + return (returncode, proc.kill.called) + + # Ignore "Close running child process: kill ..." log + with test_utils.disable_logger(): + returncode, killed = self.loop.run_until_complete(kill_running()) + self.assertIsNone(returncode) + + # transport.close() must kill the process if it is still running + self.assertTrue(killed) + test_utils.run_briefly(self.loop) + + def test_close_dont_kill_finished(self): + @asyncio.coroutine + def kill_running(): + create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + *PROGRAM_BLOCKED) + transport, protocol = yield from create + proc = transport.get_extra_info('subprocess') + + # kill the process (but asyncio is not notified immediatly) + proc.kill() + proc.wait() + + proc.kill = mock.Mock() + proc_returncode = proc.poll() + transport_returncode = transport.get_returncode() + transport.close() + return (proc_returncode, transport_returncode, proc.kill.called) + + # Ignore "Unknown child process pid ..." log of SafeChildWatcher, + # emitted because the test already consumes the exit status: + # proc.wait() + with test_utils.disable_logger(): + result = self.loop.run_until_complete(kill_running()) + test_utils.run_briefly(self.loop) + + proc_returncode, transport_return_code, killed = result + + self.assertIsNotNone(proc_returncode) + self.assertIsNone(transport_return_code) + + # transport.close() must not kill the process if it finished, even if + # the transport was not notified yet + self.assertFalse(killed) + if sys.platform != 'win32': # Unix -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 10 14:51:17 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 Feb 2015 13:51:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogQmFz?= =?utf-8?q?eSubprocessTransport=2Eclose=28=29_doesn=27t_try_to_kill_the_pr?= =?utf-8?q?ocess_if_it?= Message-ID: <20150210135116.108381.41492@psf.io> https://hg.python.org/cpython/rev/645f3d750be1 changeset: 94579:645f3d750be1 branch: 3.4 parent: 94577:2a06379f6562 user: Victor Stinner date: Tue Feb 10 14:49:32 2015 +0100 summary: asyncio: BaseSubprocessTransport.close() doesn't try to kill the process if it already finished files: Lib/asyncio/base_subprocess.py | 7 +- Lib/test/test_asyncio/test_subprocess.py | 55 ++++++++++++ 2 files changed, 61 insertions(+), 1 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -93,7 +93,12 @@ continue proto.pipe.close() - if self._proc is not None and self._returncode is None: + if (self._proc is not None + # the child process finished? + and self._returncode is None + # the child process finished but the transport was not notified yet? + and self._proc.poll() is None + ): if self._loop.get_debug(): logger.warning('Close running child process: kill %r', self) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -349,6 +349,61 @@ self.loop.run_until_complete(cancel_make_transport()) test_utils.run_briefly(self.loop) + def test_close_kill_running(self): + @asyncio.coroutine + def kill_running(): + create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + *PROGRAM_BLOCKED) + transport, protocol = yield from create + proc = transport.get_extra_info('subprocess') + proc.kill = mock.Mock() + returncode = transport.get_returncode() + transport.close() + return (returncode, proc.kill.called) + + # Ignore "Close running child process: kill ..." log + with test_utils.disable_logger(): + returncode, killed = self.loop.run_until_complete(kill_running()) + self.assertIsNone(returncode) + + # transport.close() must kill the process if it is still running + self.assertTrue(killed) + test_utils.run_briefly(self.loop) + + def test_close_dont_kill_finished(self): + @asyncio.coroutine + def kill_running(): + create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + *PROGRAM_BLOCKED) + transport, protocol = yield from create + proc = transport.get_extra_info('subprocess') + + # kill the process (but asyncio is not notified immediatly) + proc.kill() + proc.wait() + + proc.kill = mock.Mock() + proc_returncode = proc.poll() + transport_returncode = transport.get_returncode() + transport.close() + return (proc_returncode, transport_returncode, proc.kill.called) + + # Ignore "Unknown child process pid ..." log of SafeChildWatcher, + # emitted because the test already consumes the exit status: + # proc.wait() + with test_utils.disable_logger(): + result = self.loop.run_until_complete(kill_running()) + test_utils.run_briefly(self.loop) + + proc_returncode, transport_return_code, killed = result + + self.assertIsNotNone(proc_returncode) + self.assertIsNone(transport_return_code) + + # transport.close() must not kill the process if it finished, even if + # the transport was not notified yet + self.assertFalse(killed) + if sys.platform != 'win32': # Unix -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 10 22:23:47 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 10 Feb 2015 21:23:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323383=3A_Cleaned_?= =?utf-8?q?up_bytes_formatting=2E?= Message-ID: <20150210212346.130116.89243@psf.io> https://hg.python.org/cpython/rev/4883f9046b10 changeset: 94581:4883f9046b10 user: Serhiy Storchaka date: Tue Feb 10 23:23:12 2015 +0200 summary: Issue #23383: Cleaned up bytes formatting. files: Objects/bytesobject.c | 193 ++++++++--------------------- 1 files changed, 52 insertions(+), 141 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -433,105 +433,46 @@ return result; } -/* format_long emulates the format codes d, u, o, x and X, and - * the F_ALT flag, for Python's long (unbounded) ints. It's not used for - * Python's regular ints. - * Return value: a new PyBytes*, or NULL if error. - * . *pbuf is set to point into it, - * *plen set to the # of chars following that. - * Caller must decref it when done using pbuf. - * The string starting at *pbuf is of the form - * "-"? ("0x" | "0X")? digit+ - * "0x"/"0X" are present only for x and X conversions, with F_ALT - * set in flags. The case of hex digits will be correct, - * There will be at least prec digits, zero-filled on the left if - * necessary to get that many. - * val object to be converted - * flags bitmask of format flags; only F_ALT is looked at - * prec minimum number of digits; 0-fill on left if needed - * type a character in [duoxX]; u acts the same as d - * - * CAUTION: o, x and X conversions on regular ints can never - * produce a '-' sign, but can for Python's unbounded ints. - */ - -static PyObject * -format_long(PyObject *val, int flags, int prec, int type, - char **pbuf, int *plen) +Py_LOCAL_INLINE(int) +byte_converter(PyObject *arg, char *p) { - PyObject *s; - PyObject *result = NULL; - - s = _PyUnicode_FormatLong(val, flags & F_ALT, prec, type); - if (!s) - return NULL; - result = _PyUnicode_AsASCIIString(s, "strict"); - Py_DECREF(s); - if (!result) - return NULL; - *pbuf = PyBytes_AS_STRING(result); - *plen = PyBytes_GET_SIZE(result); - return result; -} - -Py_LOCAL_INLINE(int) -formatchar(char *buf, size_t buflen, PyObject *v) -{ - PyObject *w = NULL; - /* convert bytearray to bytes */ - if (PyByteArray_Check(v)) { - w = PyBytes_FromObject(v); - if (w == NULL) - goto error; - v = w; + if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) { + *p = PyBytes_AS_STRING(arg)[0]; + return 1; } - /* presume that the buffer is at least 2 characters long */ - if (PyBytes_Check(v)) { - if (!PyArg_Parse(v, "c;%c requires an integer in range(256) or a single byte", &buf[0])) - goto error; + else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1) { + *p = PyByteArray_AS_STRING(arg)[0]; + return 1; } else { - long ival = PyLong_AsLong(v); - if (ival == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "%c requires an integer in range(256) or a single byte"); - goto error; + long ival = PyLong_AsLong(arg); + if (0 <= ival && ival <= 255) { + *p = (char)ival; + return 1; } - if (ival < 0 || ival > 255) { - PyErr_SetString(PyExc_TypeError, - "%c requires an integer in range(256) or a single byte"); - goto error; - } - buf[0] = (char)ival; } - Py_XDECREF(w); - buf[1] = '\0'; - return 1; - - error: - Py_XDECREF(w); - return -1; + PyErr_SetString(PyExc_TypeError, + "%c requires an integer in range(256) or a single byte"); + return 0; } static PyObject * -format_obj(PyObject *v) +format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) { - PyObject *result = NULL, *w = NULL; - PyObject *func; + PyObject *func, *result; _Py_IDENTIFIER(__bytes__); - /* convert bytearray to bytes */ - if (PyByteArray_Check(v)) { - w = PyBytes_FromObject(v); - if (w == NULL) - return NULL; - v = w; - } /* is it a bytes object? */ if (PyBytes_Check(v)) { - result = v; + *pbuf = PyBytes_AS_STRING(v); + *plen = PyBytes_GET_SIZE(v); Py_INCREF(v); - Py_XDECREF(w); - return result; + return v; + } + if (PyByteArray_Check(v)) { + *pbuf = PyByteArray_AS_STRING(v); + *plen = PyByteArray_GET_SIZE(v); + Py_INCREF(v); + return v; } /* does it support __bytes__? */ func = _PyObject_LookupSpecial(v, &PyId___bytes__); @@ -547,6 +488,8 @@ Py_DECREF(result); return NULL; } + *pbuf = PyBytes_AS_STRING(result); + *plen = PyBytes_GET_SIZE(result); return result; } PyErr_Format(PyExc_TypeError, @@ -573,7 +516,6 @@ Py_ssize_t reslen, rescnt, fmtcnt; int args_owned = 0; PyObject *result; - PyObject *repr; PyObject *dict = NULL; if (format == NULL || !PyBytes_Check(format) || args == NULL) { PyErr_BadInternalCall(); @@ -619,15 +561,13 @@ int prec = -1; int c = '\0'; int fill; - int isnumok; + PyObject *iobj; PyObject *v = NULL; PyObject *temp = NULL; - Py_buffer buf = {NULL, NULL}; - char *pbuf; + const char *pbuf = NULL; int sign; - Py_ssize_t len; - char formatbuf[FORMATBUFLEN]; - /* For format{int,char}() */ + Py_ssize_t len = 0; + char onechar; /* For byte_converter() */ fmt++; if (*fmt == '(') { @@ -781,37 +721,21 @@ len = 1; break; case 'a': - temp = PyObject_Repr(v); + temp = PyObject_ASCII(v); if (temp == NULL) goto error; - repr = PyUnicode_AsEncodedObject(temp, "ascii", "backslashreplace"); - if (repr == NULL) { - Py_DECREF(temp); - goto error; - } - if (PyObject_GetBuffer(repr, &buf, PyBUF_SIMPLE) != 0) { - temp = format_obj(repr); - if (temp == NULL) { - Py_DECREF(repr); - goto error; - } - Py_DECREF(repr); - repr = temp; - } - pbuf = PyBytes_AS_STRING(repr); - len = PyBytes_GET_SIZE(repr); - Py_DECREF(repr); + assert(PyUnicode_IS_ASCII(temp)); + pbuf = (const char *)PyUnicode_1BYTE_DATA(temp); + len = PyUnicode_GET_LENGTH(temp); if (prec >= 0 && len > prec) len = prec; break; case 's': // %s is only for 2/3 code; 3 only code should use %b case 'b': - temp = format_obj(v); + temp = format_obj(v, &pbuf, &len); if (temp == NULL) goto error; - pbuf = PyBytes_AS_STRING(temp); - len = PyBytes_GET_SIZE(temp); if (prec >= 0 && len > prec) len = prec; break; @@ -823,41 +747,32 @@ case 'X': if (c == 'i') c = 'd'; - isnumok = 0; + iobj = NULL; if (PyNumber_Check(v)) { - PyObject *iobj=NULL; - if ((PyLong_Check(v))) { iobj = v; Py_INCREF(iobj); } else { iobj = PyNumber_Long(v); - } - if (iobj!=NULL) { - if (PyLong_Check(iobj)) { - int ilen; - - isnumok = 1; - temp = format_long(iobj, flags, prec, c, - &pbuf, &ilen); - Py_DECREF(iobj); - if (!temp) - goto error; - len = ilen; - sign = 1; - } - else { - Py_DECREF(iobj); - } + if (iobj != NULL && !PyLong_Check(iobj)) + Py_CLEAR(iobj); } } - if (!isnumok) { + if (iobj == NULL) { PyErr_Format(PyExc_TypeError, "%%%c format: a number is required, " "not %.200s", c, Py_TYPE(v)->tp_name); goto error; } + temp = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, c); + Py_DECREF(iobj); + if (!temp) + goto error; + assert(PyUnicode_IS_ASCII(temp)); + pbuf = (const char *)PyUnicode_1BYTE_DATA(temp); + len = PyUnicode_GET_LENGTH(temp); + sign = 1; if (flags & F_ZERO) fill = '0'; break; @@ -877,9 +792,9 @@ fill = '0'; break; case 'c': - pbuf = formatbuf; - len = formatchar(pbuf, sizeof(formatbuf), v); - if (len < 0) + pbuf = &onechar; + len = byte_converter(v, &onechar); + if (!len) goto error; break; default: @@ -911,12 +826,10 @@ reslen += rescnt; if (reslen < 0) { Py_DECREF(result); - PyBuffer_Release(&buf); Py_XDECREF(temp); return PyErr_NoMemory(); } if (_PyBytes_Resize(&result, reslen)) { - PyBuffer_Release(&buf); Py_XDECREF(temp); return NULL; } @@ -970,11 +883,9 @@ if (dict && (argidx < arglen) && c != '%') { PyErr_SetString(PyExc_TypeError, "not all arguments converted during bytes formatting"); - PyBuffer_Release(&buf); Py_XDECREF(temp); goto error; } - PyBuffer_Release(&buf); Py_XDECREF(temp); } /* '%' */ } /* until end */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 05:37:27 2015 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 11 Feb 2015 04:37:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_copyright=2E?= Message-ID: <20150211043727.29530.29807@psf.io> https://hg.python.org/cpython/rev/7d826a6b92a1 changeset: 94582:7d826a6b92a1 user: Raymond Hettinger date: Tue Feb 10 22:37:22 2015 -0600 summary: Update copyright. files: Modules/_collectionsmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -3,7 +3,7 @@ /* collections module implementation of a deque() datatype Written and maintained by Raymond D. Hettinger - Copyright (c) 2004-2014 Python Software Foundation. + Copyright (c) 2004-2015 Python Software Foundation. All rights reserved. */ -- Repository URL: https://hg.python.org/cpython From benjamin at python.org Wed Feb 11 05:49:01 2015 From: benjamin at python.org (Benjamin Peterson) Date: Tue, 10 Feb 2015 23:49:01 -0500 Subject: [Python-checkins] cpython: Update copyright. In-Reply-To: <20150211043727.29530.29807@psf.io> References: <20150211043727.29530.29807@psf.io> Message-ID: <1423630141.237881.225973753.24ED9A94@webmail.messagingengine.com> On Tue, Feb 10, 2015, at 23:37, raymond.hettinger wrote: > https://hg.python.org/cpython/rev/7d826a6b92a1 > changeset: 94582:7d826a6b92a1 > user: Raymond Hettinger > date: Tue Feb 10 22:37:22 2015 -0600 > summary: > Update copyright. > > files: > Modules/_collectionsmodule.c | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > > diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c > --- a/Modules/_collectionsmodule.c > +++ b/Modules/_collectionsmodule.c > @@ -3,7 +3,7 @@ > > /* collections module implementation of a deque() datatype > Written and maintained by Raymond D. Hettinger > - Copyright (c) 2004-2014 Python Software Foundation. > + Copyright (c) 2004-2015 Python Software Foundation. > All rights reserved. > */ How about simply removing this line? The copyight years are well documented in the LICENSE and README.txt, and it would save you the trouble of keeping this up to date. From solipsis at pitrou.net Wed Feb 11 09:38:56 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 11 Feb 2015 09:38:56 +0100 Subject: [Python-checkins] Daily reference leaks (4883f9046b10): sum=1424 Message-ID: results for 4883f9046b10 on branch "default" -------------------------------------------- test_asyncio leaked [388, 388, 388] references, sum=1164 test_asyncio leaked [84, 88, 85] memory blocks, sum=257 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogS5Lmzl', '-x'] From python-checkins at python.org Wed Feb 11 13:14:09 2015 From: python-checkins at python.org (chris.angelico) Date: Wed, 11 Feb 2015 12:14:09 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_485_from_Chris_Bar?= =?utf-8?q?ker=27s_edits_=28w/_minor_formatting=29?= Message-ID: <20150211121351.37925.47806@psf.io> https://hg.python.org/peps/rev/6625f2ec2d3e changeset: 5694:6625f2ec2d3e user: Chris Angelico date: Wed Feb 11 23:13:44 2015 +1100 summary: Update PEP 485 from Chris Barker's edits (w/ minor formatting) files: pep-0485.txt | 190 ++++++++++++++++++++------------------ 1 files changed, 101 insertions(+), 89 deletions(-) diff --git a/pep-0485.txt b/pep-0485.txt --- a/pep-0485.txt +++ b/pep-0485.txt @@ -16,16 +16,14 @@ This PEP proposes the addition of a function to the standard library that determines whether one value is approximately equal or "close" to -another value. It is also proposed that an assertion be added to the -``unittest.TestCase`` class to provide easy access for those using -unittest for testing. +another value. Rationale ========= Floating point values contain limited precision, which results in -their being unable to exactly represent some values, and for error to +their being unable to exactly represent some values, and for errors to accumulate with repeated computation. As a result, it is common advice to only use an equality comparison in very specific situations. Often a inequality comparison fits the bill, but there are times @@ -49,8 +47,8 @@ * Is an absolute difference test. Often the measure of difference requires, particularly for floating point numbers, a relative error, - i.e "Are these two values within x% of each-other?", rather than an - absolute error. Particularly when the magnatude of the values is + i.e. "Are these two values within x% of each-other?", rather than an + absolute error. Particularly when the magnitude of the values is unknown a priori. The numpy package has the ``allclose()`` and ``isclose()`` functions, @@ -63,7 +61,7 @@ Overflow and other help sites. Many other non-python systems provide such a test, including the Boost C++ -library and the APL language (reference?). +library and the APL language [4]_. These existing implementations indicate that this is a common need and not trivial to write oneself, making it a candidate for the standard @@ -73,28 +71,31 @@ Proposed Implementation ======================= -NOTE: this PEP is the result of an extended discussion on the +NOTE: this PEP is the result of extended discussions on the python-ideas list [1]_. -The new function will have the following signature:: +The new function will go into the math module, and have the following +signature:: - is_close(a, b, rel_tolerance=1e-9, abs_tolerance=0.0) + isclose(a, b, rel_tol=1e-9, abs_tol=0.0) ``a`` and ``b``: are the two values to be tested to relative closeness -``rel_tolerance``: is the relative tolerance -- it is the amount of -error allowed, relative to the magnitude a and b. For example, to set -a tolerance of 5%, pass tol=0.05. The default tolerance is 1e-8, which -assures that the two values are the same within about 8 decimal -digits. +``rel_tol``: is the relative tolerance -- it is the amount of error +allowed, relative to the larger absolute value of a or b. For example, +to set a tolerance of 5%, pass tol=0.05. The default tolerance is 1e-9, +which assures that the two values are the same within about 9 decimal +digits. ``rel_tol`` must be greater than 0.0 -``abs_tolerance``: is an minimum absolute tolerance level -- useful for +``abs_tol``: is an minimum absolute tolerance level -- useful for comparisons near zero. Modulo error checking, etc, the function will return the result of:: - abs(a-b) <= max( rel_tolerance * min(abs(a), abs(b), abs_tolerance ) + abs(a-b) <= max( rel_tol * max(abs(a), abs(b)), abs_tol ) +The name, ``isclose``, is selected for consistency with the existing +``isnan`` and ``isinf``. Handling of non-finite numbers ------------------------------ @@ -111,17 +112,18 @@ The primary use-case is expected to be floating point numbers. However, users may want to compare other numeric types similarly. In theory, it should work for any type that supports ``abs()``, -comparisons, and subtraction. The code will be written and tested to -accommodate these types: +multiplication, comparisons, and subtraction. The code will be written +and tested to accommodate these types: -* ``Decimal``: for Decimal, the tolerance must be set to a Decimal type. +* ``Decimal`` * ``int`` * ``Fraction`` -* ``complex``: for complex, ``abs(z)`` will be used for scaling and - comparison. +* ``complex``: for complex, the absolute value of the complex values + will be used for scaling and comparison. If a complex tolerance is + passed in, the absolute value will be used as the tolerance. Behavior near zero @@ -130,9 +132,9 @@ Relative comparison is problematic if either value is zero. By definition, no value is small relative to zero. And computationally, if either value is zero, the difference is the absolute value of the -other value, and the computed absolute tolerance will be rel_tolerance -times that value. rel-tolerance is always less than one, so the -difference will never be less than the tolerance. +other value, and the computed absolute tolerance will be ``rel_tol`` +times that value. When ``rel_tol`` is less than one, the difference will +never be less than the tolerance. However, while mathematically correct, there are many use cases where a user will need to know if a computed value is "close" to zero. This @@ -146,50 +148,51 @@ if a is approximately equal to -b, then a and b will never be computed as "close". -To handle this case, an optional parameter, ``abs_tolerance`` can be +To handle this case, an optional parameter, ``abs_tol`` can be used to set a minimum tolerance used in the case of very small or zero -computed absolute tolerance. That is, the values will be always be -considered close if the difference between them is less than the -abs_tolerance +computed relative tolerance. That is, the values will be always be +considered close if the difference between them is less than +``abs_tol`` The default absolute tolerance value is set to zero because there is no value that is appropriate for the general case. It is impossible to know an appropriate value without knowing the likely values expected for a given use case. If all the values tested are on order of one, -then a value of about 1e-8 might be appropriate, but that would be far -too large if expected values are on order of 1e-12 or smaller. +then a value of about 1e-9 might be appropriate, but that would be far +too large if expected values are on order of 1e-9 or smaller. Any non-zero default might result in user's tests passing totally -inappropriately. If, on the other hand a test against zero fails the +inappropriately. If, on the other hand, a test against zero fails the first time with defaults, a user will be prompted to select an appropriate value for the problem at hand in order to get the test to pass. NOTE: that the author of this PEP has resolved to go back over many of -his tests that use the numpy ``all_close()`` function, which provides -a default abs_tolerance, and make sure that the default value is +his tests that use the numpy ``allclose()`` function, which provides +a default absolute tolerance, and make sure that the default value is appropriate. -If the user sets the rel_tolerance parameter to 0.0, then only the +If the user sets the rel_tol parameter to 0.0, then only the absolute tolerance will effect the result. While not the goal of the function, it does allow it to be used as a purely absolute tolerance check as well. -unittest assertion -------------------- -[need text here] - -implementation +Implementation -------------- A sample implementation is available (as of Jan 22, 2015) on gitHub: -https://github.com/PythonCHB/close_pep/blob/master +https://github.com/PythonCHB/close_pep/blob/master/is_close.py This implementation has a flag that lets the user select which relative tolerance test to apply -- this PEP does not suggest that -that be retained, but rather than the strong test be selected. +that be retained, but rather than the weak test be selected. + +There are also drafts of this PEP and test code, etc. there: + +https://github.com/PythonCHB/close_pep + Relative Difference =================== @@ -215,7 +218,7 @@ 4) The absolute value of the arithmetic mean of the two -These lead to the following possibilities for determining if two +These leads to the following possibilities for determining if two values, a and b, are close to each other. 1) ``abs(a-b) <= tol*abs(a)`` @@ -228,9 +231,9 @@ NOTE: (2) and (3) can also be written as: -2) ``(abs(a-b) <= tol*abs(a)) or (abs(a-b) <= tol*abs(a))`` +2) ``(abs(a-b) <= abs(tol*a)) or (abs(a-b) <= abs(tol*b))`` -3) ``(abs(a-b) <= tol*abs(a)) and (abs(a-b) <= tol*abs(a))`` +3) ``(abs(a-b) <= abs(tol*a)) and (abs(a-b) <= abs(tol*b))`` (Boost refers to these as the "weak" and "strong" formulations [3]_) These can be a tiny bit more computationally efficient, and thus are @@ -292,7 +295,7 @@ minimum tolerance ``tol * b == 0.1 * 9.0 == 0.9`` -delta = ``(1.0 - 0.9) * 0.1 = 0.1`` or ``tol**2 * a = 0.1**2 * 10 = .01`` +delta = ``(1.0 - 0.9) = 0.1`` or ``tol**2 * a = 0.1**2 * 10 = .1`` The absolute difference between the maximum and minimum tolerance tests in this case could be substantial. However, the primary use @@ -310,7 +313,7 @@ yield exactly the same results for all values of a and b. In addition, in common use, tolerances are defined to 1 significant -figure -- that is, 1e-8 is specifying about 8 decimal digits of +figure -- that is, 1e-9 is specifying about 9 decimal digits of accuracy. So the difference between the various possible tests is well below the precision to which the tolerance is specified. @@ -321,11 +324,11 @@ A relative comparison can be either symmetric or non-symmetric. For a symmetric algorithm: -``is_close_to(a,b)`` is always the same as ``is_close_to(b,a)`` +``isclose(a,b)`` is always the same as ``isclose(b,a)`` If a relative closeness test uses only one of the values (such as (1) -above), then the result is asymmetric, i.e. is_close_to(a,b) is not -necessarily the same as is_close_to(b,a). +above), then the result is asymmetric, i.e. isclose(a,b) is not +necessarily the same as isclose(b,a). Which approach is most appropriate depends on what question is being asked. If the question is: "are these two numbers close to each @@ -369,18 +372,31 @@ the value be either added together before dividing by 2, which could result in extra overflow to inf for very large numbers, or require each value to be divided by two before being added together, which -could result in underflow to -inf for very small numbers. This effect +could result in underflow to zero for very small numbers. This effect would only occur at the very limit of float values, but it was decided -there as no benefit to the method worth reducing the range of -functionality. +there was no benefit to the method worth reducing the range of +functionality or adding the complexity of checking values to determine +the order of computation. This leaves the boost "weak" test (2)-- or using the smaller value to scale the tolerance, or the Boost "strong" (3) test, which uses the smaller of the values to scale the tolerance. For small tolerance, -they yield the same result, but this proposal uses the boost "strong" -test case: it is symmetric and provides a slightly stricter criteria -for tolerance. +they yield the same result, but this proposal uses the boost "weak" +test case: it is symmetric and provides a more useful result for very +large tolerances. +Large tolerances +---------------- + +The most common use case is expected to be small tolerances -- on order of the +default 1e-9. However there may be use cases where a user wants to know if two +fairly disparate values are within a particular range of each other: "is a +within 200% (rel_tol = 2.0) of b? In this case, the string test would never +indicate that two values are within that range of each other if one of them is +zero. The strong case, however would use the larger (non-zero) value for the +test, and thus return true if one value is zero. For example: is 0 within 200% +of 10? 200% of ten is 20, so the range within 200% of ten is -10 to +30. Zero +falls within that range, so it will return True. Defaults ======== @@ -392,16 +408,15 @@ The relative tolerance required for two values to be considered "close" is entirely use-case dependent. Nevertheless, the relative -tolerance needs to be less than 1.0, and greater than 1e-16 -(approximate precision of a python float). The value of 1e-9 was -selected because it is the largest relative tolerance for which the -various possible methods will yield the same result, and it is also -about half of the precision available to a python float. In the -general case, a good numerical algorithm is not expected to lose more -than about half of available digits of accuracy, and if a much larger -tolerance is acceptable, the user should be considering the proper -value in that case. Thus 1-e9 is expected to "just work" for many -cases. +tolerance needs to be greater than 1e-16 (approximate precision of a +python float). The value of 1e-9 was selected because it is the +largest relative tolerance for which the various possible methods will +yield the same result, and it is also about half of the precision +available to a python float. In the general case, a good numerical +algorithm is not expected to lose more than about half of available +digits of accuracy, and if a much larger tolerance is acceptable, the +user should be considering the proper value in that case. Thus 1-e9 is +expected to "just work" for many cases. Absolute tolerance default -------------------------- @@ -437,19 +452,16 @@ results computed near what I expect as a result?" This sort of test may or may not be part of a formal unit testing suite. Such testing could be used one-off at the command line, in an iPython notebook, -part of doctests, or simple assets in an ``if __name__ == "__main__"`` +part of doctests, or simple asserts in an ``if __name__ == "__main__"`` block. -The proposed unitest.TestCase assertion would have course be used in -unit testing. - It would also be an appropriate function to use for the termination criteria for a simple iterative solution to an implicit function:: guess = something while True: new_guess = implicit_function(guess, *args) - if is_close(new_guess, guess): + if isclose(new_guess, guess): break guess = new_guess @@ -481,13 +493,13 @@ This method is purely an absolute tolerance test, and does not address the need for a relative tolerance test. -numpy ``is_close()`` --------------------- +numpy ``isclose()`` +------------------- http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.isclose.html -The numpy package provides the vectorized functions is_close() and -all_close, for similar use cases as this proposal: +The numpy package provides the vectorized functions isclose() and +allclose(), for similar use cases as this proposal: ``isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)`` @@ -522,9 +534,9 @@ ------------------------------- The Boost project ( [3]_ ) provides a floating point comparison -function. Is is a symmetric approach, with both "weak" (larger of the +function. It is a symmetric approach, with both "weak" (larger of the two relative errors) and "strong" (smaller of the two relative errors) -options. This proposal uses the Boost "strong" approach. There is no +options. This proposal uses the Boost "weak" approach. There is no need to complicate the API by providing the option to select different methods when the results will be similar in most cases, and the user is unlikely to know which to select in any case. @@ -545,10 +557,6 @@ test to, at the very least, copy the function into their code base, and select the comparison method to use. -In addition, adding the function to the standard library allows it to -be used in the ``unittest.TestCase.assertIsClose()`` method, providing -a substantial convenience to those using unittest. - ``zero_tol`` '''''''''''' @@ -568,16 +576,15 @@ ''''''''''''''''''''' Given the issues with comparing to zero, another possibility would -have been to only provide a relative tolerance, and let every -comparison to zero fail. In this case, the user would need to do a -simple absolute test: `abs(val) < zero_tol` in the case where the -comparison involved zero. +have been to only provide a relative tolerance, and let comparison to +zero fail. In this case, the user would need to do a simple absolute +test: `abs(val) < zero_tol` in the case where the comparison involved +zero. However, this would not allow the same call to be used for a sequence -of values, such as in a loop or comprehension, or in the -``TestCase.assertClose()`` method. Making the function far less -useful. It is noted that the default abs_tolerance=0.0 achieves the -same effect if the default is not overidden. +of values, such as in a loop or comprehension. Making the function far +less useful. It is noted that the default abs_tol=0.0 achieves the +same effect if the default is not overridden. Other tests '''''''''''' @@ -605,6 +612,11 @@ http://www.boost.org/doc/libs/1_35_0/libs/test/doc/components/test_tools/floating_point_comparison.html +.. [4] 1976. R. H. Lathwell. APL comparison tolerance. Proceedings of + the eighth international conference on APL Pages 255 - 258 + + http://dl.acm.org/citation.cfm?doid=800114.803685 + .. Bruce Dawson's discussion of floating point. https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Feb 11 14:26:06 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 Feb 2015 13:26:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDMz?= =?utf-8?q?=3A_Fix_faulthandler=2E=5Fstack=5Foverflow=28=29?= Message-ID: <20150211132548.29520.73950@psf.io> https://hg.python.org/cpython/rev/689092296ad3 changeset: 94583:689092296ad3 branch: 3.4 parent: 94579:645f3d750be1 user: Victor Stinner date: Wed Feb 11 14:23:35 2015 +0100 summary: Issue #23433: Fix faulthandler._stack_overflow() Fix undefined behaviour: don't compare pointers. Use Py_uintptr_t type instead of void*. It fixes test_faulthandler on Fedora 22 which now uses GCC 5. files: Modules/faulthandler.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -911,12 +911,12 @@ } #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) -static void* -stack_overflow(void *min_sp, void *max_sp, size_t *depth) +static Py_uintptr_t +stack_overflow(Py_uintptr_t min_sp, Py_uintptr_t max_sp, size_t *depth) { /* allocate 4096 bytes on the stack at each call */ unsigned char buffer[4096]; - void *sp = &buffer; + Py_uintptr_t sp = (Py_uintptr_t)&buffer; *depth += 1; if (sp < min_sp || max_sp < sp) return sp; @@ -929,7 +929,8 @@ faulthandler_stack_overflow(PyObject *self) { size_t depth, size; - char *sp = (char *)&depth, *stop; + Py_uintptr_t sp = (Py_uintptr_t)&depth; + Py_uintptr_t stop; depth = 0; stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 14:26:06 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 Feb 2015 13:26:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy40IChmYXVsdGhhbmRsZXIp?= Message-ID: <20150211132548.37955.68418@psf.io> https://hg.python.org/cpython/rev/f50974be635d changeset: 94584:f50974be635d parent: 94582:7d826a6b92a1 parent: 94583:689092296ad3 user: Victor Stinner date: Wed Feb 11 14:23:46 2015 +0100 summary: Merge 3.4 (faulthandler) files: Modules/faulthandler.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -927,12 +927,12 @@ } #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) -static void* -stack_overflow(void *min_sp, void *max_sp, size_t *depth) +static Py_uintptr_t +stack_overflow(Py_uintptr_t min_sp, Py_uintptr_t max_sp, size_t *depth) { /* allocate 4096 bytes on the stack at each call */ unsigned char buffer[4096]; - void *sp = &buffer; + Py_uintptr_t sp = (Py_uintptr_t)&buffer; *depth += 1; if (sp < min_sp || max_sp < sp) return sp; @@ -945,7 +945,8 @@ faulthandler_stack_overflow(PyObject *self) { size_t depth, size; - char *sp = (char *)&depth, *stop; + Py_uintptr_t sp = (Py_uintptr_t)&depth; + Py_uintptr_t stop; faulthandler_suppress_crash_report(); depth = 0; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 14:32:41 2015 From: python-checkins at python.org (berker.peksag) Date: Wed, 11 Feb 2015 13:32:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_typos_in_Doc/whatsnew/?= =?utf-8?b?My41LnJzdC4=?= Message-ID: <20150211133222.43793.70987@psf.io> https://hg.python.org/cpython/rev/688cd0682916 changeset: 94585:688cd0682916 user: Berker Peksag date: Wed Feb 11 15:32:34 2015 +0200 summary: Fix typos in Doc/whatsnew/3.5.rst. files: Doc/whatsnew/3.5.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -149,7 +149,7 @@ cgi --- -* :class:`FieldStorage` now supports the context management protocol. +* :class:`~cgi.FieldStorage` now supports the context management protocol. (Contributed by Berker Peksag in :issue:`20289`.) code @@ -340,8 +340,8 @@ * The :func:`time.monotonic` function is now always available. (Contributed by Victor Stinner in :issue:`22043`.) -time ----- +urllib +------ * A new :class:`urllib.request.HTTPBasicPriorAuthHandler` allows HTTP Basic Authentication credentials to be sent unconditionally with the first HTTP -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 14:56:46 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 11 Feb 2015 13:56:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323344=3A_marshal?= =?utf-8?q?=2Edumps=28=29_is_now_20-25=25_faster_on_average=2E?= Message-ID: <20150211135548.37929.28959@psf.io> https://hg.python.org/cpython/rev/bb05f845e7dc changeset: 94587:bb05f845e7dc user: Serhiy Storchaka date: Wed Feb 11 15:54:54 2015 +0200 summary: Issue #23344: marshal.dumps() is now 20-25% faster on average. files: Doc/whatsnew/3.5.rst | 5 +- Misc/NEWS | 2 + Python/marshal.c | 83 +++++++++++++++++++++++-------- 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -381,8 +381,9 @@ * Many operations on :class:`io.BytesIO` are now 50% to 100% faster. (Contributed by Serhiy Storchaka in :issue:`15381`.) -* :func:`marshal.dumps` with versions 3 and 4 is now 40-50% faster on average. - (Contributed by Serhiy Storchaka in :issue:`20416`.) +* :func:`marshal.dumps` is now faster (65%-85% with versions 3--4, 20-25% with + versions 0--2 on typical data, and up to 5x in best cases). + (Contributed by Serhiy Storchaka in :issue:`20416` and :issue:`23344`.) Build and C API Changes diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #23344: marshal.dumps() is now 20-25% faster on average. + - Issue #20416: marshal.dumps() with protocols 3 and 4 is now 40-50% faster on average. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -78,42 +78,75 @@ int version; } WFILE; -#define w_byte(c, p) if (((p)->fp)) putc((c), (p)->fp); \ - else if ((p)->ptr != (p)->end) *(p)->ptr++ = (c); \ - else w_more((c), p) +#define w_byte(c, p) do { \ + if ((p)->ptr != (p)->end || w_reserve((p), 1)) \ + *(p)->ptr++ = (c); \ + } while(0) static void -w_more(char c, WFILE *p) +w_flush(WFILE *p) { - Py_ssize_t size, newsize; - if (p->str == NULL) - return; /* An error already occurred */ + assert(p->fp != NULL); + fwrite(p->buf, 1, p->ptr - p->buf, p->fp); + p->ptr = p->buf; +} + +static int +w_reserve(WFILE *p, Py_ssize_t needed) +{ + Py_ssize_t pos, size, delta; + if (p->ptr == NULL) + return 0; /* An error already occurred */ + if (p->fp != NULL) { + w_flush(p); + return needed <= p->end - p->ptr; + } + assert(p->str != NULL); + pos = p->ptr - p->buf; size = PyBytes_Size(p->str); - newsize = size + size + 1024; - if (newsize > 32*1024*1024) { - newsize = size + (size >> 3); /* 12.5% overallocation */ + if (size > 16*1024*1024) + delta = (size >> 3); /* 12.5% overallocation */ + else + delta = size + 1024; + delta = Py_MAX(delta, needed); + if (delta > PY_SSIZE_T_MAX - size) { + p->error = WFERR_NOMEMORY; + return 0; } - if (_PyBytes_Resize(&p->str, newsize) != 0) { - p->ptr = p->end = NULL; + size += delta; + if (_PyBytes_Resize(&p->str, size) != 0) { + p->ptr = p->buf = p->end = NULL; + return 0; } else { - p->ptr = PyBytes_AS_STRING((PyBytesObject *)p->str) + size; - p->end = - PyBytes_AS_STRING((PyBytesObject *)p->str) + newsize; - *p->ptr++ = c; + p->buf = PyBytes_AS_STRING(p->str); + p->ptr = p->buf + pos; + p->end = p->buf + size; + return 1; } } static void w_string(const char *s, Py_ssize_t n, WFILE *p) { + Py_ssize_t m; + if (!n || p->ptr == NULL) + return; + m = p->end - p->ptr; if (p->fp != NULL) { - fwrite(s, 1, n, p->fp); + if (n <= m) { + Py_MEMCPY(p->ptr, s, n); + p->ptr += n; + } + else { + w_flush(p); + fwrite(s, 1, n, p->fp); + } } else { - while (--n >= 0) { - w_byte(*s, p); - s++; + if (n <= m || w_reserve(p, n - m)) { + Py_MEMCPY(p->ptr, s, n); + p->ptr += n; } } } @@ -573,26 +606,34 @@ void PyMarshal_WriteLongToFile(long x, FILE *fp, int version) { + char buf[4]; WFILE wf; memset(&wf, 0, sizeof(wf)); wf.fp = fp; + wf.ptr = wf.buf = buf; + wf.end = wf.ptr + sizeof(buf); wf.error = WFERR_OK; wf.version = version; w_long(x, &wf); + w_flush(&wf); } void PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version) { + char buf[BUFSIZ]; WFILE wf; memset(&wf, 0, sizeof(wf)); wf.fp = fp; + wf.ptr = wf.buf = buf; + wf.end = wf.ptr + sizeof(buf); wf.error = WFERR_OK; wf.version = version; if (w_init_refs(&wf, version)) return; /* caller mush check PyErr_Occurred() */ w_object(x, &wf); w_clear_refs(&wf); + w_flush(&wf); } typedef WFILE RFILE; /* Same struct with different invariants */ @@ -1533,7 +1574,7 @@ wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); if (wf.str == NULL) return NULL; - wf.ptr = PyBytes_AS_STRING((PyBytesObject *)wf.str); + wf.ptr = wf.buf = PyBytes_AS_STRING((PyBytesObject *)wf.str); wf.end = wf.ptr + PyBytes_Size(wf.str); wf.error = WFERR_OK; wf.version = version; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 14:56:46 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 11 Feb 2015 13:56:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320416=3A_marshal?= =?utf-8?q?=2Edumps=28=29_with_protocols_3_and_4_is_now_40-50=25_faster_on?= Message-ID: <20150211135547.11110.45932@psf.io> https://hg.python.org/cpython/rev/012364df2712 changeset: 94586:012364df2712 user: Serhiy Storchaka date: Wed Feb 11 15:53:31 2015 +0200 summary: Issue #20416: marshal.dumps() with protocols 3 and 4 is now 40-50% faster on average. files: Doc/whatsnew/3.5.rst | 3 + Misc/NEWS | 3 + Python/marshal.c | 95 ++++++++++++++++++------------- 3 files changed, 61 insertions(+), 40 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -381,6 +381,9 @@ * Many operations on :class:`io.BytesIO` are now 50% to 100% faster. (Contributed by Serhiy Storchaka in :issue:`15381`.) +* :func:`marshal.dumps` with versions 3 and 4 is now 40-50% faster on average. + (Contributed by Serhiy Storchaka in :issue:`20416`.) + Build and C API Changes ======================= diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #20416: marshal.dumps() with protocols 3 and 4 is now 40-50% faster on + average. + - Issue #23421: Fixed compression in tarfile CLI. Patch by wdv4758h. - Issue #23361: Fix possible overflow in Windows subprocess creation code. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -12,6 +12,7 @@ #include "longintrepr.h" #include "code.h" #include "marshal.h" +#include "../Modules/hashtable.h" /* High water mark to determine when the marshalled object is dangerously deep * and risks coring the interpreter. When the object stack gets this deep, @@ -73,6 +74,7 @@ char *buf; Py_ssize_t buf_size; PyObject *refs; /* dict on marshal, list on unmarshal */ + _Py_hashtable_t *hashtable; int version; } WFILE; @@ -223,46 +225,38 @@ static int w_ref(PyObject *v, char *flag, WFILE *p) { - PyObject *id; - PyObject *idx; + _Py_hashtable_entry_t *entry; + int w; - if (p->version < 3 || p->refs == NULL) + if (p->version < 3 || p->hashtable == NULL) return 0; /* not writing object references */ /* if it has only one reference, it definitely isn't shared */ if (Py_REFCNT(v) == 1) return 0; - id = PyLong_FromVoidPtr((void*)v); - if (id == NULL) - goto err; - idx = PyDict_GetItem(p->refs, id); - if (idx != NULL) { + entry = _Py_hashtable_get_entry(p->hashtable, v); + if (entry != NULL) { /* write the reference index to the stream */ - long w = PyLong_AsLong(idx); - Py_DECREF(id); - if (w == -1 && PyErr_Occurred()) { - goto err; - } + _Py_HASHTABLE_ENTRY_READ_DATA(p->hashtable, &w, sizeof(w), entry); /* we don't store "long" indices in the dict */ assert(0 <= w && w <= 0x7fffffff); w_byte(TYPE_REF, p); w_long(w, p); return 1; } else { - int ok; - Py_ssize_t s = PyDict_Size(p->refs); + size_t s = p->hashtable->entries; /* we don't support long indices */ if (s >= 0x7fffffff) { PyErr_SetString(PyExc_ValueError, "too many objects"); goto err; } - idx = PyLong_FromSsize_t(s); - ok = idx && PyDict_SetItem(p->refs, id, idx) == 0; - Py_DECREF(id); - Py_XDECREF(idx); - if (!ok) + w = s; + Py_INCREF(v); + if (_Py_HASHTABLE_SET(p->hashtable, v, w) < 0) { + Py_DECREF(v); goto err; + } *flag |= FLAG_REF; return 0; } @@ -545,15 +539,44 @@ } } +static int +w_init_refs(WFILE *wf, int version) +{ + if (version >= 3) { + wf->hashtable = _Py_hashtable_new(sizeof(int), _Py_hashtable_hash_ptr, + _Py_hashtable_compare_direct); + if (wf->hashtable == NULL) { + PyErr_NoMemory(); + return -1; + } + } + return 0; +} + +static int +w_decref_entry(_Py_hashtable_entry_t *entry, void *Py_UNUSED(data)) +{ + Py_XDECREF(entry->key); + return 0; +} + +static void +w_clear_refs(WFILE *wf) +{ + if (wf->hashtable != NULL) { + _Py_hashtable_foreach(wf->hashtable, w_decref_entry, NULL); + _Py_hashtable_destroy(wf->hashtable); + } +} + /* version currently has no effect for writing ints. */ void PyMarshal_WriteLongToFile(long x, FILE *fp, int version) { WFILE wf; + memset(&wf, 0, sizeof(wf)); wf.fp = fp; wf.error = WFERR_OK; - wf.depth = 0; - wf.refs = NULL; wf.version = version; w_long(x, &wf); } @@ -562,17 +585,14 @@ PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version) { WFILE wf; + memset(&wf, 0, sizeof(wf)); wf.fp = fp; wf.error = WFERR_OK; - wf.depth = 0; - if (version >= 3) { - if ((wf.refs = PyDict_New()) == NULL) - return; /* caller mush check PyErr_Occurred() */ - } else - wf.refs = NULL; wf.version = version; + if (w_init_refs(&wf, version)) + return; /* caller mush check PyErr_Occurred() */ w_object(x, &wf); - Py_XDECREF(wf.refs); + w_clear_refs(&wf); } typedef WFILE RFILE; /* Same struct with different invariants */ @@ -1509,25 +1529,20 @@ { WFILE wf; - wf.fp = NULL; - wf.readable = NULL; + memset(&wf, 0, sizeof(wf)); wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); if (wf.str == NULL) return NULL; wf.ptr = PyBytes_AS_STRING((PyBytesObject *)wf.str); wf.end = wf.ptr + PyBytes_Size(wf.str); wf.error = WFERR_OK; - wf.depth = 0; wf.version = version; - if (version >= 3) { - if ((wf.refs = PyDict_New()) == NULL) { - Py_DECREF(wf.str); - return NULL; - } - } else - wf.refs = NULL; + if (w_init_refs(&wf, version)) { + Py_DECREF(wf.str); + return NULL; + } w_object(x, &wf); - Py_XDECREF(wf.refs); + w_clear_refs(&wf); if (wf.str != NULL) { char *base = PyBytes_AS_STRING((PyBytesObject *)wf.str); if (wf.ptr - base > PY_SSIZE_T_MAX) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 15:20:54 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 11 Feb 2015 14:20:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Splitted_the_WFILE_structu?= =?utf-8?q?re_to_WFILE_and_RFILE=2E?= Message-ID: <20150211141901.31022.63604@psf.io> https://hg.python.org/cpython/rev/c9c6b5bcdb1f changeset: 94588:c9c6b5bcdb1f user: Serhiy Storchaka date: Wed Feb 11 16:18:09 2015 +0200 summary: Splitted the WFILE structure to WFILE and RFILE. files: Python/marshal.c | 17 +++++++++++------ 1 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -65,15 +65,10 @@ FILE *fp; int error; /* see WFERR_* values */ int depth; - /* If fp == NULL, the following are valid: */ - PyObject *readable; /* Stream-like object being read from */ PyObject *str; - PyObject *current_filename; char *ptr; char *end; char *buf; - Py_ssize_t buf_size; - PyObject *refs; /* dict on marshal, list on unmarshal */ _Py_hashtable_t *hashtable; int version; } WFILE; @@ -636,7 +631,17 @@ w_flush(&wf); } -typedef WFILE RFILE; /* Same struct with different invariants */ +typedef struct { + FILE *fp; + int depth; + PyObject *readable; /* Stream-like object being read from */ + PyObject *current_filename; + char *ptr; + char *end; + char *buf; + Py_ssize_t buf_size; + PyObject *refs; /* a list */ +} RFILE; static char * r_string(Py_ssize_t n, RFILE *p) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 18:19:01 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 Feb 2015 17:19:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy40ICh0eXBvKQ==?= Message-ID: <20150211171900.11128.85393@psf.io> https://hg.python.org/cpython/rev/8f978b2891dc changeset: 94590:8f978b2891dc parent: 94588:c9c6b5bcdb1f parent: 94589:368b2021c2e7 user: Victor Stinner date: Wed Feb 11 18:18:10 2015 +0100 summary: Merge 3.4 (typo) files: Include/unicodeobject.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1052,7 +1052,7 @@ always ends with a nul character. If size is not NULL, write the number of wide characters (excluding the null character) into *size. - Returns a buffer allocated by PyMem_Alloc() (use PyMem_Free() to free it) + Returns a buffer allocated by PyMem_Malloc() (use PyMem_Free() to free it) on success. On error, returns NULL, *size is undefined and raises a MemoryError. */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 18:19:01 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 11 Feb 2015 17:19:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogRml4IHR5cG86IFB5?= =?utf-8?q?Mem=5FAlloc_=3D=3E_PyMem=5FMalloc?= Message-ID: <20150211171900.31024.1833@psf.io> https://hg.python.org/cpython/rev/368b2021c2e7 changeset: 94589:368b2021c2e7 branch: 3.4 parent: 94583:689092296ad3 user: Victor Stinner date: Wed Feb 11 18:17:56 2015 +0100 summary: Fix typo: PyMem_Alloc => PyMem_Malloc files: Include/unicodeobject.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1052,7 +1052,7 @@ always ends with a nul character. If size is not NULL, write the number of wide characters (excluding the null character) into *size. - Returns a buffer allocated by PyMem_Alloc() (use PyMem_Free() to free it) + Returns a buffer allocated by PyMem_Malloc() (use PyMem_Free() to free it) on success. On error, returns NULL, *size is undefined and raises a MemoryError. */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 19:41:17 2015 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 11 Feb 2015 18:41:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323445=3A_pydebug_builds_now_use_=22gcc_-Og=22_w?= =?utf-8?q?here_possible=2C_to_make_the?= Message-ID: <20150211184113.29538.70627@psf.io> https://hg.python.org/cpython/rev/527ed5205806 changeset: 94592:527ed5205806 parent: 94590:8f978b2891dc parent: 94591:e37b201297d2 user: Antoine Pitrou date: Wed Feb 11 19:41:01 2015 +0100 summary: Issue #23445: pydebug builds now use "gcc -Og" where possible, to make the resulting executable faster. files: Misc/NEWS | 6 ++++++ configure | 6 +++++- configure.ac | 6 +++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,12 @@ argument which, if set to True, will pass messages to handlers taking handler levels into account. +Build +----- + +- Issue #23445: pydebug builds now use "gcc -Og" where possible, to make + the resulting executable faster. + What's New in Python 3.5 alpha 1? ================================= diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6338,7 +6338,11 @@ if test "$Py_DEBUG" = 'true' ; then # Optimization messes up debuggers, so turn it off for # debug builds. - OPT="-g -O0 -Wall $STRICT_PROTO" + if "$CC" -v --help 2>/dev/null |grep -- -Og > /dev/null; then + OPT="-g -Og -Wall $STRICT_PROTO" + else + OPT="-g -O0 -Wall $STRICT_PROTO" + fi else OPT="-g $WRAP -O3 -Wall $STRICT_PROTO" fi diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1128,7 +1128,11 @@ if test "$Py_DEBUG" = 'true' ; then # Optimization messes up debuggers, so turn it off for # debug builds. - OPT="-g -O0 -Wall $STRICT_PROTO" + if "$CC" -v --help 2>/dev/null |grep -- -Og > /dev/null; then + OPT="-g -Og -Wall $STRICT_PROTO" + else + OPT="-g -O0 -Wall $STRICT_PROTO" + fi else OPT="-g $WRAP -O3 -Wall $STRICT_PROTO" fi -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 11 19:41:17 2015 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 11 Feb 2015 18:41:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDQ1?= =?utf-8?q?=3A_pydebug_builds_now_use_=22gcc_-Og=22_where_possible=2C_to_m?= =?utf-8?q?ake_the?= Message-ID: <20150211184112.37947.11840@psf.io> https://hg.python.org/cpython/rev/e37b201297d2 changeset: 94591:e37b201297d2 branch: 3.4 parent: 94589:368b2021c2e7 user: Antoine Pitrou date: Wed Feb 11 19:39:16 2015 +0100 summary: Issue #23445: pydebug builds now use "gcc -Og" where possible, to make the resulting executable faster. files: Misc/NEWS | 6 ++++++ configure | 6 +++++- configure.ac | 6 +++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,12 @@ - Issue #23361: Fix possible overflow in Windows subprocess creation code. +Build +----- + +- Issue #23445: pydebug builds now use "gcc -Og" where possible, to make + the resulting executable faster. + What's New in Python 3.4.3rc1? ============================== diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6283,7 +6283,11 @@ if test "$Py_DEBUG" = 'true' ; then # Optimization messes up debuggers, so turn it off for # debug builds. - OPT="-g -O0 -Wall $STRICT_PROTO" + if "$CC" -v --help 2>/dev/null |grep -- -Og > /dev/null; then + OPT="-g -Og -Wall $STRICT_PROTO" + else + OPT="-g -O0 -Wall $STRICT_PROTO" + fi else OPT="-g $WRAP -O3 -Wall $STRICT_PROTO" fi diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1119,7 +1119,11 @@ if test "$Py_DEBUG" = 'true' ; then # Optimization messes up debuggers, so turn it off for # debug builds. - OPT="-g -O0 -Wall $STRICT_PROTO" + if "$CC" -v --help 2>/dev/null |grep -- -Og > /dev/null; then + OPT="-g -Og -Wall $STRICT_PROTO" + else + OPT="-g -O0 -Wall $STRICT_PROTO" + fi else OPT="-g $WRAP -O3 -Wall $STRICT_PROTO" fi -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 12 02:49:25 2015 From: python-checkins at python.org (steve.dower) Date: Thu, 12 Feb 2015 01:49:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_installer_Back_button_?= =?utf-8?q?going_to_wrong_page_when_modifying=2E?= Message-ID: <20150212014917.11122.97807@psf.io> https://hg.python.org/cpython/rev/4828cb77bf2a changeset: 94593:4828cb77bf2a user: Steve Dower date: Wed Feb 11 17:49:01 2015 -0800 summary: Fix installer Back button going to wrong page when modifying. Also fix error when doing test builds without documentation file. files: Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp | 9 ++++++++- Tools/msi/doc/doc.wxs | 2 ++ 2 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp --- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp +++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp @@ -325,7 +325,11 @@ case ID_CUSTOM1_BACK_BUTTON: SavePageSettings(); - GoToPage(PAGE_INSTALL); + if (_modifying) { + GoToPage(PAGE_MODIFY); + } else { + GoToPage(PAGE_INSTALL); + } break; case ID_INSTALL_CUSTOM_BUTTON: __fallthrough; @@ -412,6 +416,7 @@ _engine->SetVariableString(L"InstallAllUsersState", L"disable"); _engine->SetVariableString(L"TargetDirState", L"disable"); _engine->SetVariableString(L"CustomBrowseButtonState", L"disable"); + _modifying = TRUE; GoToPage(PAGE_CUSTOM1); break; @@ -2518,6 +2523,7 @@ _suppressDowngradeFailure = FALSE; _suppressRepair = FALSE; + _modifying = FALSE; _overridableVariables = nullptr; _taskbarList = nullptr; @@ -2598,6 +2604,7 @@ BOOL _suppressDowngradeFailure; BOOL _suppressRepair; + BOOL _modifying; STRINGDICT_HANDLE _overridableVariables; diff --git a/Tools/msi/doc/doc.wxs b/Tools/msi/doc/doc.wxs --- a/Tools/msi/doc/doc.wxs +++ b/Tools/msi/doc/doc.wxs @@ -10,6 +10,7 @@ + @@ -20,6 +21,7 @@ Description="!(loc.ShortcutDescription)" /> + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 12 16:35:39 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 12 Feb 2015 15:35:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323450=3A_Fix_sign?= =?utf-8?q?al=2Eset=5Fwakeup=5Ffd=28=29_on_Windows?= Message-ID: <20150212153500.43805.61903@psf.io> https://hg.python.org/cpython/rev/9e10c4255277 changeset: 94594:9e10c4255277 user: Victor Stinner date: Thu Feb 12 16:34:54 2015 +0100 summary: Issue #23450: Fix signal.set_wakeup_fd() on Windows Detect integer overflow on the file descriptor of the socket on 64-bit Python. files: Modules/signalmodule.c | 25 ++++++++++++++----------- 1 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -505,7 +505,7 @@ { #ifdef MS_WINDOWS PyObject *fdobj; - SOCKET_T fd, old_fd; + SOCKET_T sockfd, old_sockfd; int res; int res_size = sizeof res; PyObject *mod; @@ -515,8 +515,8 @@ if (!PyArg_ParseTuple(args, "O:set_wakeup_fd", &fdobj)) return NULL; - fd = PyLong_AsSocket_t(fdobj); - if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) + sockfd = PyLong_AsSocket_t(fdobj); + if (sockfd == (SOCKET_T)(-1) && PyErr_Occurred()) return NULL; #else int fd, old_fd; @@ -536,7 +536,7 @@ #ifdef MS_WINDOWS is_socket = 0; - if (fd != INVALID_FD) { + if (sockfd != INVALID_FD) { /* Import the _socket module to call WSAStartup() */ mod = PyImport_ImportModuleNoBlock("_socket"); if (mod == NULL) @@ -544,15 +544,18 @@ Py_DECREF(mod); /* test the socket */ - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&res, &res_size) != 0) { - int err = WSAGetLastError(); + int fd, err; + + err = WSAGetLastError(); if (err != WSAENOTSOCK) { PyErr_SetExcFromWindowsErr(PyExc_OSError, err); return NULL; } - if (!_PyVerify_fd(fd)) { + fd = (int)sockfd; + if ((SOCKET_T)fd != sockfd || !_PyVerify_fd(fd)) { PyErr_SetString(PyExc_ValueError, "invalid fd"); return NULL; } @@ -572,12 +575,12 @@ } } - old_fd = wakeup.fd; - wakeup.fd = fd; + old_sockfd = wakeup.fd; + wakeup.fd = sockfd; wakeup.use_send = is_socket; - if (old_fd != INVALID_FD) - return PyLong_FromSocket_t(old_fd); + if (old_sockfd != INVALID_FD) + return PyLong_FromSocket_t(old_sockfd); else return PyLong_FromLong(-1); #else -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 12 20:13:53 2015 From: python-checkins at python.org (berker.peksag) Date: Thu, 12 Feb 2015 19:13:53 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_PEP_486_by_Paul_Moore=2E?= Message-ID: <20150212191334.43793.86321@psf.io> https://hg.python.org/peps/rev/979e56a2ee51 changeset: 5695:979e56a2ee51 user: Berker Peksag date: Thu Feb 12 21:13:56 2015 +0200 summary: Add PEP 486 by Paul Moore. Also, update Paul's email address. files: pep-0250.txt | 2 +- pep-0302.txt | 2 +- pep-0310.txt | 2 +- pep-0486.txt | 149 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 3 deletions(-) diff --git a/pep-0250.txt b/pep-0250.txt --- a/pep-0250.txt +++ b/pep-0250.txt @@ -2,7 +2,7 @@ Title: Using site-packages on Windows Version: $Revision$ Last-Modified: $Date$ -Author: gustav at morpheus.demon.co.uk (Paul Moore) +Author: p.f.moore at gmail.com (Paul Moore) Status: Final Type: Standards Track Created: 30-Mar-2001 diff --git a/pep-0302.txt b/pep-0302.txt --- a/pep-0302.txt +++ b/pep-0302.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Just van Rossum , - Paul Moore + Paul Moore Status: Final Type: Standards Track Content-Type: text/x-rst diff --git a/pep-0310.txt b/pep-0310.txt --- a/pep-0310.txt +++ b/pep-0310.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Michael Hudson , - Paul Moore + Paul Moore Status: Rejected Type: Standards Track Content-Type: text/plain diff --git a/pep-0486.txt b/pep-0486.txt new file mode 100644 --- /dev/null +++ b/pep-0486.txt @@ -0,0 +1,149 @@ +PEP: 486 +Title: Make the Python Launcher aware of virtual environments +Version: $Revision$ +Last-Modified: $Date$ +Author: Paul Moore +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 12-Feb-2015 +Python-Version: 3.5 +Post-History: + + +Abstract +======== + +The Windows installers for Python include a launcher that locates the +correct Python interpreter to run (see PEP 397). However, the +launcher is not aware of virtual environments (virtualenv [1]_ or PEP +405 based), and so cannot be used to run commands from the active +virtualenv. + +This PEP proposes making the launcher "virtualenv aware". This means +that when run without specifying an explicit Python interpreter to +use, the launcher will use the currently active virtualenv, if any, +before falling back to the configured default Python. + + +Rationale +========= + +Windows users with multiple copies of Python installed need a means of +selecting which one to use. The Python launcher provides this +facility by means of a ``py`` command that can be used to run either a +configured "default" Python or a specific interpreter, by means of +command line arguments. So typical usage would be:: + + # Run the Python interactive interpreter + py + + # Execute an installed module + py -m pip install pytest + py -m pytest + +When using virtual environments, the ``py`` launcher is unaware that a +virtualenv is active, and will continue to use the system Python. So +different command invocations are needed to run the same commands in a +virtualenv:: + + # Run the Python interactive interpreter + python + + # Execute an installed module (these could use python -m, + # which is longer to type but is a little mopre similar to the + # launcher approach) + pip install pytest + py.test + +Having to use different commands is is error-prone, and in many cases +the error is difficult to spot immediately. The PEP proposes making +the ``py`` command usable with virtual environments, so that the first +form of command can be used in all cases. + + +Implementation +============== + +Both ``virtualenv`` and the core ``venv`` module set an environment +variable ``VIRTUAL_ENV`` when activating a virtualenv. This PEP +proposes that the launcher checks for the ``VIRTUAL_ENV`` environment +variable whenever it would run the "default" Python interpreter for +the system (i.e., when no specific version flags such as ``py -2.7`` +are used) and if present, run the Python interpreter for the +virtualenv rather than the default system Python. + +The "default" Python interpreter referred to above is (as per PEP 397) +either the latest version of Python installed on the system, or +a version configured via the ``py.ini`` configuration file. When the +user specifies an explicit Python version on the command line, this +will always be used (as at present). + + +Impact on Script Launching +========================== + +As well as interactive use, the launcher is used as the Windows file +association for Python scripts. In that case, a "shebang" (``#!``) +line at the start of the script is used to identify the interpreter to +run. A fully-qualified path can be used, or a version-specific Python +(``python3`` or ``python2``, or even ``python3.5``), or the generic +``python``, which means to use the default interpreter. + +With the proposed change, scripts that start with ``#!python`` (or one +of its equivalent forms) will be run using an active virtualenv. This +is a change in behaviour, although it will only affect users running +scripts from the command line with a virtualenv activated. + +Under Unix, the ``#!/usr/bin/env python`` shebang line will use the +version of Python found on ``$PATH``, whereas ``#!/usr/bin/python`` +will use the system Python. In order to match Unix behaviour as +closely as possible, it is proposed that the two shebang forms:: + + #!/usr/bin/env python + #!python + +use an active virtualenv, if present, whereas the forms:: + + #!/usr/bin/python + #!/usr/local/bin/python + +use *only* the default system Python, and ignore the ``VIRTUAL_ENV`` +environment variable. + + +Exclusions +========== + +The PEP makes no attempt to promote the use of the launcher for +running Python on Windows. Most existing documentation assumes the +user of ``python`` as the command to run Python, and (for example) +``pip`` to run an installed Python command. This documentation is not +expected to change, and users who choose to manage their ``PATH`` +environment variable can continue to use this form. The focus of this +PEP is purely on allowing users who prefer to use the launcher when +dealing with their system Python installations, to be able to continue +to do so when using virtual environments. + + +References +========== + +.. [1] https://virtualenv.pypa.io/ + + +Copyright +========= + +This document has been placed in the public domain. + + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Feb 12 22:50:22 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 12 Feb 2015 21:50:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio_doc=29?= Message-ID: <20150212215006.29542.47969@psf.io> https://hg.python.org/cpython/rev/b8acfbf5aa61 changeset: 94596:b8acfbf5aa61 parent: 94594:9e10c4255277 parent: 94595:430a2b541709 user: Victor Stinner date: Thu Feb 12 22:49:45 2015 +0100 summary: Merge 3.4 (asyncio doc) files: Doc/library/asyncio-eventloop.rst | 32 +++++++++-------- Doc/library/asyncio-stream.rst | 16 ++++---- Doc/library/asyncio-subprocess.rst | 12 +++--- Doc/library/asyncio-sync.rst | 20 +++++----- Doc/library/asyncio-task.rst | 8 ++- Doc/tools/extensions/pyspecific.py | 26 ++++++++++++++ 6 files changed, 72 insertions(+), 42 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -180,7 +180,7 @@ Creating connections -------------------- -.. method:: BaseEventLoop.create_connection(protocol_factory, host=None, port=None, \*, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None) +.. coroutinemethod:: BaseEventLoop.create_connection(protocol_factory, host=None, port=None, \*, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None) Create a streaming transport connection to a given Internet *host* and *port*: socket family :py:data:`~socket.AF_INET` or @@ -253,7 +253,7 @@ (:class:`StreamReader`, :class:`StreamWriter`) instead of a protocol. -.. method:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) +.. coroutinemethod:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) Create datagram connection: socket family :py:data:`~socket.AF_INET` or :py:data:`~socket.AF_INET6` depending on *host* (or *family* if specified), @@ -271,7 +271,7 @@ :ref:`UDP echo server protocol ` examples. -.. method:: BaseEventLoop.create_unix_connection(protocol_factory, path, \*, ssl=None, sock=None, server_hostname=None) +.. coroutinemethod:: BaseEventLoop.create_unix_connection(protocol_factory, path, \*, ssl=None, sock=None, server_hostname=None) Create UNIX connection: socket family :py:data:`~socket.AF_UNIX`, socket type :py:data:`~socket.SOCK_STREAM`. The :py:data:`~socket.AF_UNIX` socket @@ -290,7 +290,7 @@ Creating listening connections ------------------------------ -.. method:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None) +.. coroutinemethod:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None) Create a TCP server (socket type :data:`~socket.SOCK_STREAM`) bound to *host* and *port*. @@ -336,11 +336,13 @@ :class:`StreamWriter`) pair and calls back a function with this pair. -.. method:: BaseEventLoop.create_unix_server(protocol_factory, path=None, \*, sock=None, backlog=100, ssl=None) +.. coroutinemethod:: BaseEventLoop.create_unix_server(protocol_factory, path=None, \*, sock=None, backlog=100, ssl=None) Similar to :meth:`BaseEventLoop.create_server`, but specific to the socket family :py:data:`~socket.AF_UNIX`. + This method is a :ref:`coroutine `. + Availability: UNIX. @@ -384,7 +386,7 @@ Low-level socket operations --------------------------- -.. method:: BaseEventLoop.sock_recv(sock, nbytes) +.. coroutinemethod:: BaseEventLoop.sock_recv(sock, nbytes) Receive data from the socket. The return value is a bytes object representing the data received. The maximum amount of data to be received @@ -399,7 +401,7 @@ The :meth:`socket.socket.recv` method. -.. method:: BaseEventLoop.sock_sendall(sock, data) +.. coroutinemethod:: BaseEventLoop.sock_sendall(sock, data) Send data to the socket. The socket must be connected to a remote socket. This method continues to send data from *data* until either all data has @@ -416,7 +418,7 @@ The :meth:`socket.socket.sendall` method. -.. method:: BaseEventLoop.sock_connect(sock, address) +.. coroutinemethod:: BaseEventLoop.sock_connect(sock, address) Connect to a remote socket at *address*. @@ -438,7 +440,7 @@ method. -.. method:: BaseEventLoop.sock_accept(sock) +.. coroutinemethod:: BaseEventLoop.sock_accept(sock) Accept a connection. The socket must be bound to an address and listening for connections. The return value is a pair ``(conn, address)`` where *conn* @@ -459,12 +461,12 @@ Resolve host name ----------------- -.. method:: BaseEventLoop.getaddrinfo(host, port, \*, family=0, type=0, proto=0, flags=0) +.. coroutinemethod:: BaseEventLoop.getaddrinfo(host, port, \*, family=0, type=0, proto=0, flags=0) This method is a :ref:`coroutine `, similar to :meth:`socket.getaddrinfo` function but non-blocking. -.. method:: BaseEventLoop.getnameinfo(sockaddr, flags=0) +.. coroutinemethod:: BaseEventLoop.getnameinfo(sockaddr, flags=0) This method is a :ref:`coroutine `, similar to :meth:`socket.getnameinfo` function but non-blocking. @@ -476,7 +478,7 @@ On Windows with :class:`SelectorEventLoop`, these methods are not supported. Use :class:`ProactorEventLoop` to support pipes on Windows. -.. method:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) +.. coroutinemethod:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) Register read pipe in eventloop. @@ -490,7 +492,7 @@ This method is a :ref:`coroutine `. -.. method:: BaseEventLoop.connect_write_pipe(protocol_factory, pipe) +.. coroutinemethod:: BaseEventLoop.connect_write_pipe(protocol_factory, pipe) Register write pipe in eventloop. @@ -543,7 +545,7 @@ pool of processes). By default, an event loop uses a thread pool executor (:class:`~concurrent.futures.ThreadPoolExecutor`). -.. method:: BaseEventLoop.run_in_executor(executor, callback, \*args) +.. coroutinemethod:: BaseEventLoop.run_in_executor(executor, callback, \*args) Arrange for a callback to be called in the specified executor. @@ -654,7 +656,7 @@ The server is closed asynchonously, use the :meth:`wait_closed` coroutine to wait until the server is closed. - .. method:: wait_closed() + .. coroutinemethod:: wait_closed() Wait until the :meth:`close` method completes. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -9,7 +9,7 @@ Stream functions ================ -.. function:: open_connection(host=None, port=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: open_connection(host=None, port=None, \*, loop=None, limit=None, \*\*kwds) A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, writer) pair. @@ -32,7 +32,7 @@ This function is a :ref:`coroutine `. -.. function:: start_server(client_connected_cb, host=None, port=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: start_server(client_connected_cb, host=None, port=None, \*, loop=None, limit=None, \*\*kwds) Start a socket server, with a callback for each client connected. The return value is the same as :meth:`~BaseEventLoop.create_server()`. @@ -56,7 +56,7 @@ This function is a :ref:`coroutine `. -.. function:: open_unix_connection(path=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: open_unix_connection(path=None, \*, loop=None, limit=None, **kwds) A wrapper for :meth:`~BaseEventLoop.create_unix_connection()` returning a (reader, writer) pair. @@ -68,7 +68,7 @@ Availability: UNIX. -.. function:: start_unix_server(client_connected_cb, path=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: start_unix_server(client_connected_cb, path=None, \*, loop=None, limit=None, **kwds) Start a UNIX Domain Socket server, with a callback for each client connected. @@ -106,7 +106,7 @@ Set the transport. - .. method:: read(n=-1) + .. coroutinemethod:: read(n=-1) Read up to *n* bytes. If *n* is not provided, or set to ``-1``, read until EOF and return all read bytes. @@ -116,7 +116,7 @@ This method is a :ref:`coroutine `. - .. method:: readline() + .. coroutinemethod:: readline() Read one line, where "line" is a sequence of bytes ending with ``\n``. @@ -128,7 +128,7 @@ This method is a :ref:`coroutine `. - .. method:: readexactly(n) + .. coroutinemethod:: readexactly(n) Read exactly *n* bytes. Raise an :exc:`IncompleteReadError` if the end of the stream is reached before *n* can be read, the @@ -168,7 +168,7 @@ Close the transport: see :meth:`BaseTransport.close`. - .. method:: drain() + .. coroutinemethod:: drain() Let the write buffer of the underlying transport a chance to be flushed. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -27,7 +27,7 @@ Create a subprocess: high-level API using Process ------------------------------------------------- -.. function:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) +.. coroutinefunction:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) Create a subprocess. @@ -39,7 +39,7 @@ This function is a :ref:`coroutine `. -.. function:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) +.. coroutinefunction:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) Run the shell command *cmd*. @@ -67,7 +67,7 @@ Run subprocesses asynchronously using the :mod:`subprocess` module. -.. method:: BaseEventLoop.subprocess_exec(protocol_factory, \*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) +.. coroutinemethod:: BaseEventLoop.subprocess_exec(protocol_factory, \*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) Create a subprocess from one or more string arguments (character strings or bytes strings encoded to the :ref:`filesystem encoding @@ -116,7 +116,7 @@ See the constructor of the :class:`subprocess.Popen` class for parameters. -.. method:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) +.. coroutinemethod:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) Create a subprocess from *cmd*, which is a character string or a bytes string encoded to the :ref:`filesystem encoding `, @@ -193,7 +193,7 @@ :meth:`~subprocess.Popen.wait` method of the :class:`~subprocess.Popen` class is implemented as a busy loop. - .. method:: wait() + .. coroutinemethod:: wait() Wait for child process to terminate. Set and return :attr:`returncode` attribute. @@ -207,7 +207,7 @@ blocks waiting for the OS pipe buffer to accept more data. Use the :meth:`communicate` method when using pipes to avoid that. - .. method:: communicate(input=None) + .. coroutinemethod:: communicate(input=None) Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -89,7 +89,7 @@ Return ``True`` if the lock is acquired. - .. method:: acquire() + .. coroutinemethod:: acquire() Acquire a lock. @@ -139,7 +139,7 @@ true are awakened. Coroutine that call :meth:`wait` once the flag is true will not block at all. - .. method:: wait() + .. coroutinemethod:: wait() Block until the internal flag is true. @@ -166,7 +166,7 @@ object, and it is used as the underlying lock. Otherwise, a new :class:`Lock` object is created and used as the underlying lock. - .. method:: acquire() + .. coroutinemethod:: acquire() Acquire the underlying lock. @@ -213,7 +213,7 @@ There is no return value. - .. method:: wait() + .. coroutinemethod:: wait() Wait until notified. @@ -227,7 +227,7 @@ This method is a :ref:`coroutine `. - .. method:: wait_for(predicate) + .. coroutinemethod:: wait_for(predicate) Wait until a predicate becomes true. @@ -258,7 +258,7 @@ defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` is raised. - .. method:: acquire() + .. coroutinemethod:: acquire() Acquire a semaphore. @@ -273,7 +273,7 @@ Returns ``True`` if semaphore can not be acquired immediately. - .. method:: release() + .. coroutinemethod:: release() Release a semaphore, incrementing the internal counter by one. When it was zero on entry and another coroutine is waiting for it to become @@ -323,7 +323,7 @@ If the Queue was initialized with ``maxsize=0`` (the default), then :meth:`full()` is never ``True``. - .. method:: get() + .. coroutinemethod:: get() Remove and return an item from the queue. If queue is empty, wait until an item is available. @@ -341,7 +341,7 @@ Return an item if one is immediately available, else raise :exc:`QueueEmpty`. - .. method:: put(item) + .. coroutinemethod:: put(item) Put an item into the queue. If the queue is full, wait until a free slot is available before adding item. @@ -395,7 +395,7 @@ A subclass of :class:`Queue` with :meth:`task_done` and :meth:`join` methods. - .. method:: join() + .. coroutinemethod:: join() Block until all items in the queue have been gotten and processed. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -545,7 +545,7 @@ Return ``True`` if *func* is a decorated :ref:`coroutine function `. -.. function:: sleep(delay, result=None, \*, loop=None) +.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) Create a :ref:`coroutine ` that completes after a given time (in seconds). If *result* is provided, it is produced to the caller @@ -554,6 +554,8 @@ The resolution of the sleep depends on the :ref:`granularity of the event loop `. + This function is a :ref:`coroutine `. + .. function:: shield(arg, \*, loop=None) Wait for a future, shielding it from cancellation. @@ -581,7 +583,7 @@ except CancelledError: res = None -.. function:: wait(futures, \*, loop=None, timeout=None, return_when=ALL_COMPLETED) +.. coroutinefunction:: wait(futures, \*, loop=None, timeout=None, return_when=ALL_COMPLETED) Wait for the Futures and coroutine objects given by the sequence *futures* to complete. Coroutines will be wrapped in Tasks. Returns two sets of @@ -626,7 +628,7 @@ when the timeout occurs are returned in the second set. -.. function:: wait_for(fut, timeout, \*, loop=None) +.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None) Wait for the single :class:`Future` or :ref:`coroutine object ` to complete with timeout. If *timeout* is ``None``, block until the future diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -145,6 +145,30 @@ return PyClassmember.run(self) +class PyCoroutineMixin(object): + def handle_signature(self, sig, signode): + ret = super(PyCoroutineMixin, self).handle_signature(sig, signode) +# signode.insert(0, addnodes.desc_addname('coroutine ', 'coroutine ')) + signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine ')) + return ret + + def needs_arglist(self): + return False + + +class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel): + def run(self): + # a decorator function is a function after all + self.name = 'py:function' + return PyModulelevel.run(self) + + +class PyCoroutineMethod(PyCoroutineMixin, PyClassmember): + def run(self): + self.name = 'py:method' + return PyClassmember.run(self) + + # Support for documenting version of removal in deprecations class DeprecatedRemoved(Directive): @@ -347,5 +371,7 @@ app.add_description_unit('2to3fixer', '2to3fixer', '%s (2to3 fixer)') app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction) app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod) + app.add_directive_to_domain('py', 'coroutinefunction', PyCoroutineFunction) + app.add_directive_to_domain('py', 'coroutinemethod', PyCoroutineMethod) app.add_directive('miscnews', MiscNews) return {'version': '1.0', 'parallel_read_safe': True} -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 12 22:50:22 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 12 Feb 2015 21:50:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_annotate_coroutine_on_coroutine_functions_and_methods?= Message-ID: <20150212215005.37943.78095@psf.io> https://hg.python.org/cpython/rev/430a2b541709 changeset: 94595:430a2b541709 branch: 3.4 parent: 94591:e37b201297d2 user: Victor Stinner date: Thu Feb 12 22:49:18 2015 +0100 summary: asyncio doc: annotate coroutine on coroutine functions and methods files: Doc/library/asyncio-eventloop.rst | 32 +++++++++-------- Doc/library/asyncio-stream.rst | 16 ++++---- Doc/library/asyncio-subprocess.rst | 12 +++--- Doc/library/asyncio-sync.rst | 20 +++++----- Doc/library/asyncio-task.rst | 8 ++- Doc/tools/extensions/pyspecific.py | 26 ++++++++++++++ 6 files changed, 72 insertions(+), 42 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -180,7 +180,7 @@ Creating connections -------------------- -.. method:: BaseEventLoop.create_connection(protocol_factory, host=None, port=None, \*, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None) +.. coroutinemethod:: BaseEventLoop.create_connection(protocol_factory, host=None, port=None, \*, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None) Create a streaming transport connection to a given Internet *host* and *port*: socket family :py:data:`~socket.AF_INET` or @@ -253,7 +253,7 @@ (:class:`StreamReader`, :class:`StreamWriter`) instead of a protocol. -.. method:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) +.. coroutinemethod:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) Create datagram connection: socket family :py:data:`~socket.AF_INET` or :py:data:`~socket.AF_INET6` depending on *host* (or *family* if specified), @@ -271,7 +271,7 @@ :ref:`UDP echo server protocol ` examples. -.. method:: BaseEventLoop.create_unix_connection(protocol_factory, path, \*, ssl=None, sock=None, server_hostname=None) +.. coroutinemethod:: BaseEventLoop.create_unix_connection(protocol_factory, path, \*, ssl=None, sock=None, server_hostname=None) Create UNIX connection: socket family :py:data:`~socket.AF_UNIX`, socket type :py:data:`~socket.SOCK_STREAM`. The :py:data:`~socket.AF_UNIX` socket @@ -290,7 +290,7 @@ Creating listening connections ------------------------------ -.. method:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None) +.. coroutinemethod:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None) Create a TCP server (socket type :data:`~socket.SOCK_STREAM`) bound to *host* and *port*. @@ -336,11 +336,13 @@ :class:`StreamWriter`) pair and calls back a function with this pair. -.. method:: BaseEventLoop.create_unix_server(protocol_factory, path=None, \*, sock=None, backlog=100, ssl=None) +.. coroutinemethod:: BaseEventLoop.create_unix_server(protocol_factory, path=None, \*, sock=None, backlog=100, ssl=None) Similar to :meth:`BaseEventLoop.create_server`, but specific to the socket family :py:data:`~socket.AF_UNIX`. + This method is a :ref:`coroutine `. + Availability: UNIX. @@ -384,7 +386,7 @@ Low-level socket operations --------------------------- -.. method:: BaseEventLoop.sock_recv(sock, nbytes) +.. coroutinemethod:: BaseEventLoop.sock_recv(sock, nbytes) Receive data from the socket. The return value is a bytes object representing the data received. The maximum amount of data to be received @@ -399,7 +401,7 @@ The :meth:`socket.socket.recv` method. -.. method:: BaseEventLoop.sock_sendall(sock, data) +.. coroutinemethod:: BaseEventLoop.sock_sendall(sock, data) Send data to the socket. The socket must be connected to a remote socket. This method continues to send data from *data* until either all data has @@ -416,7 +418,7 @@ The :meth:`socket.socket.sendall` method. -.. method:: BaseEventLoop.sock_connect(sock, address) +.. coroutinemethod:: BaseEventLoop.sock_connect(sock, address) Connect to a remote socket at *address*. @@ -438,7 +440,7 @@ method. -.. method:: BaseEventLoop.sock_accept(sock) +.. coroutinemethod:: BaseEventLoop.sock_accept(sock) Accept a connection. The socket must be bound to an address and listening for connections. The return value is a pair ``(conn, address)`` where *conn* @@ -459,12 +461,12 @@ Resolve host name ----------------- -.. method:: BaseEventLoop.getaddrinfo(host, port, \*, family=0, type=0, proto=0, flags=0) +.. coroutinemethod:: BaseEventLoop.getaddrinfo(host, port, \*, family=0, type=0, proto=0, flags=0) This method is a :ref:`coroutine `, similar to :meth:`socket.getaddrinfo` function but non-blocking. -.. method:: BaseEventLoop.getnameinfo(sockaddr, flags=0) +.. coroutinemethod:: BaseEventLoop.getnameinfo(sockaddr, flags=0) This method is a :ref:`coroutine `, similar to :meth:`socket.getnameinfo` function but non-blocking. @@ -476,7 +478,7 @@ On Windows with :class:`SelectorEventLoop`, these methods are not supported. Use :class:`ProactorEventLoop` to support pipes on Windows. -.. method:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) +.. coroutinemethod:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) Register read pipe in eventloop. @@ -490,7 +492,7 @@ This method is a :ref:`coroutine `. -.. method:: BaseEventLoop.connect_write_pipe(protocol_factory, pipe) +.. coroutinemethod:: BaseEventLoop.connect_write_pipe(protocol_factory, pipe) Register write pipe in eventloop. @@ -543,7 +545,7 @@ pool of processes). By default, an event loop uses a thread pool executor (:class:`~concurrent.futures.ThreadPoolExecutor`). -.. method:: BaseEventLoop.run_in_executor(executor, callback, \*args) +.. coroutinemethod:: BaseEventLoop.run_in_executor(executor, callback, \*args) Arrange for a callback to be called in the specified executor. @@ -654,7 +656,7 @@ The server is closed asynchonously, use the :meth:`wait_closed` coroutine to wait until the server is closed. - .. method:: wait_closed() + .. coroutinemethod:: wait_closed() Wait until the :meth:`close` method completes. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -9,7 +9,7 @@ Stream functions ================ -.. function:: open_connection(host=None, port=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: open_connection(host=None, port=None, \*, loop=None, limit=None, \*\*kwds) A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, writer) pair. @@ -32,7 +32,7 @@ This function is a :ref:`coroutine `. -.. function:: start_server(client_connected_cb, host=None, port=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: start_server(client_connected_cb, host=None, port=None, \*, loop=None, limit=None, \*\*kwds) Start a socket server, with a callback for each client connected. The return value is the same as :meth:`~BaseEventLoop.create_server()`. @@ -56,7 +56,7 @@ This function is a :ref:`coroutine `. -.. function:: open_unix_connection(path=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: open_unix_connection(path=None, \*, loop=None, limit=None, **kwds) A wrapper for :meth:`~BaseEventLoop.create_unix_connection()` returning a (reader, writer) pair. @@ -68,7 +68,7 @@ Availability: UNIX. -.. function:: start_unix_server(client_connected_cb, path=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: start_unix_server(client_connected_cb, path=None, \*, loop=None, limit=None, **kwds) Start a UNIX Domain Socket server, with a callback for each client connected. @@ -106,7 +106,7 @@ Set the transport. - .. method:: read(n=-1) + .. coroutinemethod:: read(n=-1) Read up to *n* bytes. If *n* is not provided, or set to ``-1``, read until EOF and return all read bytes. @@ -116,7 +116,7 @@ This method is a :ref:`coroutine `. - .. method:: readline() + .. coroutinemethod:: readline() Read one line, where "line" is a sequence of bytes ending with ``\n``. @@ -128,7 +128,7 @@ This method is a :ref:`coroutine `. - .. method:: readexactly(n) + .. coroutinemethod:: readexactly(n) Read exactly *n* bytes. Raise an :exc:`IncompleteReadError` if the end of the stream is reached before *n* can be read, the @@ -168,7 +168,7 @@ Close the transport: see :meth:`BaseTransport.close`. - .. method:: drain() + .. coroutinemethod:: drain() Let the write buffer of the underlying transport a chance to be flushed. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -27,7 +27,7 @@ Create a subprocess: high-level API using Process ------------------------------------------------- -.. function:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) +.. coroutinefunction:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) Create a subprocess. @@ -39,7 +39,7 @@ This function is a :ref:`coroutine `. -.. function:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) +.. coroutinefunction:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) Run the shell command *cmd*. @@ -67,7 +67,7 @@ Run subprocesses asynchronously using the :mod:`subprocess` module. -.. method:: BaseEventLoop.subprocess_exec(protocol_factory, \*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) +.. coroutinemethod:: BaseEventLoop.subprocess_exec(protocol_factory, \*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) Create a subprocess from one or more string arguments (character strings or bytes strings encoded to the :ref:`filesystem encoding @@ -116,7 +116,7 @@ See the constructor of the :class:`subprocess.Popen` class for parameters. -.. method:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) +.. coroutinemethod:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) Create a subprocess from *cmd*, which is a character string or a bytes string encoded to the :ref:`filesystem encoding `, @@ -193,7 +193,7 @@ :meth:`~subprocess.Popen.wait` method of the :class:`~subprocess.Popen` class is implemented as a busy loop. - .. method:: wait() + .. coroutinemethod:: wait() Wait for child process to terminate. Set and return :attr:`returncode` attribute. @@ -207,7 +207,7 @@ blocks waiting for the OS pipe buffer to accept more data. Use the :meth:`communicate` method when using pipes to avoid that. - .. method:: communicate(input=None) + .. coroutinemethod:: communicate(input=None) Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -89,7 +89,7 @@ Return ``True`` if the lock is acquired. - .. method:: acquire() + .. coroutinemethod:: acquire() Acquire a lock. @@ -139,7 +139,7 @@ true are awakened. Coroutine that call :meth:`wait` once the flag is true will not block at all. - .. method:: wait() + .. coroutinemethod:: wait() Block until the internal flag is true. @@ -166,7 +166,7 @@ object, and it is used as the underlying lock. Otherwise, a new :class:`Lock` object is created and used as the underlying lock. - .. method:: acquire() + .. coroutinemethod:: acquire() Acquire the underlying lock. @@ -213,7 +213,7 @@ There is no return value. - .. method:: wait() + .. coroutinemethod:: wait() Wait until notified. @@ -227,7 +227,7 @@ This method is a :ref:`coroutine `. - .. method:: wait_for(predicate) + .. coroutinemethod:: wait_for(predicate) Wait until a predicate becomes true. @@ -258,7 +258,7 @@ defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` is raised. - .. method:: acquire() + .. coroutinemethod:: acquire() Acquire a semaphore. @@ -273,7 +273,7 @@ Returns ``True`` if semaphore can not be acquired immediately. - .. method:: release() + .. coroutinemethod:: release() Release a semaphore, incrementing the internal counter by one. When it was zero on entry and another coroutine is waiting for it to become @@ -323,7 +323,7 @@ If the Queue was initialized with ``maxsize=0`` (the default), then :meth:`full()` is never ``True``. - .. method:: get() + .. coroutinemethod:: get() Remove and return an item from the queue. If queue is empty, wait until an item is available. @@ -341,7 +341,7 @@ Return an item if one is immediately available, else raise :exc:`QueueEmpty`. - .. method:: put(item) + .. coroutinemethod:: put(item) Put an item into the queue. If the queue is full, wait until a free slot is available before adding item. @@ -395,7 +395,7 @@ A subclass of :class:`Queue` with :meth:`task_done` and :meth:`join` methods. - .. method:: join() + .. coroutinemethod:: join() Block until all items in the queue have been gotten and processed. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -545,7 +545,7 @@ Return ``True`` if *func* is a decorated :ref:`coroutine function `. -.. function:: sleep(delay, result=None, \*, loop=None) +.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) Create a :ref:`coroutine ` that completes after a given time (in seconds). If *result* is provided, it is produced to the caller @@ -554,6 +554,8 @@ The resolution of the sleep depends on the :ref:`granularity of the event loop `. + This function is a :ref:`coroutine `. + .. function:: shield(arg, \*, loop=None) Wait for a future, shielding it from cancellation. @@ -581,7 +583,7 @@ except CancelledError: res = None -.. function:: wait(futures, \*, loop=None, timeout=None, return_when=ALL_COMPLETED) +.. coroutinefunction:: wait(futures, \*, loop=None, timeout=None, return_when=ALL_COMPLETED) Wait for the Futures and coroutine objects given by the sequence *futures* to complete. Coroutines will be wrapped in Tasks. Returns two sets of @@ -626,7 +628,7 @@ when the timeout occurs are returned in the second set. -.. function:: wait_for(fut, timeout, \*, loop=None) +.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None) Wait for the single :class:`Future` or :ref:`coroutine object ` to complete with timeout. If *timeout* is ``None``, block until the future diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -145,6 +145,30 @@ return PyClassmember.run(self) +class PyCoroutineMixin(object): + def handle_signature(self, sig, signode): + ret = super(PyCoroutineMixin, self).handle_signature(sig, signode) +# signode.insert(0, addnodes.desc_addname('coroutine ', 'coroutine ')) + signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine ')) + return ret + + def needs_arglist(self): + return False + + +class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel): + def run(self): + # a decorator function is a function after all + self.name = 'py:function' + return PyModulelevel.run(self) + + +class PyCoroutineMethod(PyCoroutineMixin, PyClassmember): + def run(self): + self.name = 'py:method' + return PyClassmember.run(self) + + # Support for documenting version of removal in deprecations class DeprecatedRemoved(Directive): @@ -347,5 +371,7 @@ app.add_description_unit('2to3fixer', '2to3fixer', '%s (2to3 fixer)') app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction) app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod) + app.add_directive_to_domain('py', 'coroutinefunction', PyCoroutineFunction) + app.add_directive_to_domain('py', 'coroutinemethod', PyCoroutineMethod) app.add_directive('miscnews', MiscNews) return {'version': '1.0', 'parallel_read_safe': True} -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Fri Feb 13 08:39:00 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 13 Feb 2015 08:39:00 +0100 Subject: [Python-checkins] Daily reference leaks (b8acfbf5aa61): sum=949 Message-ID: results for b8acfbf5aa61 on branch "default" -------------------------------------------- test_asyncio leaked [388, 388, 388] references, sum=1164 test_asyncio leaked [84, 85, 85] memory blocks, sum=254 test_functools leaked [0, 0, 3] memory blocks, sum=3 test_gc leaked [0, 0, -388] references, sum=-388 test_gc leaked [0, 0, -84] memory blocks, sum=-84 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogRzteff', '-x'] From python-checkins at python.org Fri Feb 13 11:13:30 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 13 Feb 2015 10:13:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxODQw?= =?utf-8?q?=3A_Fixed_expanding_unicode_variables_of_form_=24var_in?= Message-ID: <20150213101327.43787.9198@psf.io> https://hg.python.org/cpython/rev/8e2388b1e875 changeset: 94597:8e2388b1e875 branch: 2.7 parent: 94535:e55f955659bc user: Serhiy Storchaka date: Fri Feb 13 12:02:05 2015 +0200 summary: Issue #21840: Fixed expanding unicode variables of form $var in posixpath.expandvars(). Fixed all os.path implementations on unicode-disabled builds. files: Lib/genericpath.py | 8 ++++++++ Lib/macpath.py | 3 ++- Lib/ntpath.py | 9 +++++---- Lib/os2emxpath.py | 3 ++- Lib/posixpath.py | 21 +++++++-------------- Lib/test/test_genericpath.py | 2 ++ Lib/test/test_macpath.py | 1 + Lib/test/test_ntpath.py | 5 +++-- Lib/test/test_posixpath.py | 19 ++++++++++++++++++- Misc/NEWS | 4 ++++ 10 files changed, 52 insertions(+), 23 deletions(-) diff --git a/Lib/genericpath.py b/Lib/genericpath.py --- a/Lib/genericpath.py +++ b/Lib/genericpath.py @@ -10,6 +10,14 @@ 'getsize', 'isdir', 'isfile'] +try: + _unicode = unicode +except NameError: + # If Python is built without Unicode support, the unicode type + # will not exist. Fake one. + class _unicode(object): + pass + # Does a path exist? # This is false for dangling symbolic links on systems that support them. def exists(path): diff --git a/Lib/macpath.py b/Lib/macpath.py --- a/Lib/macpath.py +++ b/Lib/macpath.py @@ -5,6 +5,7 @@ from stat import * import genericpath from genericpath import * +from genericpath import _unicode __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", @@ -186,7 +187,7 @@ def abspath(path): """Return an absolute path.""" if not isabs(path): - if isinstance(path, unicode): + if isinstance(path, _unicode): cwd = os.getcwdu() else: cwd = os.getcwd() diff --git a/Lib/ntpath.py b/Lib/ntpath.py --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -12,6 +12,7 @@ import warnings from genericpath import * +from genericpath import _unicode __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", @@ -331,7 +332,7 @@ return path import string varchars = string.ascii_letters + string.digits + '_-' - if isinstance(path, unicode): + if isinstance(path, _unicode): encoding = sys.getfilesystemencoding() def getenv(var): return os.environ[var.encode(encoding)].decode(encoding) @@ -414,7 +415,7 @@ def normpath(path): """Normalize path, eliminating double slashes, etc.""" # Preserve unicode (if path is unicode) - backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.') + backslash, dot = (u'\\', u'.') if isinstance(path, _unicode) else ('\\', '.') if path.startswith(('\\\\.\\', '\\\\?\\')): # in the case of paths with these prefixes: # \\.\ -> device names @@ -471,7 +472,7 @@ def abspath(path): """Return the absolute version of a path.""" if not isabs(path): - if isinstance(path, unicode): + if isinstance(path, _unicode): cwd = os.getcwdu() else: cwd = os.getcwd() @@ -487,7 +488,7 @@ path = _getfullpathname(path) except WindowsError: pass # Bad path - return unchanged. - elif isinstance(path, unicode): + elif isinstance(path, _unicode): path = os.getcwdu() else: path = os.getcwd() diff --git a/Lib/os2emxpath.py b/Lib/os2emxpath.py --- a/Lib/os2emxpath.py +++ b/Lib/os2emxpath.py @@ -8,6 +8,7 @@ import os import stat from genericpath import * +from genericpath import _unicode from ntpath import (expanduser, expandvars, isabs, islink, splitdrive, splitext, split, walk) @@ -146,7 +147,7 @@ def abspath(path): """Return the absolute version of a path""" if not isabs(path): - if isinstance(path, unicode): + if isinstance(path, _unicode): cwd = os.getcwdu() else: cwd = os.getcwd() diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -16,14 +16,7 @@ import genericpath import warnings from genericpath import * - -try: - _unicode = unicode -except NameError: - # If Python is built without Unicode support, the unicode type - # will not exist. Fake one. - class _unicode(object): - pass +from genericpath import _unicode __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", @@ -294,16 +287,16 @@ if '$' not in path: return path if isinstance(path, _unicode): + if not _uvarprog: + import re + _uvarprog = re.compile(ur'\$(\w+|\{[^}]*\})', re.UNICODE) + varprog = _uvarprog + encoding = sys.getfilesystemencoding() + else: if not _varprog: import re _varprog = re.compile(r'\$(\w+|\{[^}]*\})') varprog = _varprog - encoding = sys.getfilesystemencoding() - else: - if not _uvarprog: - import re - _uvarprog = re.compile(_unicode(r'\$(\w+|\{[^}]*\})'), re.UNICODE) - varprog = _uvarprog encoding = None i = 0 while True: diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -243,11 +243,13 @@ def test_realpath(self): self.assertIn("foo", self.pathmodule.realpath("foo")) + @test_support.requires_unicode def test_normpath_issue5827(self): # Make sure normpath preserves unicode for path in (u'', u'.', u'/', u'\\', u'///foo/.//bar//'): self.assertIsInstance(self.pathmodule.normpath(path), unicode) + @test_support.requires_unicode def test_abspath_issue3426(self): # Check that abspath returns unicode when the arg is unicode # with both ASCII and non-ASCII cwds. diff --git a/Lib/test/test_macpath.py b/Lib/test/test_macpath.py --- a/Lib/test/test_macpath.py +++ b/Lib/test/test_macpath.py @@ -59,6 +59,7 @@ self.assertEqual(splitext(""), ('', '')) self.assertEqual(splitext("foo.bar.ext"), ('foo.bar', '.ext')) + @test_support.requires_unicode def test_normpath(self): # Issue 5827: Make sure normpath preserves unicode for path in (u'', u'.', u'/', u'\\', u':', u'///foo/.//bar//'): diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -69,8 +69,9 @@ ('', '\\\\conky\\\\mountpoint\\foo\\bar')) tester('ntpath.splitunc("//conky//mountpoint/foo/bar")', ('', '//conky//mountpoint/foo/bar')) - self.assertEqual(ntpath.splitunc(u'//conky/MOUNTPO\u0130NT/foo/bar'), - (u'//conky/MOUNTPO\u0130NT', u'/foo/bar')) + if test_support.have_unicode: + self.assertEqual(ntpath.splitunc(u'//conky/MOUNTPO%cNT/foo/bar' % 0x0130), + (u'//conky/MOUNTPO%cNT' % 0x0130, u'/foo/bar')) def test_split(self): tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar')) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -1,7 +1,9 @@ import unittest from test import test_support, test_genericpath -import posixpath, os +import posixpath +import os +import sys from posixpath import realpath, abspath, dirname, basename # An absolute path to a temporary filename for testing. We can't rely on TESTFN @@ -409,6 +411,21 @@ finally: os.getcwd = real_getcwd + @test_support.requires_unicode + def test_expandvars_nonascii_word(self): + encoding = sys.getfilesystemencoding() + # Non-ASCII word characters + letters = test_support.u(r'\xe6\u0130\u0141\u03c6\u041a\u05d0\u062a\u0e01') + uwnonascii = letters.encode(encoding, 'ignore').decode(encoding)[:3] + swnonascii = uwnonascii.encode(encoding) + if not swnonascii: + self.skip('Needs non-ASCII word characters') + with test_support.EnvironmentVarGuard() as env: + env.clear() + env[swnonascii] = 'baz' + swnonascii + self.assertEqual(posixpath.expandvars(u'$%s bar' % uwnonascii), + u'baz%s bar' % uwnonascii) + class PosixCommonTest(test_genericpath.CommonTest): pathmodule = posixpath diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,10 @@ Library ------- +- Issue #21840: Fixed expanding unicode variables of form $var in + posixpath.expandvars(). Fixed all os.path implementations on + unicode-disabled builds. + - Issue #23363: Fix possible overflow in itertools.permutations. - Issue #23364: Fix possible overflow in itertools.product. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 13 11:47:52 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 13 Feb 2015 10:47:52 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxODQw?= =?utf-8?q?=3A_Fixed_a_typo=2E?= Message-ID: <20150213104747.29536.51211@psf.io> https://hg.python.org/cpython/rev/544c5d4f4084 changeset: 94598:544c5d4f4084 branch: 2.7 user: Serhiy Storchaka date: Fri Feb 13 12:47:08 2015 +0200 summary: Issue #21840: Fixed a typo. files: Lib/test/test_posixpath.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -419,7 +419,7 @@ uwnonascii = letters.encode(encoding, 'ignore').decode(encoding)[:3] swnonascii = uwnonascii.encode(encoding) if not swnonascii: - self.skip('Needs non-ASCII word characters') + self.skipTest('Needs non-ASCII word characters') with test_support.EnvironmentVarGuard() as env: env.clear() env[swnonascii] = 'baz' + swnonascii -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 13 14:21:13 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 13 Feb 2015 13:21:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIxODQ5?= =?utf-8?q?=3A_Ported_from_2=2E7_tests_for_non-ASCII_data=2E?= Message-ID: <20150213132047.29542.22621@psf.io> https://hg.python.org/cpython/rev/908533d5a427 changeset: 94600:908533d5a427 branch: 3.4 parent: 94595:430a2b541709 user: Serhiy Storchaka date: Fri Feb 13 15:13:33 2015 +0200 summary: Issue #21849: Ported from 2.7 tests for non-ASCII data. files: Lib/test/_test_multiprocessing.py | 20 ++++++++++++------ 1 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -2020,6 +2020,12 @@ class _TestRemoteManager(BaseTestCase): ALLOWED_TYPES = ('manager',) + values = ['hello world', None, True, 2.25, + 'hall\xe5 v\xe4rlden', + '\u043f\u0440\u0438\u0432\u0456\u0442 \u0441\u0432\u0456\u0442', + b'hall\xe5 v\xe4rlden', + ] + result = values[:] @classmethod def _putter(cls, address, authkey): @@ -2028,7 +2034,8 @@ ) manager.connect() queue = manager.get_queue() - queue.put(('hello world', None, True, 2.25)) + # Note that xmlrpclib will deserialize object as a list not a tuple + queue.put(tuple(cls.values)) def test_remote(self): authkey = os.urandom(32) @@ -2048,8 +2055,7 @@ manager2.connect() queue = manager2.get_queue() - # Note that xmlrpclib will deserialize object as a list not a tuple - self.assertEqual(queue.get(), ['hello world', None, True, 2.25]) + self.assertEqual(queue.get(), self.result) # Because we are using xmlrpclib for serialization instead of # pickle this will cause a serialization error. @@ -3405,12 +3411,12 @@ name = os.path.join(os.path.dirname(__file__), 'mp_fork_bomb.py') if sm != 'fork': rc, out, err = test.script_helper.assert_python_failure(name, sm) - self.assertEqual('', out.decode('ascii')) - self.assertIn('RuntimeError', err.decode('ascii')) + self.assertEqual(out, b'') + self.assertIn(b'RuntimeError', err) else: rc, out, err = test.script_helper.assert_python_ok(name, sm) - self.assertEqual('123', out.decode('ascii').rstrip()) - self.assertEqual('', err.decode('ascii')) + self.assertEqual(out.rstrip(), b'123') + self.assertEqual(err, b'') # # Issue #17555: ForkAwareThreadLock -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 13 14:21:13 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 13 Feb 2015 13:21:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2321849=3A_Ported_from_2=2E7_tests_for_non-ASCII_?= =?utf-8?q?data=2E?= Message-ID: <20150213132047.11120.73721@psf.io> https://hg.python.org/cpython/rev/1784c1901af6 changeset: 94601:1784c1901af6 parent: 94596:b8acfbf5aa61 parent: 94600:908533d5a427 user: Serhiy Storchaka date: Fri Feb 13 15:19:08 2015 +0200 summary: Issue #21849: Ported from 2.7 tests for non-ASCII data. files: Lib/test/_test_multiprocessing.py | 20 ++++++++++++------ 1 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -2020,6 +2020,12 @@ class _TestRemoteManager(BaseTestCase): ALLOWED_TYPES = ('manager',) + values = ['hello world', None, True, 2.25, + 'hall\xe5 v\xe4rlden', + '\u043f\u0440\u0438\u0432\u0456\u0442 \u0441\u0432\u0456\u0442', + b'hall\xe5 v\xe4rlden', + ] + result = values[:] @classmethod def _putter(cls, address, authkey): @@ -2028,7 +2034,8 @@ ) manager.connect() queue = manager.get_queue() - queue.put(('hello world', None, True, 2.25)) + # Note that xmlrpclib will deserialize object as a list not a tuple + queue.put(tuple(cls.values)) def test_remote(self): authkey = os.urandom(32) @@ -2048,8 +2055,7 @@ manager2.connect() queue = manager2.get_queue() - # Note that xmlrpclib will deserialize object as a list not a tuple - self.assertEqual(queue.get(), ['hello world', None, True, 2.25]) + self.assertEqual(queue.get(), self.result) # Because we are using xmlrpclib for serialization instead of # pickle this will cause a serialization error. @@ -3405,12 +3411,12 @@ name = os.path.join(os.path.dirname(__file__), 'mp_fork_bomb.py') if sm != 'fork': rc, out, err = test.script_helper.assert_python_failure(name, sm) - self.assertEqual('', out.decode('ascii')) - self.assertIn('RuntimeError', err.decode('ascii')) + self.assertEqual(out, b'') + self.assertIn(b'RuntimeError', err) else: rc, out, err = test.script_helper.assert_python_ok(name, sm) - self.assertEqual('123', out.decode('ascii').rstrip()) - self.assertEqual('', err.decode('ascii')) + self.assertEqual(out.rstrip(), b'123') + self.assertEqual(err, b'') # # Issue #17555: ForkAwareThreadLock -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 13 14:21:13 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 13 Feb 2015 13:21:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxODQ5?= =?utf-8?q?=3A_Fixed_xmlrpclib_serialization_of_non-ASCII_unicode_strings_?= =?utf-8?q?in?= Message-ID: <20150213132047.43797.99043@psf.io> https://hg.python.org/cpython/rev/a4a3a8b3f37f changeset: 94599:a4a3a8b3f37f branch: 2.7 user: Serhiy Storchaka date: Fri Feb 13 15:08:36 2015 +0200 summary: Issue #21849: Fixed xmlrpclib serialization of non-ASCII unicode strings in the multiprocessing module. files: Lib/multiprocessing/connection.py | 4 +- Lib/multiprocessing/sharedctypes.py | 7 ++++- Lib/test/test_multiprocessing.py | 25 ++++++++++++---- Misc/NEWS | 3 ++ 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -454,10 +454,10 @@ return self._loads(s) def _xml_dumps(obj): - return xmlrpclib.dumps((obj,), None, None, None, 1).encode('utf8') + return xmlrpclib.dumps((obj,), None, None, None, 1) def _xml_loads(s): - (obj,), method = xmlrpclib.loads(s.decode('utf8')) + (obj,), method = xmlrpclib.loads(s) return obj class XmlListener(Listener): diff --git a/Lib/multiprocessing/sharedctypes.py b/Lib/multiprocessing/sharedctypes.py --- a/Lib/multiprocessing/sharedctypes.py +++ b/Lib/multiprocessing/sharedctypes.py @@ -46,13 +46,18 @@ # typecode_to_type = { - 'c': ctypes.c_char, 'u': ctypes.c_wchar, + 'c': ctypes.c_char, 'b': ctypes.c_byte, 'B': ctypes.c_ubyte, 'h': ctypes.c_short, 'H': ctypes.c_ushort, 'i': ctypes.c_int, 'I': ctypes.c_uint, 'l': ctypes.c_long, 'L': ctypes.c_ulong, 'f': ctypes.c_float, 'd': ctypes.c_double } +try: + typecode_to_type['u'] = ctypes.c_wchar +except AttributeError: + pass + # # diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1371,6 +1371,16 @@ class _TestRemoteManager(BaseTestCase): ALLOWED_TYPES = ('manager',) + values = ['hello world', None, True, 2.25, + #'hall\xc3\xa5 v\xc3\xa4rlden'] # UTF-8 + ] + result = values[:] + if test_support.have_unicode: + #result[-1] = u'hall\xe5 v\xe4rlden' + uvalue = test_support.u(r'\u043f\u0440\u0438\u0432\u0456\u0442 ' + r'\u0441\u0432\u0456\u0442') + values.append(uvalue) + result.append(uvalue) @classmethod def _putter(cls, address, authkey): @@ -1379,7 +1389,8 @@ ) manager.connect() queue = manager.get_queue() - queue.put(('hello world', None, True, 2.25)) + # Note that xmlrpclib will deserialize object as a list not a tuple + queue.put(tuple(cls.values)) def test_remote(self): authkey = os.urandom(32) @@ -1399,8 +1410,7 @@ manager2.connect() queue = manager2.get_queue() - # Note that xmlrpclib will deserialize object as a list not a tuple - self.assertEqual(queue.get(), ['hello world', None, True, 2.25]) + self.assertEqual(queue.get(), self.result) # Because we are using xmlrpclib for serialization instead of # pickle this will cause a serialization error. @@ -2392,12 +2402,12 @@ name = os.path.join(os.path.dirname(__file__), 'mp_fork_bomb.py') if WIN32: rc, out, err = test.script_helper.assert_python_failure(name) - self.assertEqual('', out.decode('ascii')) - self.assertIn('RuntimeError', err.decode('ascii')) + self.assertEqual(out, '') + self.assertIn('RuntimeError', err) else: rc, out, err = test.script_helper.assert_python_ok(name) - self.assertEqual('123', out.decode('ascii').rstrip()) - self.assertEqual('', err.decode('ascii')) + self.assertEqual(out.rstrip(), '123') + self.assertEqual(err, '') # # Issue 12098: check sys.flags of child matches that for parent @@ -2421,6 +2431,7 @@ flags = (tuple(sys.flags), grandchild_flags) print(json.dumps(flags)) + @test_support.requires_unicode # XXX json needs unicode support def test_flags(self): import json, subprocess # start child process using unusual flags diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #21849: Fixed xmlrpclib serialization of non-ASCII unicode strings in + the multiprocessing module. + - Issue #21840: Fixed expanding unicode variables of form $var in posixpath.expandvars(). Fixed all os.path implementations on unicode-disabled builds. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 13 19:48:27 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 13 Feb 2015 18:48:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323418=3A_Add_missing_entries_to_http=2Eserver?= =?utf-8?b?Ll9fYWxsX18u?= Message-ID: <20150213184817.37945.653@psf.io> https://hg.python.org/cpython/rev/03e3e78014ea changeset: 94603:03e3e78014ea parent: 94601:1784c1901af6 parent: 94602:d2dbec7d74d0 user: Berker Peksag date: Fri Feb 13 20:48:41 2015 +0200 summary: Issue #23418: Add missing entries to http.server.__all__. Patch by Martin Panter. files: Lib/http/server.py | 5 ++++- Lib/test/test_httpservers.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -82,7 +82,10 @@ __version__ = "0.6" -__all__ = ["HTTPServer", "BaseHTTPRequestHandler"] +__all__ = [ + "HTTPServer", "BaseHTTPRequestHandler", + "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler", +] import html import http.client diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -760,6 +760,19 @@ self.assertEqual(path, self.translated) +class MiscTestCase(unittest.TestCase): + def test_all(self): + expected = [] + blacklist = {'executable', 'nobody_uid', 'test'} + for name in dir(server): + if name.startswith('_') or name in blacklist: + continue + module_object = getattr(server, name) + if getattr(module_object, '__module__', None) == 'http.server': + expected.append(name) + self.assertCountEqual(server.__all__, expected) + + def test_main(verbose=None): cwd = os.getcwd() try: @@ -769,6 +782,7 @@ SimpleHTTPServerTestCase, CGIHTTPServerTestCase, SimpleHTTPRequestHandlerTestCase, + MiscTestCase, ) finally: os.chdir(cwd) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 13 19:48:27 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 13 Feb 2015 18:48:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDE4?= =?utf-8?b?OiBBZGQgbWlzc2luZyBlbnRyaWVzIHRvIGh0dHAuc2VydmVyLl9fYWxsX18u?= Message-ID: <20150213184816.29522.86570@psf.io> https://hg.python.org/cpython/rev/d2dbec7d74d0 changeset: 94602:d2dbec7d74d0 branch: 3.4 parent: 94600:908533d5a427 user: Berker Peksag date: Fri Feb 13 20:48:15 2015 +0200 summary: Issue #23418: Add missing entries to http.server.__all__. Patch by Martin Panter. files: Lib/http/server.py | 5 ++++- Lib/test/test_httpservers.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -82,7 +82,10 @@ __version__ = "0.6" -__all__ = ["HTTPServer", "BaseHTTPRequestHandler"] +__all__ = [ + "HTTPServer", "BaseHTTPRequestHandler", + "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler", +] import html import http.client diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -760,6 +760,19 @@ self.assertEqual(path, self.translated) +class MiscTestCase(unittest.TestCase): + def test_all(self): + expected = [] + blacklist = {'executable', 'nobody_uid', 'test'} + for name in dir(server): + if name.startswith('_') or name in blacklist: + continue + module_object = getattr(server, name) + if getattr(module_object, '__module__', None) == 'http.server': + expected.append(name) + self.assertCountEqual(server.__all__, expected) + + def test_main(verbose=None): cwd = os.getcwd() try: @@ -769,6 +782,7 @@ SimpleHTTPServerTestCase, CGIHTTPServerTestCase, SimpleHTTPRequestHandlerTestCase, + MiscTestCase, ) finally: os.chdir(cwd) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 13 20:01:54 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 13 Feb 2015 19:01:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2321717=3A_tarfile?= =?utf-8?q?=2Eopen=28=29_now_supports_=27x=27_=28exclusive_creation=29_mod?= =?utf-8?q?e=2E?= Message-ID: <20150213190148.31040.75159@psf.io> https://hg.python.org/cpython/rev/ed9e9e6b3c1e changeset: 94604:ed9e9e6b3c1e user: Berker Peksag date: Fri Feb 13 21:02:12 2015 +0200 summary: Issue #21717: tarfile.open() now supports 'x' (exclusive creation) mode. files: Doc/library/tarfile.rst | 37 +++++++++-- Doc/whatsnew/3.5.rst | 6 ++ Lib/tarfile.py | 37 +++++++---- Lib/test/test_tarfile.py | 82 ++++++++++++++++++++++++++++ Misc/NEWS | 2 + 5 files changed, 142 insertions(+), 22 deletions(-) diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -62,6 +62,23 @@ +------------------+---------------------------------------------+ | ``'r:xz'`` | Open for reading with lzma compression. | +------------------+---------------------------------------------+ + | ``'x'`` or | Create a tarfile exclusively without | + | ``'x:'`` | compression. | + | | Raise an :exc:`FileExistsError` exception | + | | if it is already exists. | + +------------------+---------------------------------------------+ + | ``'x:gz'`` | Create a tarfile with gzip compression. | + | | Raise an :exc:`FileExistsError` exception | + | | if it is already exists. | + +------------------+---------------------------------------------+ + | ``'x:bz2'`` | Create a tarfile with bzip2 compression. | + | | Raise an :exc:`FileExistsError` exception | + | | if it is already exists. | + +------------------+---------------------------------------------+ + | ``'x:xz'`` | Create a tarfile with lzma compression. | + | | Raise an :exc:`FileExistsError` exception | + | | if it is already exists. | + +------------------+---------------------------------------------+ | ``'a' or 'a:'`` | Open for appending with no compression. The | | | file is created if it does not exist. | +------------------+---------------------------------------------+ @@ -82,9 +99,9 @@ If *fileobj* is specified, it is used as an alternative to a :term:`file object` opened in binary mode for *name*. It is supposed to be at position 0. - For modes ``'w:gz'``, ``'r:gz'``, ``'w:bz2'``, ``'r:bz2'``, :func:`tarfile.open` - accepts the keyword argument *compresslevel* to specify the compression level of - the file. + For modes ``'w:gz'``, ``'r:gz'``, ``'w:bz2'``, ``'r:bz2'``, ``'x:gz'``, + ``'x:bz2'``, :func:`tarfile.open` accepts the keyword argument + *compresslevel* to specify the compression level of the file. For special purposes, there is a second format for *mode*: ``'filemode|[compression]'``. :func:`tarfile.open` will return a :class:`TarFile` @@ -127,6 +144,8 @@ | | writing. | +-------------+--------------------------------------------+ + .. versionchanged:: 3.5 + The ``'x'`` (exclusive creation) mode was added. .. class:: TarFile @@ -252,8 +271,8 @@ In this case, the file object's :attr:`name` attribute is used if it exists. *mode* is either ``'r'`` to read from an existing archive, ``'a'`` to append - data to an existing file or ``'w'`` to create a new file overwriting an existing - one. + data to an existing file, ``'w'`` to create a new file overwriting an existing + one or ``'x'`` to create a new file only if it's not exists. If *fileobj* is given, it is used for reading or writing data. If it can be determined, *mode* is overridden by *fileobj*'s mode. *fileobj* will be used @@ -292,12 +311,14 @@ to be handled. The default settings will work for most users. See section :ref:`tar-unicode` for in-depth information. + The *pax_headers* argument is an optional dictionary of strings which + will be added as a pax global header if *format* is :const:`PAX_FORMAT`. + .. versionchanged:: 3.2 Use ``'surrogateescape'`` as the default for the *errors* argument. - The *pax_headers* argument is an optional dictionary of strings which - will be added as a pax global header if *format* is :const:`PAX_FORMAT`. - + .. versionchanged:: 3.5 + The ``'x'`` (exclusive creation) mode was added. .. classmethod:: TarFile.open(...) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -334,6 +334,12 @@ :meth:`socket.socket.send`. (Contributed by Giampaolo Rodola' in :issue:`17552`.) +tarfile +------- + +* The :func:`tarfile.open` function now supports ``'x'`` (exclusive creation) + mode. (Contributed by Berker Peksag in :issue:`21717`.) + time ---- diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1409,9 +1409,9 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - modes = {"r": "rb", "a": "r+b", "w": "wb"} + modes = {"r": "rb", "a": "r+b", "w": "wb", "x": "xb"} if mode not in modes: - raise ValueError("mode must be 'r', 'a' or 'w'") + raise ValueError("mode must be 'r', 'a', 'w' or 'x'") self.mode = mode self._mode = modes[mode] @@ -1524,6 +1524,15 @@ 'w:bz2' open for writing with bzip2 compression 'w:xz' open for writing with lzma compression + 'x' or 'x:' create a tarfile exclusively without compression, raise + an exception if the file is already created + 'x:gz' create an gzip compressed tarfile, raise an exception + if the file is already created + 'x:bz2' create an bzip2 compressed tarfile, raise an exception + if the file is already created + 'x:xz' create an lzma compressed tarfile, raise an exception + if the file is already created + 'r|*' open a stream of tar blocks with transparent compression 'r|' open an uncompressed stream of tar blocks for reading 'r|gz' open a gzip compressed stream of tar blocks @@ -1582,7 +1591,7 @@ t._extfileobj = False return t - elif mode in ("a", "w"): + elif mode in ("a", "w", "x"): return cls.taropen(name, mode, fileobj, **kwargs) raise ValueError("undiscernible mode") @@ -1591,8 +1600,8 @@ def taropen(cls, name, mode="r", fileobj=None, **kwargs): """Open uncompressed tar archive name for reading or writing. """ - if mode not in ("r", "a", "w"): - raise ValueError("mode must be 'r', 'a' or 'w'") + if mode not in ("r", "a", "w", "x"): + raise ValueError("mode must be 'r', 'a', 'w' or 'x'") return cls(name, mode, fileobj, **kwargs) @classmethod @@ -1600,8 +1609,8 @@ """Open gzip compressed tar archive name for reading or writing. Appending is not allowed. """ - if mode not in ("r", "w"): - raise ValueError("mode must be 'r' or 'w'") + if mode not in ("r", "w", "x"): + raise ValueError("mode must be 'r', 'w' or 'x'") try: import gzip @@ -1634,8 +1643,8 @@ """Open bzip2 compressed tar archive name for reading or writing. Appending is not allowed. """ - if mode not in ("r", "w"): - raise ValueError("mode must be 'r' or 'w'.") + if mode not in ("r", "w", "x"): + raise ValueError("mode must be 'r', 'w' or 'x'") try: import bz2 @@ -1663,8 +1672,8 @@ """Open lzma compressed tar archive name for reading or writing. Appending is not allowed. """ - if mode not in ("r", "w"): - raise ValueError("mode must be 'r' or 'w'") + if mode not in ("r", "w", "x"): + raise ValueError("mode must be 'r', 'w' or 'x'") try: import lzma @@ -1751,7 +1760,7 @@ addfile(). If given, `arcname' specifies an alternative name for the file in the archive. """ - self._check("aw") + self._check("awx") # When fileobj is given, replace name by # fileobj's real name. @@ -1885,7 +1894,7 @@ TarInfo object, if it returns None the TarInfo object will be excluded from the archive. """ - self._check("aw") + self._check("awx") if arcname is None: arcname = name @@ -1942,7 +1951,7 @@ On Windows platforms, `fileobj' should always be opened with mode 'rb' to avoid irritation about the file size. """ - self._check("aw") + self._check("awx") tarinfo = copy.copy(tarinfo) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1428,6 +1428,88 @@ ("longlnk/" * 127) + "longlink_") +class CreateTest(TarTest, unittest.TestCase): + + prefix = "x:" + + file_path = os.path.join(TEMPDIR, "spameggs42") + + def setUp(self): + support.unlink(tmpname) + + @classmethod + def setUpClass(cls): + with open(cls.file_path, "wb") as fobj: + fobj.write(b"aaa") + + @classmethod + def tearDownClass(cls): + support.unlink(cls.file_path) + + def test_create(self): + with tarfile.open(tmpname, self.mode) as tobj: + tobj.add(self.file_path) + + with self.taropen(tmpname) as tobj: + names = tobj.getnames() + self.assertEqual(len(names), 1) + self.assertIn('spameggs42', names[0]) + + def test_create_existing(self): + with tarfile.open(tmpname, self.mode) as tobj: + tobj.add(self.file_path) + + with self.assertRaises(FileExistsError): + tobj = tarfile.open(tmpname, self.mode) + + with self.taropen(tmpname) as tobj: + names = tobj.getnames() + self.assertEqual(len(names), 1) + self.assertIn('spameggs42', names[0]) + + def test_create_taropen(self): + with self.taropen(tmpname, "x") as tobj: + tobj.add(self.file_path) + + with self.taropen(tmpname) as tobj: + names = tobj.getnames() + self.assertEqual(len(names), 1) + self.assertIn('spameggs42', names[0]) + + def test_create_existing_taropen(self): + with self.taropen(tmpname, "x") as tobj: + tobj.add(self.file_path) + + with self.assertRaises(FileExistsError): + with self.taropen(tmpname, "x"): + pass + + with self.taropen(tmpname) as tobj: + names = tobj.getnames() + self.assertEqual(len(names), 1) + self.assertIn("spameggs42", names[0]) + + +class GzipCreateTest(GzipTest, CreateTest): + pass + + +class Bz2CreateTest(Bz2Test, CreateTest): + pass + + +class LzmaCreateTest(LzmaTest, CreateTest): + pass + + +class CreateWithXModeTest(CreateTest): + + prefix = "x" + + test_create_taropen = None + test_create_existing_taropen = None + + @unittest.skipUnless(hasattr(os, "link"), "Missing hardlink implementation") class HardlinkTest(unittest.TestCase): # Test the creation of LNKTYPE (hardlink) members in an archive. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #21717: tarfile.open() now supports 'x' (exclusive creation) mode. + - Issue #23344: marshal.dumps() is now 20-25% faster on average. - Issue #20416: marshal.dumps() with protocols 3 and 4 is now 40-50% faster on -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 00:40:15 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 13 Feb 2015 23:40:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314910=3A_Add_allo?= =?utf-8?q?w=5Fabbrev_parameter_to_argparse=2EArgumentParser=2E?= Message-ID: <20150213233850.43783.15130@psf.io> https://hg.python.org/cpython/rev/99302634d756 changeset: 94605:99302634d756 user: Berker Peksag date: Sat Feb 14 01:39:17 2015 +0200 summary: Issue #14910: Add allow_abbrev parameter to argparse.ArgumentParser. Patch by Jonathan Paugh, Steven Bethard, paul j3 and Daniel Eriksson. files: Doc/library/argparse.rst | 35 ++++++++++++++++++++-- Doc/whatsnew/3.5.rst | 8 +++++ Lib/argparse.py | 40 ++++++++++++++------------ Lib/test/test_argparse.py | 33 ++++++++++++++++++++++ Misc/NEWS | 3 ++ 5 files changed, 97 insertions(+), 22 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -135,7 +135,7 @@ formatter_class=argparse.HelpFormatter, \ prefix_chars='-', fromfile_prefix_chars=None, \ argument_default=None, conflict_handler='error', \ - add_help=True) + add_help=True, allow_abbrev=True) Create a new :class:`ArgumentParser` object. All parameters should be passed as keyword arguments. Each parameter has its own more detailed description @@ -169,6 +169,12 @@ * add_help_ - Add a -h/--help option to the parser (default: ``True``) + * allow_abbrev_ - Allows long options to be abbreviated if the + abbreviation is unambiguous. (default: ``True``) + + .. versionchanged:: 3.5 + *allow_abbrev* parameter was added. + The following sections describe how each of these are used. @@ -518,6 +524,26 @@ >>> parser.parse_args([]) Namespace() +.. _allow_abbrev: + +allow_abbrev +^^^^^^^^^^^^ + +Normally, when you pass an argument list to the +:meth:`~ArgumentParser.parse_args` method of a :class:`ArgumentParser`, +it :ref:`recognizes abbreviations ` of long options. + +This feature can be disabled by setting ``allow_abbrev`` to ``False``:: + + >>> parser = argparse.ArgumentParser(prog='PROG', allow_abbrev=False) + >>> parser.add_argument('--foobar', action='store_true') + >>> parser.add_argument('--foonley', action='store_false') + >>> parser.parse_args([--foon]) + usage: PROG [-h] [--foobar] [--foonley] + PROG: error: unrecognized arguments: --foon + +.. versionadded:: 3.5 + conflict_handler ^^^^^^^^^^^^^^^^ @@ -1410,9 +1436,9 @@ Argument abbreviations (prefix matching) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The :meth:`~ArgumentParser.parse_args` method allows long options to be -abbreviated to a prefix, if the abbreviation is unambiguous (the prefix matches -a unique option):: +The :meth:`~ArgumentParser.parse_args` method :ref:`by default ` +allows long options to be abbreviated to a prefix, if the abbreviation is +unambiguous (the prefix matches a unique option):: >>> parser = argparse.ArgumentParser(prog='PROG') >>> parser.add_argument('-bacon') @@ -1426,6 +1452,7 @@ PROG: error: ambiguous option: -ba could match -badger, -bacon An error is produced for arguments that could produce more than one options. +This feature can be disabled by setting :ref:`allow_abbrev` to ``False``. Beyond ``sys.argv`` diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -146,6 +146,14 @@ Improved Modules ================ +argparse +-------- + +* :class:`~argparse.ArgumentParser` now allows to disable + :ref:`abbreviated usage ` of long options by setting + :ref:`allow_abbrev` to ``False``. + (Contributed by Jonathan Paugh, Steven Bethard, paul j3 and Daniel Eriksson.) + cgi --- diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1590,6 +1590,7 @@ - argument_default -- The default value for all arguments - conflict_handler -- String indicating how to handle conflicts - add_help -- Add a -h/-help option + - allow_abbrev -- Allow long options to be abbreviated unambiguously """ def __init__(self, @@ -1603,7 +1604,8 @@ fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', - add_help=True): + add_help=True, + allow_abbrev=True): superinit = super(ArgumentParser, self).__init__ superinit(description=description, @@ -1621,6 +1623,7 @@ self.formatter_class = formatter_class self.fromfile_prefix_chars = fromfile_prefix_chars self.add_help = add_help + self.allow_abbrev = allow_abbrev add_group = self.add_argument_group self._positionals = add_group(_('positional arguments')) @@ -2098,23 +2101,24 @@ action = self._option_string_actions[option_string] return action, option_string, explicit_arg - # search through all possible prefixes of the option string - # and all actions in the parser for possible interpretations - option_tuples = self._get_option_tuples(arg_string) - - # if multiple actions match, the option string was ambiguous - if len(option_tuples) > 1: - options = ', '.join([option_string - for action, option_string, explicit_arg in option_tuples]) - args = {'option': arg_string, 'matches': options} - msg = _('ambiguous option: %(option)s could match %(matches)s') - self.error(msg % args) - - # if exactly one action matched, this segmentation is good, - # so return the parsed action - elif len(option_tuples) == 1: - option_tuple, = option_tuples - return option_tuple + if self.allow_abbrev: + # search through all possible prefixes of the option string + # and all actions in the parser for possible interpretations + option_tuples = self._get_option_tuples(arg_string) + + # if multiple actions match, the option string was ambiguous + if len(option_tuples) > 1: + options = ', '.join([option_string + for action, option_string, explicit_arg in option_tuples]) + args = {'option': arg_string, 'matches': options} + msg = _('ambiguous option: %(option)s could match %(matches)s') + self.error(msg % args) + + # if exactly one action matched, this segmentation is good, + # so return the parsed action + elif len(option_tuples) == 1: + option_tuple, = option_tuples + return option_tuple # if it was not found as an option, but it looks like a negative # number, it was meant to be positional diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -753,6 +753,39 @@ ] +class TestOptionalsAllowLongAbbreviation(ParserTestCase): + """Allow long options to be abbreviated unambiguously""" + + argument_signatures = [ + Sig('--foo'), + Sig('--foobaz'), + Sig('--fooble', action='store_true'), + ] + failures = ['--foob 5', '--foob'] + successes = [ + ('', NS(foo=None, foobaz=None, fooble=False)), + ('--foo 7', NS(foo='7', foobaz=None, fooble=False)), + ('--fooba a', NS(foo=None, foobaz='a', fooble=False)), + ('--foobl --foo g', NS(foo='g', foobaz=None, fooble=True)), + ] + + +class TestOptionalsDisallowLongAbbreviation(ParserTestCase): + """Do not allow abbreviations of long options at all""" + + parser_signature = Sig(allow_abbrev=False) + argument_signatures = [ + Sig('--foo'), + Sig('--foodle', action='store_true'), + Sig('--foonly'), + ] + failures = ['-foon 3', '--foon 3', '--food', '--food --foo 2'] + successes = [ + ('', NS(foo=None, foodle=False, foonly=None)), + ('--foo 3', NS(foo='3', foodle=False, foonly=None)), + ('--foonly 7 --foodle --foo 2', NS(foo='2', foodle=True, foonly='7')), + ] + # ================ # Positional tests # ================ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #14910: Add allow_abbrev parameter to argparse.ArgumentParser. Patch by + Jonathan Paugh, Steven Bethard, paul j3 and Daniel Eriksson. + - Issue #21717: tarfile.open() now supports 'x' (exclusive creation) mode. - Issue #23344: marshal.dumps() is now 20-25% faster on average. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sat Feb 14 06:14:50 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 14 Feb 2015 06:14:50 +0100 Subject: [Python-checkins] Daily reference leaks (ed9e9e6b3c1e): sum=1421 Message-ID: results for ed9e9e6b3c1e on branch "default" -------------------------------------------- test_asyncio leaked [388, 388, 388] references, sum=1164 test_asyncio leaked [84, 85, 85] memory blocks, sum=254 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogdTvIOm', '-x'] From python-checkins at python.org Sat Feb 14 10:02:36 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 09:02:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319105=3A_pprint_n?= =?utf-8?q?ow_more_efficiently_uses_free_space_at_the_right=2E?= Message-ID: <20150214090233.60724.50156@psf.io> https://hg.python.org/cpython/rev/7a6671d491da changeset: 94606:7a6671d491da user: Serhiy Storchaka date: Sat Feb 14 10:55:19 2015 +0200 summary: Issue #19105: pprint now more efficiently uses free space at the right. files: Lib/pprint.py | 87 +++++++++++++++++-------- Lib/test/test_pprint.py | 97 +++++++++++++++++++++++++--- Misc/NEWS | 2 + 3 files changed, 147 insertions(+), 39 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -161,7 +161,7 @@ return rep = self._repr(object, context, level - 1) typ = type(object) - max_width = self._width - 1 - indent - allowance + max_width = self._width - indent - allowance sepLines = len(rep) > max_width write = stream.write @@ -174,24 +174,14 @@ length = len(object) if length: context[objid] = 1 - indent = indent + self._indent_per_level if issubclass(typ, _OrderedDict): items = list(object.items()) else: items = sorted(object.items(), key=_safe_tuple) - key, ent = items[0] - rep = self._repr(key, context, level) - write(rep) - write(': ') - self._format(ent, stream, indent + len(rep) + 2, - allowance + 1, context, level) - if length > 1: - for key, ent in items[1:]: - rep = self._repr(key, context, level) - write(',\n%s%s: ' % (' '*indent, rep)) - self._format(ent, stream, indent + len(rep) + 2, - allowance + 1, context, level) - indent = indent - self._indent_per_level + self._format_dict_items(items, stream, + indent + self._indent_per_level, + allowance + 1, + context, level) del context[objid] write('}') return @@ -207,7 +197,10 @@ endchar = ']' elif issubclass(typ, tuple): write('(') - endchar = ')' + if length == 1: + endchar = ',)' + else: + endchar = ')' else: if not length: write(rep) @@ -227,10 +220,9 @@ context[objid] = 1 self._format_items(object, stream, indent + self._indent_per_level, - allowance + 1, context, level) + allowance + len(endchar), + context, level) del context[objid] - if issubclass(typ, tuple) and length == 1: - write(',') write(endchar) return @@ -239,19 +231,27 @@ lines = object.splitlines(True) if level == 1: indent += 1 - max_width -= 2 + allowance += 1 + max_width1 = max_width = self._width - indent for i, line in enumerate(lines): rep = repr(line) - if len(rep) <= max_width: + if i == len(lines) - 1: + max_width1 -= allowance + if len(rep) <= max_width1: chunks.append(rep) else: # A list of alternating (non-space, space) strings - parts = re.split(r'(\s+)', line) + [''] + parts = re.findall(r'\S*\s*', line) + assert parts + assert not parts[-1] + parts.pop() # drop empty last part + max_width2 = max_width current = '' - for i in range(0, len(parts), 2): - part = parts[i] + parts[i+1] + for j, part in enumerate(parts): candidate = current + part - if len(repr(candidate)) > max_width: + if j == len(parts) - 1 and i == len(lines) - 1: + max_width2 -= allowance + if len(repr(candidate)) > max_width2: if current: chunks.append(repr(current)) current = part @@ -273,12 +273,41 @@ return write(rep) + def _format_dict_items(self, items, stream, indent, allowance, context, + level): + write = stream.write + delimnl = ',\n' + ' ' * indent + last_index = len(items) - 1 + for i, (key, ent) in enumerate(items): + last = i == last_index + rep = self._repr(key, context, level) + write(rep) + write(': ') + self._format(ent, stream, indent + len(rep) + 2, + allowance if last else 1, + context, level) + if not last: + write(delimnl) + def _format_items(self, items, stream, indent, allowance, context, level): write = stream.write delimnl = ',\n' + ' ' * indent delim = '' - width = max_width = self._width - indent - allowance + 2 - for ent in items: + width = max_width = self._width - indent + 1 + it = iter(items) + try: + next_ent = next(it) + except StopIteration: + return + last = False + while not last: + ent = next_ent + try: + next_ent = next(it) + except StopIteration: + last = True + max_width -= allowance + width -= allowance if self._compact: rep = self._repr(ent, context, level) w = len(rep) + 2 @@ -294,7 +323,9 @@ continue write(delim) delim = delimnl - self._format(ent, stream, indent, allowance, context, level) + self._format(ent, stream, indent, + allowance if last else 1, + context, level) def _repr(self, object, context, level): repr, readable, recursive = self.format(object, context.copy(), diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -192,10 +192,52 @@ o = [o1, o2] expected = """\ [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + {'first': 1, 'second': 2, 'third': 3}]""" + self.assertEqual(pprint.pformat(o, indent=4, width=42), expected) + expected = """\ +[ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], { 'first': 1, 'second': 2, 'third': 3}]""" - self.assertEqual(pprint.pformat(o, indent=4, width=42), expected) + self.assertEqual(pprint.pformat(o, indent=4, width=41), expected) + + def test_width(self): + expected = """\ +[[[[[[1, 2, 3], + '1 2']]]], + {1: [1, 2, 3], + 2: [12, 34]}, + 'abc def ghi', + ('ab cd ef',), + set2({1, 23}), + [[[[[1, 2, 3], + '1 2']]]]]""" + o = eval(expected) + self.assertEqual(pprint.pformat(o, width=15), expected) + self.assertEqual(pprint.pformat(o, width=16), expected) + self.assertEqual(pprint.pformat(o, width=25), expected) + self.assertEqual(pprint.pformat(o, width=14), """\ +[[[[[[1, + 2, + 3], + '1 ' + '2']]]], + {1: [1, + 2, + 3], + 2: [12, + 34]}, + 'abc def ' + 'ghi', + ('ab cd ' + 'ef',), + set2({1, + 23}), + [[[[[1, + 2, + 3], + '1 ' + '2']]]]]""") def test_sorted_dict(self): # Starting in Python 2.5, pprint sorts dict displays by key regardless @@ -535,13 +577,12 @@ def test_str_wrap(self): # pprint tries to wrap strings intelligently fox = 'the quick brown fox jumped over a lazy dog' - self.assertEqual(pprint.pformat(fox, width=20), """\ -('the quick ' - 'brown fox ' - 'jumped over a ' - 'lazy dog')""") + self.assertEqual(pprint.pformat(fox, width=19), """\ +('the quick brown ' + 'fox jumped over ' + 'a lazy dog')""") self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2}, - width=26), """\ + width=25), """\ {'a': 1, 'b': 'the quick brown ' 'fox jumped over ' @@ -553,12 +594,34 @@ # - non-ASCII is allowed # - an apostrophe doesn't disrupt the pprint special = "Portons dix bons \"whiskys\"\n? l'avocat goujat\t qui fumait au zoo" - self.assertEqual(pprint.pformat(special, width=21), """\ -('Portons dix ' - 'bons "whiskys"\\n' + self.assertEqual(pprint.pformat(special, width=68), repr(special)) + self.assertEqual(pprint.pformat(special, width=31), """\ +('Portons dix bons "whiskys"\\n' + "? l'avocat goujat\\t qui " + 'fumait au zoo')""") + self.assertEqual(pprint.pformat(special, width=20), """\ +('Portons dix bons ' + '"whiskys"\\n' "? l'avocat " 'goujat\\t qui ' 'fumait au zoo')""") + self.assertEqual(pprint.pformat([[[[[special]]]]], width=35), """\ +[[[[['Portons dix bons "whiskys"\\n' + "? l'avocat goujat\\t qui " + 'fumait au zoo']]]]]""") + self.assertEqual(pprint.pformat([[[[[special]]]]], width=25), """\ +[[[[['Portons dix bons ' + '"whiskys"\\n' + "? l'avocat " + 'goujat\\t qui ' + 'fumait au zoo']]]]]""") + self.assertEqual(pprint.pformat([[[[[special]]]]], width=23), """\ +[[[[['Portons dix ' + 'bons "whiskys"\\n' + "? l'avocat " + 'goujat\\t qui ' + 'fumait au ' + 'zoo']]]]]""") # An unwrappable string is formatted as its repr unwrappable = "x" * 100 self.assertEqual(pprint.pformat(unwrappable, width=80), repr(unwrappable)) @@ -581,7 +644,19 @@ 14, 15], [], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4]]""" - self.assertEqual(pprint.pformat(o, width=48, compact=True), expected) + self.assertEqual(pprint.pformat(o, width=47, compact=True), expected) + + def test_compact_width(self): + levels = 20 + number = 10 + o = [0] * number + for i in range(levels - 1): + o = [o] + for w in range(levels * 2 + 1, levels + 3 * number - 1): + lines = pprint.pformat(o, width=w, compact=True).splitlines() + maxwidth = max(map(len, lines)) + self.assertLessEqual(maxwidth, w) + self.assertGreater(maxwidth, w - 3) class DottedPrettyPrinter(pprint.PrettyPrinter): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #19105: pprint now more efficiently uses free space at the right. + - Issue #14910: Add allow_abbrev parameter to argparse.ArgumentParser. Patch by Jonathan Paugh, Steven Bethard, paul j3 and Daniel Eriksson. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 16:34:21 2015 From: python-checkins at python.org (chris.angelico) Date: Sat, 14 Feb 2015 15:34:21 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Apply_PEP_486_changes_from_Pa?= =?utf-8?q?ul_Moore?= Message-ID: <20150214153411.126610.60983@psf.io> https://hg.python.org/peps/rev/d81a7d2993b5 changeset: 5696:d81a7d2993b5 user: Chris Angelico date: Sun Feb 15 02:33:55 2015 +1100 summary: Apply PEP 486 changes from Paul Moore files: pep-0486.txt | 38 +++++++++++++++++++------------------- 1 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pep-0486.txt b/pep-0486.txt --- a/pep-0486.txt +++ b/pep-0486.txt @@ -83,6 +83,7 @@ Impact on Script Launching ========================== + As well as interactive use, the launcher is used as the Windows file association for Python scripts. In that case, a "shebang" (``#!``) line at the start of the script is used to identify the interpreter to @@ -90,26 +91,18 @@ (``python3`` or ``python2``, or even ``python3.5``), or the generic ``python``, which means to use the default interpreter. -With the proposed change, scripts that start with ``#!python`` (or one -of its equivalent forms) will be run using an active virtualenv. This -is a change in behaviour, although it will only affect users running -scripts from the command line with a virtualenv activated. +The launcher also looks for the specific shebang line +``#!/usr/bin/env python``. On Unix, the ``env`` program searches for a +command on ``$PATH`` and runs the command so located. Similarly, with +this shebang line, the launcher will look for a copy of ``python.exe`` +on the user's current ``%PATH%`` and will run that copy. -Under Unix, the ``#!/usr/bin/env python`` shebang line will use the -version of Python found on ``$PATH``, whereas ``#!/usr/bin/python`` -will use the system Python. In order to match Unix behaviour as -closely as possible, it is proposed that the two shebang forms:: - - #!/usr/bin/env python - #!python - -use an active virtualenv, if present, whereas the forms:: - - #!/usr/bin/python - #!/usr/local/bin/python - -use *only* the default system Python, and ignore the ``VIRTUAL_ENV`` -environment variable. +As activating a virtualenv means that it is added to ``PATH``, no +special handling is needed to run scripts with the active virtualenv - +they just need to use the ``#!/usr/bin/env python`` shebang line, +exactly as on Unix. (If there is no activated virtualenv, and no +``python.exe`` on ``PATH``, the launcher will look for a default +Python exactly as if the shebang line had said ``#!python``). Exclusions @@ -126,6 +119,13 @@ to do so when using virtual environments. +Reference Implementation +======================== + +A patch implementing the proposed behaviour is available at +http://bugs.python.org/issue23465 + + References ========== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sat Feb 14 18:38:43 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 14 Feb 2015 17:38:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323461=3A_Normalis?= =?utf-8?q?e_line_endings_when_comparing_old_and_new_contents_of?= Message-ID: <20150214173838.62575.73783@psf.io> https://hg.python.org/cpython/rev/f9a43e2a3877 changeset: 94607:f9a43e2a3877 user: Steve Dower date: Sat Feb 14 09:38:19 2015 -0800 summary: Issue #23461: Normalise line endings when comparing old and new contents of importlib.h files: PCbuild/_freeze_importlib.vcxproj | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PCbuild/_freeze_importlib.vcxproj b/PCbuild/_freeze_importlib.vcxproj --- a/PCbuild/_freeze_importlib.vcxproj +++ b/PCbuild/_freeze_importlib.vcxproj @@ -85,8 +85,8 @@ - <_OldContent Condition="Exists('$(PySourcePath)Python\importlib.h')">$([System.IO.File]::ReadAllText('$(PySourcePath)Python\importlib.h')) - <_NewContent Condition="Exists('$(IntDir)importlib.g.h')">$([System.IO.File]::ReadAllText('$(IntDir)importlib.g.h')) + <_OldContent Condition="Exists('$(PySourcePath)Python\importlib.h')">$([System.IO.File]::ReadAllText('$(PySourcePath)Python\importlib.h').Replace(` `, ` `)) + <_NewContent Condition="Exists('$(IntDir)importlib.g.h')">$([System.IO.File]::ReadAllText('$(IntDir)importlib.g.h').Replace(` `, ` `)) https://hg.python.org/cpython/rev/add998f98e31 changeset: 94608:add998f98e31 user: Steve Dower date: Sat Feb 14 09:50:59 2015 -0800 summary: Closes #23437: Make user scripts directory versioned on Windows (patch by pmoore) files: Doc/install/index.rst | 2 +- Lib/distutils/command/install.py | 2 +- Lib/sysconfig.py | 2 +- Tools/scripts/win_add2path.py | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -361,7 +361,7 @@ Type of file Installation directory =============== =========================================================== modules :file:`{userbase}\\Python{XY}\\site-packages` -scripts :file:`{userbase}\\Scripts` +scripts :file:`{userbase}\\Python{XY}\\Scripts` data :file:`{userbase}` C headers :file:`{userbase}\\Python{XY}\\Include\\{distname}` =============== =========================================================== diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -51,7 +51,7 @@ 'purelib': '$usersite', 'platlib': '$usersite', 'headers': '$userbase/Python$py_version_nodot/Include/$dist_name', - 'scripts': '$userbase/Scripts', + 'scripts': '$userbase/Python$py_version_nodot/Scripts', 'data' : '$userbase', } diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -57,7 +57,7 @@ 'purelib': '{userbase}/Python{py_version_nodot}/site-packages', 'platlib': '{userbase}/Python{py_version_nodot}/site-packages', 'include': '{userbase}/Python{py_version_nodot}/Include', - 'scripts': '{userbase}/Scripts', + 'scripts': '{userbase}/Python{py_version_nodot}/Scripts', 'data': '{userbase}', }, 'posix_user': { diff --git a/Tools/scripts/win_add2path.py b/Tools/scripts/win_add2path.py --- a/Tools/scripts/win_add2path.py +++ b/Tools/scripts/win_add2path.py @@ -22,7 +22,8 @@ scripts = os.path.join(pythonpath, "Scripts") appdata = os.environ["APPDATA"] if hasattr(site, "USER_SITE"): - userpath = site.USER_SITE.replace(appdata, "%APPDATA%") + usersite = site.USER_SITE.replace(appdata, "%APPDATA%") + userpath = os.path.dirname(usersite) userscripts = os.path.join(userpath, "Scripts") else: userscripts = None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 18:56:15 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 17:56:15 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Fixed_markup_of_footnotes=2E?= Message-ID: <20150214175610.126616.12978@psf.io> https://hg.python.org/peps/rev/de065ae65454 changeset: 5698:de065ae65454 user: Serhiy Storchaka date: Sat Feb 14 19:49:04 2015 +0200 summary: Fixed markup of footnotes. files: pep-0345.txt | 5 ++++- pep-0377.txt | 10 +++++----- pep-0383.txt | 22 +++++++++++----------- pep-0403.txt | 2 +- pep-0408.txt | 12 ++++++------ pep-0439.txt | 2 +- pep-3000.txt | 2 +- pep-3111.txt | 12 ++++++------ pep-3153.txt | 2 +- 9 files changed, 36 insertions(+), 33 deletions(-) diff --git a/pep-0345.txt b/pep-0345.txt --- a/pep-0345.txt +++ b/pep-0345.txt @@ -255,7 +255,7 @@ ::::::::::::::::::::::::: Each entry is a string giving a single classification value -for the distribution. Classifiers are described in PEP 301 [2]. +for the distribution. Classifiers are described in PEP 301 [3]_. Examples:: @@ -543,6 +543,9 @@ .. [2] RFC 822 Long Header Fields: http://www.freesoft.org/CIE/RFC/822/7.htm +.. [3] PEP 301, Package Index and Metadata for Distutils: + http://www.python.org/dev/peps/pep-0301/ + Copyright ========= diff --git a/pep-0377.txt b/pep-0377.txt --- a/pep-0377.txt +++ b/pep-0377.txt @@ -22,7 +22,7 @@ with a yield in the appropriate location. One symptom of this is that ``contextlib.nested`` will currently raise ``RuntimeError`` in situations where writing out the corresponding nested ``with`` -statements would not [1]. +statements would not [1]_. The proposed change is to introduce a new flow control exception ``SkipStatement``, and skip the execution of the ``with`` @@ -32,7 +32,7 @@ PEP Rejection ============= -This PEP was rejected by Guido [2] as it imposes too great an increase +This PEP was rejected by Guido [4]_ as it imposes too great an increase in complexity without a proportional increase in expressiveness and correctness. In the absence of compelling use cases that need the more complex semantics proposed by this PEP the existing behaviour is @@ -51,7 +51,7 @@ (similar to the existing ``NotImplemented`` singleton) will be assigned to all names that appear in the ``as`` clause. -The components of the ``with`` statement remain as described in PEP 343 [2]:: +The components of the ``with`` statement remain as described in PEP 343 [2]_:: with EXPR as VAR: BLOCK @@ -221,7 +221,7 @@ suppress = self.cmA.__exit__(*args): return suppress -There is currently a tentative suggestion [3] to add import-style syntax to +There is currently a tentative suggestion [3]_ to add import-style syntax to the ``with`` statement to allow multiple context managers to be included in a single ``with`` statement without needing to use ``contextlib.nested``. In that case the compiler has the option of simply emitting multiple ``with`` @@ -249,7 +249,7 @@ Reference Implementation ======================== -Patch attached to Issue 5251 [1]. That patch uses only existing opcodes +Patch attached to Issue 5251 [1]_. That patch uses only existing opcodes (i.e. no ``SETUP_WITH``). diff --git a/pep-0383.txt b/pep-0383.txt --- a/pep-0383.txt +++ b/pep-0383.txt @@ -64,7 +64,7 @@ On Windows, Python uses the wide character APIs to access character-oriented APIs, allowing direct conversion of the -environmental data to Python str objects ([1]). +environmental data to Python str objects ([1]_). On POSIX systems, Python currently applies the locale's encoding to convert the byte data to Unicode, failing for characters that cannot @@ -72,7 +72,7 @@ represented as lone surrogate codes U+DC80..U+DCFF. Bytes below 128 will produce exceptions; see the discussion below. -To convert non-decodable bytes, a new error handler ([2]) +To convert non-decodable bytes, a new error handler ([2]_) "surrogateescape" is introduced, which produces these surrogates. On encoding, the error handler converts the surrogate back to the corresponding byte. This error handler will be used in any API that @@ -95,7 +95,7 @@ ========== This surrogateescape encoding is based on Markus Kuhn's idea that -he called UTF-8b [3]. +he called UTF-8b [3]_. While providing a uniform API to non-decodable bytes, this interface has the limitation that chosen representation only "works" if the data @@ -171,16 +171,16 @@ References ========== - [1] PEP 277 - "Unicode file name support for Windows NT" - http://www.python.org/dev/peps/pep-0277/ +.. [1] PEP 277 + "Unicode file name support for Windows NT" + http://www.python.org/dev/peps/pep-0277/ - [2] PEP 293 - "Codec Error Handling Callbacks" - http://www.python.org/dev/peps/pep-0293/ +.. [2] PEP 293 + "Codec Error Handling Callbacks" + http://www.python.org/dev/peps/pep-0293/ - [3] UTF-8b - http://mail.nl.linux.org/linux-utf8/2000-07/msg00040.html +.. [3] UTF-8b + http://mail.nl.linux.org/linux-utf8/2000-07/msg00040.html Copyright ========= diff --git a/pep-0403.txt b/pep-0403.txt --- a/pep-0403.txt +++ b/pep-0403.txt @@ -428,7 +428,7 @@ Anonymous Forward References ---------------------------- -A previous incarnation of this PEP (see [1]) proposed a syntax where the +A previous incarnation of this PEP (see [1]_) proposed a syntax where the new clause was introduced with ``:`` and the forward reference was written using ``@``. Feedback on this variant was almost universally negative, as it was considered both ugly and excessively magical:: diff --git a/pep-0408.txt b/pep-0408.txt --- a/pep-0408.txt +++ b/pep-0408.txt @@ -32,7 +32,7 @@ ============= Based on his experience with a similar "labs" namespace in Google App Engine, -Guido has rejected this PEP [3] in favour of the simpler alternative of +Guido has rejected this PEP [3]_ in favour of the simpler alternative of explicitly marking provisional modules as such in their documentation. If a module is otherwise considered suitable for standard library inclusion, @@ -42,7 +42,7 @@ without a deprecation period if the lingering concerns prove well-founded. As part of the same announcement, Guido explicitly accepted Matthew -Barnett's 'regex' module [4] as a provisional addition to the standard +Barnett's 'regex' module [4]_ as a provisional addition to the standard library for Python 3.3 (using the 'regex' name, rather than as a drop-in replacement for the existing 're' module). @@ -290,15 +290,15 @@ References ========== -.. [#] Discussed in this thread: +.. [1] Discussed in this thread: http://mail.python.org/pipermail/python-ideas/2012-January/013246.html -.. [#] http://mail.python.org/pipermail/python-ideas/2011-August/011278.html +.. [2] http://mail.python.org/pipermail/python-ideas/2011-August/011278.html -.. [#] Guido's decision: +.. [3] Guido's decision: http://mail.python.org/pipermail/python-dev/2012-January/115962.html -.. [#] Proposal for inclusion of regex: http://bugs.python.org/issue2636 +.. [4] Proposal for inclusion of regex: http://bugs.python.org/issue2636 Copyright diff --git a/pep-0439.txt b/pep-0439.txt --- a/pep-0439.txt +++ b/pep-0439.txt @@ -214,7 +214,7 @@ There is a Perl package installer also named "pip". It is quite rare and not commonly used. The Fedora variant of Linux has historically named Python's "pip" as "python-pip" and Perl's "pip" as "perl-pip". This policy has been -altered[3] so that future and upgraded Fedora installations will use the name +altered\ [3]_ so that future and upgraded Fedora installations will use the name "pip" for Python's "pip". Existing (non-upgraded) installations will still have the old name for the Python "pip", though the potential for confusion is now much reduced. diff --git a/pep-3000.txt b/pep-3000.txt --- a/pep-3000.txt +++ b/pep-3000.txt @@ -48,7 +48,7 @@ Timeline ======== -See PEP 361 [#pep361], which contains the release schedule for Python +See PEP 361 [#pep361]_, which contains the release schedule for Python 2.6 and 3.0. These versions will be released in lockstep. Note: standard library development is expected to ramp up after 3.0a1 diff --git a/pep-3111.txt b/pep-3111.txt --- a/pep-3111.txt +++ b/pep-3111.txt @@ -20,7 +20,7 @@ and raw_input() built-in functions. Python 3.0 will introduce various incompatible changes with previous -Python versions[1]. Among the proposed changes, print will become a built-in +Python versions\ [1]_. Among the proposed changes, print will become a built-in function, print(), while input() and raw_input() would be removed completely from the built-in namespace, requiring importing some module to provide even the most basic input capability. @@ -28,7 +28,7 @@ This PEP proposes that Python 3.0 retains some simple interactive user input capability, equivalent to raw_input(), within the built-in namespace. -It was accepted by the BDFL in December 2006 [5]. +It was accepted by the BDFL in December 2006 [5]_. Motivation @@ -42,7 +42,7 @@ Any computer language intended to be used in an educational setting should provide straightforward methods for both output and interactive input. -The current proposals for Python 3.0 [1] include a simple output pathway +The current proposals for Python 3.0 [1]_ include a simple output pathway via a built-in function named print(), but a more complicated method for input [e.g. via sys.stdin.readline()], one that requires importing an external module. Current versions of Python (pre-3.0) include raw_input() as a @@ -56,8 +56,8 @@ Current built-in functions, like input() and raw_input(), are found to be extremely useful in traditional teaching settings. (For more details, -see [2] and the discussion that followed.) -While the BDFL has clearly stated [3] that input() was not to be kept in +see [2]_ and the discussion that followed.) +While the BDFL has clearly stated [3]_ that input() was not to be kept in Python 3000, he has also stated that he was not against revising the decision of killing raw_input(). @@ -133,7 +133,7 @@ seen to outweigh the harm it does to experienced programmers - although it could cause confusion for people reading older books or tutorials. -The rationale for accepting the renaming can be found here [4]. +The rationale for accepting the renaming can be found here [4]_. References diff --git a/pep-3153.txt b/pep-3153.txt --- a/pep-3153.txt +++ b/pep-3153.txt @@ -166,7 +166,7 @@ This also allows for protocols to be stacked or nested easily, allowing for even more code reuse. A common example of this is JSON-RPC: according to the specification, it can be used across both -sockets and HTTP[#jsonrpc]_ . In practice, it tends to be primarily +sockets and HTTP [#jsonrpc]_. In practice, it tends to be primarily encapsulated in HTTP. The protocol-transport abstraction allows us to build a stack of protocols and transports that allow you to use HTTP as if it were a transport. For JSON-RPC, that might get you a stack -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sat Feb 14 18:56:15 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 17:56:15 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Removed_unneeded_spaces_befor?= =?utf-8?q?e_commas_and_periods=2E?= Message-ID: <20150214175610.60732.80757@psf.io> https://hg.python.org/peps/rev/98d8694c5aff changeset: 5697:98d8694c5aff user: Serhiy Storchaka date: Sat Feb 14 19:47:39 2015 +0200 summary: Removed unneeded spaces before commas and periods. files: pep-0249.txt | 4 ++-- pep-0255.txt | 2 +- pep-0352.txt | 2 +- pep-0378.txt | 2 +- pep-0444.txt | 6 +++--- pep-3118.txt | 2 +- pep-3127.txt | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pep-0249.txt b/pep-0249.txt --- a/pep-0249.txt +++ b/pep-0249.txt @@ -848,8 +848,8 @@ left undefined (ideal would be to not move the cursor at all). .. Note:: - This method should use native scrollable cursors, if available - , or revert to an emulation for forward-only scrollable + This method should use native scrollable cursors, if available, + or revert to an emulation for forward-only scrollable cursors. The method may raise NotSupportedError_ to signal that a specific operation is not supported by the database (e.g. backward scrolling). diff --git a/pep-0255.txt b/pep-0255.txt --- a/pep-0255.txt +++ b/pep-0255.txt @@ -480,7 +480,7 @@ http://www.python.org/dev/peps/pep-0219/ [4] "Iteration Abstraction in Sather" - Murer , Omohundro, Stoutamire and Szyperski + Murer, Omohundro, Stoutamire and Szyperski http://www.icsi.berkeley.edu/~sather/Publications/toplas.html [5] http://www.cs.arizona.edu/icon/ diff --git a/pep-0352.txt b/pep-0352.txt --- a/pep-0352.txt +++ b/pep-0352.txt @@ -208,7 +208,7 @@ Deprecation of features in Python 2.9 is optional. This is because it is not known at this time if Python 2.9 (which is slated to be the last version in the 2.x series) will actively deprecate features that -will not be in 3.0 . It is conceivable that no deprecation warnings +will not be in 3.0. It is conceivable that no deprecation warnings will be used in 2.9 since there could be such a difference between 2.9 and 3.0 that it would make 2.9 too "noisy" in terms of warnings. Thus the proposed deprecation warnings for Python 2.9 will be revisited diff --git a/pep-0378.txt b/pep-0378.txt --- a/pep-0378.txt +++ b/pep-0378.txt @@ -38,7 +38,7 @@ It is not the goal to replace the locale module, to perform internationalization tasks, or accommodate every possible convention. Such tasks are better suited to robust tools like -`Babel`_ . Instead, the goal is to make a common, everyday +`Babel`_. Instead, the goal is to make a common, everyday task easier for many users. .. _`Babel`: http://babel.edgewall.org/ diff --git a/pep-0444.txt b/pep-0444.txt --- a/pep-0444.txt +++ b/pep-0444.txt @@ -36,7 +36,7 @@ This protocol and specification is influenced heavily by the Web Services Gateway Interface (WSGI) 1.0 standard described in PEP 333 -[1]_ . The high-level rationale for having any standard that allows +[1]_. The high-level rationale for having any standard that allows Python-based web servers and applications to interoperate is outlined in PEP 333. This document essentially uses PEP 333 as a template, and changes its wording in various places for the purpose of forming a @@ -485,7 +485,7 @@ bytes instance representing a sequence of URL-encoded segments separated by the slash character (``/``). It is assumed that ``%2F`` characters will be decoded into literal slash characters - within ``PATH_INFO`` , as per CGI. + within ``PATH_INFO``, as per CGI. ``PATH_INFO`` The remainder of the request URL's "path", designating the virtual @@ -495,7 +495,7 @@ be a bytes instance representing a sequence of URL-encoded segments separated by the slash character (``/``). It is assumed that ``%2F`` characters will be decoded into literal slash characters - within ``PATH_INFO`` , as per CGI. + within ``PATH_INFO``, as per CGI. ``QUERY_STRING`` The portion of the request URL (in bytes) that follows the ``"?"``, diff --git a/pep-3118.txt b/pep-3118.txt --- a/pep-3118.txt +++ b/pep-3118.txt @@ -192,7 +192,7 @@ This is the default flag state (0). The returned buffer may or may not have writable memory. The format will be assumed to be - unsigned bytes . This is a "stand-alone" flag constant. It never + unsigned bytes. This is a "stand-alone" flag constant. It never needs to be \|'d to the others. The exporter will raise an error if it cannot provide such a contiguous buffer of bytes. diff --git a/pep-3127.txt b/pep-3127.txt --- a/pep-3127.txt +++ b/pep-3127.txt @@ -318,7 +318,7 @@ Decimal computer operation was important enough that many computers, including the ubiquitous PC, have instructions designed to operate on "binary coded decimal" -(BCD) [5]_ , a representation which devotes 4 bits to each +(BCD) [5]_, a representation which devotes 4 bits to each decimal digit. These instructions date from a time when the most strenuous calculations ever performed on many numbers were the calculations actually required to perform textual -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sat Feb 14 19:31:20 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 14 Feb 2015 18:31:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Simplify_MSI_projects=2E?= Message-ID: <20150214183113.126598.97193@psf.io> https://hg.python.org/cpython/rev/e7ba4d3fa65e changeset: 94609:e7ba4d3fa65e user: Steve Dower date: Sat Feb 14 10:30:54 2015 -0800 summary: Simplify MSI projects. files: Tools/msi/core/core.props | 12 --- Tools/msi/core/core.wixproj | 12 ++- Tools/msi/core/core.wxs | 12 --- Tools/msi/core/core_d.wixproj | 12 ++- Tools/msi/core/core_d.wxs | 13 +++ Tools/msi/core/core_pdb.wixproj | 12 ++- Tools/msi/core/core_pdb.wxs | 13 +++ Tools/msi/dev/dev.props | 42 ----------- Tools/msi/dev/dev.wixproj | 42 ++++++++++- Tools/msi/dev/dev.wxs | 7 - Tools/msi/dev/dev_d.wixproj | 12 ++- Tools/msi/dev/dev_d.wxs | 13 +++ Tools/msi/exe/exe.props | 36 --------- Tools/msi/exe/exe.wixproj | 36 +++++++++- Tools/msi/exe/exe.wxs | 12 --- Tools/msi/exe/exe_d.wixproj | 13 ++- Tools/msi/exe/exe_d.wxs | 13 +++ Tools/msi/exe/exe_pdb.wixproj | 13 ++- Tools/msi/exe/exe_pdb.wxs | 13 +++ Tools/msi/launcher/launcher.props | 12 --- Tools/msi/launcher/launcher.wixproj | 13 ++- Tools/msi/launcher/launcher.wxs | 7 - Tools/msi/launcher/launcher_files.wxs | 11 -- Tools/msi/launcher/launcher_pdb.wixproj | 11 -- Tools/msi/lib/lib.props | 27 ------- Tools/msi/lib/lib.wixproj | 27 ++++++- Tools/msi/lib/lib.wxs | 12 --- Tools/msi/lib/lib_d.wixproj | 12 ++- Tools/msi/lib/lib_d.wxs | 13 +++ Tools/msi/lib/lib_pdb.wixproj | 12 ++- Tools/msi/lib/lib_pdb.wxs | 13 +++ Tools/msi/tcltk/tcltk.props | 49 ------------- Tools/msi/tcltk/tcltk.wixproj | 42 ++++++++++- Tools/msi/tcltk/tcltk.wxs | 13 --- Tools/msi/tcltk/tcltk_d.wixproj | 21 +++++- Tools/msi/tcltk/tcltk_d.wxs | 14 +++ Tools/msi/tcltk/tcltk_pdb.wixproj | 12 ++- Tools/msi/tcltk/tcltk_pdb.wxs | 13 +++ Tools/msi/test/test.props | 22 ----- Tools/msi/test/test.wixproj | 22 +++++- Tools/msi/test/test.wxs | 12 --- Tools/msi/test/test_d.wixproj | 12 ++- Tools/msi/test/test_d.wxs | 13 +++ Tools/msi/test/test_pdb.wixproj | 12 ++- Tools/msi/test/test_pdb.wxs | 13 +++ Tools/msi/tools/tools.wixproj | 3 +- 46 files changed, 447 insertions(+), 334 deletions(-) diff --git a/Tools/msi/core/core.props b/Tools/msi/core/core.props deleted file mode 100644 --- a/Tools/msi/core/core.props +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/Tools/msi/core/core.wixproj b/Tools/msi/core/core.wixproj --- a/Tools/msi/core/core.wixproj +++ b/Tools/msi/core/core.wixproj @@ -5,7 +5,15 @@ 2.0 core Package - IncludeDefaultFeature=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/core/core.wxs b/Tools/msi/core/core.wxs --- a/Tools/msi/core/core.wxs +++ b/Tools/msi/core/core.wxs @@ -6,20 +6,8 @@ - - - - - - - - - - - - diff --git a/Tools/msi/core/core_d.wixproj b/Tools/msi/core/core_d.wixproj --- a/Tools/msi/core/core_d.wixproj +++ b/Tools/msi/core/core_d.wixproj @@ -5,7 +5,15 @@ 2.0 core_d Package - IncludeDebugBinaries=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/core/core_d.wxs b/Tools/msi/core/core_d.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core_d.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/core/core_pdb.wixproj b/Tools/msi/core/core_pdb.wixproj --- a/Tools/msi/core/core_pdb.wixproj +++ b/Tools/msi/core/core_pdb.wixproj @@ -5,7 +5,15 @@ 2.0 core_pdb Package - IncludeSymbols=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/core/core_pdb.wxs b/Tools/msi/core/core_pdb.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/core/core_pdb.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/dev/dev.props b/Tools/msi/dev/dev.props deleted file mode 100644 --- a/Tools/msi/dev/dev.props +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - $(DefineConstants); - IncludeMinGWLib=1; - - - - - - - - - - - $(PySourcePath) - !(bindpath.src) - $(PySourcePath) - - dev_include - - - - - - - <_GenDefPlatform>i386 - <_GenDefPlatform Condition="$(Platform) == 'x64'">i386:x86-64 - - - - - - - - \ No newline at end of file diff --git a/Tools/msi/dev/dev.wixproj b/Tools/msi/dev/dev.wixproj --- a/Tools/msi/dev/dev.wixproj +++ b/Tools/msi/dev/dev.wixproj @@ -5,7 +5,45 @@ 2.0 dev Package - IncludeDefaultFeature=1;$(DefineConstants) - + + + + $(DefineConstants); + IncludeMinGWLib=1; + + + + + + + + + + + + $(PySourcePath) + !(bindpath.src) + $(PySourcePath) + + dev_include + + + + + + + <_GenDefPlatform>i386 + <_GenDefPlatform Condition="$(Platform) == 'x64'">i386:x86-64 + + + + + + + \ No newline at end of file diff --git a/Tools/msi/dev/dev.wxs b/Tools/msi/dev/dev.wxs --- a/Tools/msi/dev/dev.wxs +++ b/Tools/msi/dev/dev.wxs @@ -6,7 +6,6 @@ - @@ -15,11 +14,5 @@ - - - - - - diff --git a/Tools/msi/dev/dev_d.wixproj b/Tools/msi/dev/dev_d.wixproj --- a/Tools/msi/dev/dev_d.wixproj +++ b/Tools/msi/dev/dev_d.wixproj @@ -5,7 +5,15 @@ 2.0 dev_d Package - IncludeDebugBinaries=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/dev/dev_d.wxs b/Tools/msi/dev/dev_d.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/dev/dev_d.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/exe/exe.props b/Tools/msi/exe/exe.props deleted file mode 100644 --- a/Tools/msi/exe/exe.props +++ /dev/null @@ -1,36 +0,0 @@ - - - - - ICE43 - - - - - - - - - - - - - - <_LicenseFiles Include="@(LicenseFiles)"> - $([System.IO.File]::ReadAllText(%(FullPath))) - - - - - - - - \ No newline at end of file diff --git a/Tools/msi/exe/exe.wixproj b/Tools/msi/exe/exe.wixproj --- a/Tools/msi/exe/exe.wixproj +++ b/Tools/msi/exe/exe.wixproj @@ -5,7 +5,39 @@ 2.0 exe Package - IncludeDefaultFeature=1;$(DefineConstants) - + + + ICE43 + + + + + + + + + + + + + + + <_LicenseFiles Include="@(LicenseFiles)"> + $([System.IO.File]::ReadAllText(%(FullPath))) + + + + + + + \ No newline at end of file diff --git a/Tools/msi/exe/exe.wxs b/Tools/msi/exe/exe.wxs --- a/Tools/msi/exe/exe.wxs +++ b/Tools/msi/exe/exe.wxs @@ -7,7 +7,6 @@ - @@ -25,16 +24,5 @@ - - - - - - - - - - - diff --git a/Tools/msi/exe/exe_d.wixproj b/Tools/msi/exe/exe_d.wixproj --- a/Tools/msi/exe/exe_d.wixproj +++ b/Tools/msi/exe/exe_d.wixproj @@ -5,7 +5,16 @@ 2.0 exe_d Package - IncludeDebugBinaries=1;$(DefineConstants) - + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/exe/exe_d.wxs b/Tools/msi/exe/exe_d.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe_d.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/exe/exe_pdb.wixproj b/Tools/msi/exe/exe_pdb.wixproj --- a/Tools/msi/exe/exe_pdb.wixproj +++ b/Tools/msi/exe/exe_pdb.wixproj @@ -5,7 +5,16 @@ 2.0 exe_pdb Package - IncludeSymbols=1;$(DefineConstants) - + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/exe/exe_pdb.wxs b/Tools/msi/exe/exe_pdb.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/exe/exe_pdb.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/launcher/launcher.props b/Tools/msi/launcher/launcher.props deleted file mode 100644 --- a/Tools/msi/launcher/launcher.props +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/Tools/msi/launcher/launcher.wixproj b/Tools/msi/launcher/launcher.wixproj --- a/Tools/msi/launcher/launcher.wixproj +++ b/Tools/msi/launcher/launcher.wixproj @@ -5,7 +5,16 @@ 2.0 launcher Package - IncludeDefaultFeature=1;$(DefineConstants) - + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/launcher/launcher.wxs b/Tools/msi/launcher/launcher.wxs --- a/Tools/msi/launcher/launcher.wxs +++ b/Tools/msi/launcher/launcher.wxs @@ -8,7 +8,6 @@ - @@ -16,12 +15,6 @@ - - - - - - diff --git a/Tools/msi/launcher/launcher_files.wxs b/Tools/msi/launcher/launcher_files.wxs --- a/Tools/msi/launcher/launcher_files.wxs +++ b/Tools/msi/launcher/launcher_files.wxs @@ -21,15 +21,4 @@ - - - - - - - - - - - diff --git a/Tools/msi/launcher/launcher_pdb.wixproj b/Tools/msi/launcher/launcher_pdb.wixproj deleted file mode 100644 --- a/Tools/msi/launcher/launcher_pdb.wixproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - {A21D4A23-483F-4822-A0B1-FCB14D8CEBA7} - 2.0 - launcher_pdb - Package - IncludeSymbols=1;$(DefineConstants) - - - \ No newline at end of file diff --git a/Tools/msi/lib/lib.props b/Tools/msi/lib/lib.props deleted file mode 100644 --- a/Tools/msi/lib/lib.props +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - $(PySourcePath)Lib - !(bindpath.src)Lib\ - $(PySourcePath)Lib - Lib\ - lib_py - - - - - \ No newline at end of file diff --git a/Tools/msi/lib/lib.wixproj b/Tools/msi/lib/lib.wixproj --- a/Tools/msi/lib/lib.wixproj +++ b/Tools/msi/lib/lib.wixproj @@ -5,7 +5,30 @@ 2.0 lib Package - IncludeDefaultFeature=1;$(DefineConstants) - + + + + + + + + + + + + $(PySourcePath)Lib + !(bindpath.src)Lib\ + $(PySourcePath)Lib + Lib\ + lib_py + + + + \ No newline at end of file diff --git a/Tools/msi/lib/lib.wxs b/Tools/msi/lib/lib.wxs --- a/Tools/msi/lib/lib.wxs +++ b/Tools/msi/lib/lib.wxs @@ -7,22 +7,10 @@ - - - - - - - - - - - - diff --git a/Tools/msi/lib/lib_d.wixproj b/Tools/msi/lib/lib_d.wixproj --- a/Tools/msi/lib/lib_d.wixproj +++ b/Tools/msi/lib/lib_d.wixproj @@ -5,7 +5,15 @@ 2.0 lib_d Package - IncludeDebugBinaries=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/lib/lib_d.wxs b/Tools/msi/lib/lib_d.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib_d.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/lib/lib_pdb.wixproj b/Tools/msi/lib/lib_pdb.wixproj --- a/Tools/msi/lib/lib_pdb.wixproj +++ b/Tools/msi/lib/lib_pdb.wixproj @@ -5,7 +5,15 @@ 2.0 lib_pdb Package - IncludeSymbols=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/lib/lib_pdb.wxs b/Tools/msi/lib/lib_pdb.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/lib/lib_pdb.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/tcltk/tcltk.props b/Tools/msi/tcltk/tcltk.props deleted file mode 100644 --- a/Tools/msi/tcltk/tcltk.props +++ /dev/null @@ -1,49 +0,0 @@ - - - - - ICE43 - - - - - - - - - - - $(tcltkDir) - !(bindpath.tcltk) - $(tcltkDir)bin - DLLs\ - tcltk_dlls - - - $(tcltkDir) - !(bindpath.tcltk) - $(tcltkDir)bin - DLLs\ - tcltk_dlls_d - - - - $(tcltkDir) - !(bindpath.tcltk) - $(tcltkDir)lib - tcl\ - tcltk_lib - - - - $(PySourcePath) - !(bindpath.src) - $(PySourcePath) - - tkinter_lib - - - - - \ No newline at end of file diff --git a/Tools/msi/tcltk/tcltk.wixproj b/Tools/msi/tcltk/tcltk.wixproj --- a/Tools/msi/tcltk/tcltk.wixproj +++ b/Tools/msi/tcltk/tcltk.wixproj @@ -5,7 +5,45 @@ 2.0 tcltk Package - IncludeDefaultFeature=1;$(DefineConstants) - + + + ICE43 + + + + + + + + + + + + $(tcltkDir) + !(bindpath.tcltk) + $(tcltkDir)bin + DLLs\ + tcltk_dlls + + + + $(tcltkDir) + !(bindpath.tcltk) + $(tcltkDir)lib + tcl\ + tcltk_lib + + + + $(PySourcePath) + !(bindpath.src) + $(PySourcePath) + + tkinter_lib + + + + \ No newline at end of file diff --git a/Tools/msi/tcltk/tcltk.wxs b/Tools/msi/tcltk/tcltk.wxs --- a/Tools/msi/tcltk/tcltk.wxs +++ b/Tools/msi/tcltk/tcltk.wxs @@ -15,7 +15,6 @@ PYTHON_EXE - @@ -37,17 +36,5 @@ - - - - - - - - - - - - diff --git a/Tools/msi/tcltk/tcltk_d.wixproj b/Tools/msi/tcltk/tcltk_d.wixproj --- a/Tools/msi/tcltk/tcltk_d.wixproj +++ b/Tools/msi/tcltk/tcltk_d.wixproj @@ -5,7 +5,24 @@ 2.0 tcltk_d Package - IncludeDebugBinaries=1;$(DefineConstants) - + + + + + + + + + + + $(tcltkDir) + !(bindpath.tcltk) + $(tcltkDir)bin + DLLs\ + tcltk_dlls_d + + + + \ No newline at end of file diff --git a/Tools/msi/tcltk/tcltk_d.wxs b/Tools/msi/tcltk/tcltk_d.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk_d.wxs @@ -0,0 +1,14 @@ +? + + + + + + + + + + + + + diff --git a/Tools/msi/tcltk/tcltk_pdb.wixproj b/Tools/msi/tcltk/tcltk_pdb.wixproj --- a/Tools/msi/tcltk/tcltk_pdb.wixproj +++ b/Tools/msi/tcltk/tcltk_pdb.wixproj @@ -5,7 +5,15 @@ 2.0 tcltk_pdb Package - IncludeSymbols=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/tcltk/tcltk_pdb.wxs b/Tools/msi/tcltk/tcltk_pdb.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/tcltk/tcltk_pdb.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/test/test.props b/Tools/msi/test/test.props deleted file mode 100644 --- a/Tools/msi/test/test.props +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - $(PySourcePath) - !(bindpath.src) - $(PySourcePath) - - test_py - - - - - \ No newline at end of file diff --git a/Tools/msi/test/test.wixproj b/Tools/msi/test/test.wixproj --- a/Tools/msi/test/test.wixproj +++ b/Tools/msi/test/test.wixproj @@ -5,7 +5,25 @@ 2.0 test Package - IncludeDefaultFeature=1;$(DefineConstants) - + + + + + + + + + + + $(PySourcePath) + !(bindpath.src) + $(PySourcePath) + + test_py + + + + \ No newline at end of file diff --git a/Tools/msi/test/test.wxs b/Tools/msi/test/test.wxs --- a/Tools/msi/test/test.wxs +++ b/Tools/msi/test/test.wxs @@ -7,21 +7,9 @@ - - - - - - - - - - - - diff --git a/Tools/msi/test/test_d.wixproj b/Tools/msi/test/test_d.wixproj --- a/Tools/msi/test/test_d.wixproj +++ b/Tools/msi/test/test_d.wixproj @@ -5,7 +5,15 @@ 2.0 test_d Package - IncludeDebugBinaries=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/test/test_d.wxs b/Tools/msi/test/test_d.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test_d.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/test/test_pdb.wixproj b/Tools/msi/test/test_pdb.wixproj --- a/Tools/msi/test/test_pdb.wixproj +++ b/Tools/msi/test/test_pdb.wixproj @@ -5,7 +5,15 @@ 2.0 test_pdb Package - IncludeSymbols=1;$(DefineConstants) - + + + + + + + + + + \ No newline at end of file diff --git a/Tools/msi/test/test_pdb.wxs b/Tools/msi/test/test_pdb.wxs new file mode 100644 --- /dev/null +++ b/Tools/msi/test/test_pdb.wxs @@ -0,0 +1,13 @@ +? + + + + + + + + + + + + diff --git a/Tools/msi/tools/tools.wixproj b/Tools/msi/tools/tools.wixproj --- a/Tools/msi/tools/tools.wixproj +++ b/Tools/msi/tools/tools.wixproj @@ -8,7 +8,8 @@ - + + -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 21:08:20 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 14 Feb 2015 20:08:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323437=3A_Update_N?= =?utf-8?q?EWS_and_whatsnew/3=2E5?= Message-ID: <20150214200818.62565.50072@psf.io> https://hg.python.org/cpython/rev/a2217106ca5e changeset: 94610:a2217106ca5e user: Steve Dower date: Sat Feb 14 12:07:59 2015 -0800 summary: Issue #23437: Update NEWS and whatsnew/3.5 files: Doc/whatsnew/3.5.rst | 7 +++++++ Misc/NEWS | 6 ++++++ 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -342,6 +342,13 @@ :meth:`socket.socket.send`. (Contributed by Giampaolo Rodola' in :issue:`17552`.) +sysconfig +--------- + +* The user scripts directory on Windows is now versioned. + (Contributed by Paul Moore in :issue:`23437`.) + + tarfile ------- diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -39,6 +39,12 @@ - Issue #23445: pydebug builds now use "gcc -Og" where possible, to make the resulting executable faster. +Windows +------- + +- Issue #23437: Make user scripts directory versioned on Windows. Patch by Paul + Moore. + What's New in Python 3.5 alpha 1? ================================= -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 21:17:52 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 14 Feb 2015 20:17:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_avoid_reading_?= =?utf-8?q?unallocated_memory_when_argc_=3D=3D_0_=28closes_=2322633=29?= Message-ID: <20150214201751.126598.36927@psf.io> https://hg.python.org/cpython/rev/687b970c8ba9 changeset: 94612:687b970c8ba9 branch: 2.7 parent: 94599:a4a3a8b3f37f user: Benjamin Peterson date: Sat Feb 14 15:17:25 2015 -0500 summary: avoid reading unallocated memory when argc == 0 (closes #22633) files: Python/frozenmain.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -35,7 +35,8 @@ #ifdef MS_WINDOWS PyInitFrozenExtensions(); #endif /* MS_WINDOWS */ - Py_SetProgramName(argv[0]); + if (argc >= 1) + Py_SetProgramName(argv[0]); Py_Initialize(); #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 21:17:52 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 14 Feb 2015 20:17:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_avoid_reading_?= =?utf-8?q?unallocated_memory_when_argc_=3D=3D_0_=28closes_=2322633=29?= Message-ID: <20150214201751.71238.92307@psf.io> https://hg.python.org/cpython/rev/d0b6efed4766 changeset: 94611:d0b6efed4766 branch: 3.4 parent: 94602:d2dbec7d74d0 user: Benjamin Peterson date: Sat Feb 14 15:16:32 2015 -0500 summary: avoid reading unallocated memory when argc == 0 (closes #22633) files: Python/frozenmain.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -24,11 +24,13 @@ /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2 = NULL; - argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - goto error; + if (argc > 0) { + argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + goto error; + } } Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ @@ -68,7 +70,8 @@ #ifdef MS_WINDOWS PyInitFrozenExtensions(); #endif /* MS_WINDOWS */ - Py_SetProgramName(argv_copy[0]); + if (argc >= 1) + Py_SetProgramName(argv_copy[0]); Py_Initialize(); #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 21:17:52 2015 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 14 Feb 2015 20:17:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI2MzMp?= Message-ID: <20150214201751.62563.49727@psf.io> https://hg.python.org/cpython/rev/ba2da33d2654 changeset: 94613:ba2da33d2654 parent: 94610:a2217106ca5e parent: 94611:d0b6efed4766 user: Benjamin Peterson date: Sat Feb 14 15:17:47 2015 -0500 summary: merge 3.4 (#22633) files: Python/frozenmain.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -24,11 +24,13 @@ /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2 = NULL; - argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - goto error; + if (argc > 0) { + argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + goto error; + } } Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ @@ -68,7 +70,8 @@ #ifdef MS_WINDOWS PyInitFrozenExtensions(); #endif /* MS_WINDOWS */ - Py_SetProgramName(argv_copy[0]); + if (argc >= 1) + Py_SetProgramName(argv_copy[0]); Py_Initialize(); #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 21:49:27 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 20:49:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODQ0?= =?utf-8?q?=3A_Fized_test=5Fgdb_failure_on_Debian_Wheezy_for_Z=2E?= Message-ID: <20150214204926.60736.41566@psf.io> https://hg.python.org/cpython/rev/ae5d868513fd changeset: 94614:ae5d868513fd branch: 3.4 parent: 94611:d0b6efed4766 user: Serhiy Storchaka date: Sat Feb 14 22:44:35 2015 +0200 summary: Issue #22844: Fized test_gdb failure on Debian Wheezy for Z. Patch by David Edelsohn. files: Lib/test/test_gdb.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -190,6 +190,8 @@ 'linux-vdso.so', 'warning: Could not load shared library symbols for ' 'linux-gate.so', + 'warning: Could not load shared library symbols for ' + 'linux-vdso64.so', 'Do you need "set solib-search-path" or ' '"set sysroot"?', 'warning: Source file is more recent than executable.', -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 21:49:27 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 20:49:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyODQ0?= =?utf-8?q?=3A_Fized_test=5Fgdb_failure_on_Debian_Wheezy_for_Z=2E?= Message-ID: <20150214204927.71232.33124@psf.io> https://hg.python.org/cpython/rev/eb3a6243af33 changeset: 94616:eb3a6243af33 branch: 2.7 parent: 94612:687b970c8ba9 user: Serhiy Storchaka date: Sat Feb 14 22:44:35 2015 +0200 summary: Issue #22844: Fized test_gdb failure on Debian Wheezy for Z. Patch by David Edelsohn. files: Lib/test/test_gdb.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -185,6 +185,8 @@ 'linux-vdso.so', 'warning: Could not load shared library symbols for ' 'linux-gate.so', + 'warning: Could not load shared library symbols for ' + 'linux-vdso64.so', 'Do you need "set solib-search-path" or ' '"set sysroot"?', 'warning: Source file is more recent than executable.', -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 21:49:27 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 20:49:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322844=3A_Fized_test=5Fgdb_failure_on_Debian_Whe?= =?utf-8?q?ezy_for_Z=2E?= Message-ID: <20150214204926.62577.1225@psf.io> https://hg.python.org/cpython/rev/df696b544b3c changeset: 94615:df696b544b3c parent: 94613:ba2da33d2654 parent: 94614:ae5d868513fd user: Serhiy Storchaka date: Sat Feb 14 22:45:15 2015 +0200 summary: Issue #22844: Fized test_gdb failure on Debian Wheezy for Z. Patch by David Edelsohn. files: Lib/test/test_gdb.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -190,6 +190,8 @@ 'linux-vdso.so', 'warning: Could not load shared library symbols for ' 'linux-gate.so', + 'warning: Could not load shared library symbols for ' + 'linux-vdso64.so', 'Do you need "set solib-search-path" or ' '"set sysroot"?', 'warning: Source file is more recent than executable.', -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 22:17:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 21:17:57 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317753=3A_Skip_test=5Fzipfile_tests_which_requir?= =?utf-8?q?e_write_access_to_test?= Message-ID: <20150214211755.126612.96959@psf.io> https://hg.python.org/cpython/rev/174f24d33bfe changeset: 94618:174f24d33bfe parent: 94615:df696b544b3c parent: 94617:6ad5909319e0 user: Serhiy Storchaka date: Sat Feb 14 23:06:42 2015 +0200 summary: Issue #17753: Skip test_zipfile tests which require write access to test and email.test. files: Lib/test/test_zipfile.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -679,7 +679,12 @@ if name + 'o' not in namelist: self.assertIn(name + 'c', namelist) + def requiresWriteAccess(self, path): + if not os.access(path, os.W_OK, effective_ids=True): + self.skipTest('requires write access to the installed location') + def test_write_pyfile(self): + self.requiresWriteAccess(os.path.dirname(__file__)) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): @@ -711,6 +716,7 @@ def test_write_python_package(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: zipfp.writepy(packagedir) @@ -724,6 +730,7 @@ def test_write_filtered_python_package(self): import test packagedir = os.path.dirname(test.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: @@ -752,6 +759,7 @@ def test_write_with_optimization(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) # use .pyc if running test in optimization mode, # use .pyo if running test in debug mode optlevel = 1 if __debug__ else 0 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 22:17:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 21:17:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE3NzUz?= =?utf-8?q?=3A_Skip_test=5Fzipfile_tests_which_require_write_access_to_tes?= =?utf-8?q?t?= Message-ID: <20150214211754.62557.58706@psf.io> https://hg.python.org/cpython/rev/6ad5909319e0 changeset: 94617:6ad5909319e0 branch: 3.4 parent: 94614:ae5d868513fd user: Serhiy Storchaka date: Sat Feb 14 23:04:35 2015 +0200 summary: Issue #17753: Skip test_zipfile tests which require write access to test and email.test. files: Lib/test/test_zipfile.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -648,7 +648,12 @@ if name + 'o' not in namelist: self.assertIn(name + 'c', namelist) + def requiresWriteAccess(self, path): + if not os.access(path, os.W_OK, effective_ids=True): + self.skipTest('requires write access to the installed location') + def test_write_pyfile(self): + self.requiresWriteAccess(os.path.dirname(__file__)) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): @@ -680,6 +685,7 @@ def test_write_python_package(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: zipfp.writepy(packagedir) @@ -693,6 +699,7 @@ def test_write_filtered_python_package(self): import test packagedir = os.path.dirname(test.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: @@ -721,6 +728,7 @@ def test_write_with_optimization(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) # use .pyc if running test in optimization mode, # use .pyo if running test in debug mode optlevel = 1 if __debug__ else 0 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 22:17:57 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 14 Feb 2015 21:17:57 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NzUz?= =?utf-8?q?=3A_Skip_test=5Fzipfile_tests_which_require_write_access_to_tes?= =?utf-8?q?t?= Message-ID: <20150214211755.71224.46275@psf.io> https://hg.python.org/cpython/rev/dfe75713f152 changeset: 94619:dfe75713f152 branch: 2.7 parent: 94616:eb3a6243af33 user: Serhiy Storchaka date: Sat Feb 14 23:17:13 2015 +0200 summary: Issue #17753: Skip test_zipfile tests which require write access to test and email.test. files: Lib/test/test_zipfile.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -775,7 +775,12 @@ class PyZipFileTests(unittest.TestCase): + def requiresWriteAccess(self, path): + if not os.access(path, os.W_OK): + self.skipTest('requires write access to the installed location') + def test_write_pyfile(self): + self.requiresWriteAccess(os.path.dirname(__file__)) with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp: fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): @@ -803,6 +808,7 @@ def test_write_python_package(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp: zipfp.writepy(packagedir) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 23:05:49 2015 From: python-checkins at python.org (berker.peksag) Date: Sat, 14 Feb 2015 22:05:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2313637=3A_Remove_outdated_versionchanged_directi?= =?utf-8?q?ves=2E?= Message-ID: <20150214220536.71236.61241@psf.io> https://hg.python.org/cpython/rev/d3ca674cf716 changeset: 94621:d3ca674cf716 parent: 94618:174f24d33bfe parent: 94620:8d32453dd0f7 user: Berker Peksag date: Sun Feb 15 00:06:07 2015 +0200 summary: Issue #13637: Remove outdated versionchanged directives. Patch by Martin Panter. files: Doc/library/binascii.rst | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -65,9 +65,6 @@ data. More than one line may be passed at a time. If the optional argument *header* is present and true, underscores will be decoded as spaces. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. function:: b2a_qp(data, quotetabs=False, istext=True, header=False) @@ -156,9 +153,6 @@ of hexadecimal digits (which can be upper or lower case), otherwise a :exc:`TypeError` is raised. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. exception:: Error -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 23:05:49 2015 From: python-checkins at python.org (berker.peksag) Date: Sat, 14 Feb 2015 22:05:49 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzEzNjM3?= =?utf-8?q?=3A_Remove_outdated_versionchanged_directives=2E?= Message-ID: <20150214220536.72279.2309@psf.io> https://hg.python.org/cpython/rev/8d32453dd0f7 changeset: 94620:8d32453dd0f7 branch: 3.4 parent: 94617:6ad5909319e0 user: Berker Peksag date: Sun Feb 15 00:05:42 2015 +0200 summary: Issue #13637: Remove outdated versionchanged directives. Patch by Martin Panter. files: Doc/library/binascii.rst | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -65,9 +65,6 @@ data. More than one line may be passed at a time. If the optional argument *header* is present and true, underscores will be decoded as spaces. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. function:: b2a_qp(data, quotetabs=False, istext=True, header=False) @@ -156,9 +153,6 @@ of hexadecimal digits (which can be upper or lower case), otherwise a :exc:`TypeError` is raised. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. exception:: Error -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 23:31:20 2015 From: python-checkins at python.org (berker.peksag) Date: Sat, 14 Feb 2015 22:31:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2313637=3A_Improve_exception_message_of_a2b=5F*_f?= =?utf-8?q?unctions=2E?= Message-ID: <20150214223055.60736.66143@psf.io> https://hg.python.org/cpython/rev/55f5e960cc40 changeset: 94623:55f5e960cc40 parent: 94621:d3ca674cf716 parent: 94622:ad4a8176a71a user: Berker Peksag date: Sun Feb 15 00:31:26 2015 +0200 summary: Issue #13637: Improve exception message of a2b_* functions. Patch by Vajrasky Kok. files: Modules/binascii.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -228,13 +228,13 @@ if (PyObject_GetBuffer(arg, buf, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "argument should be bytes, buffer or ASCII string, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); return 0; } if (!PyBuffer_IsContiguous(buf, 'C')) { PyErr_Format(PyExc_TypeError, "argument should be a contiguous buffer, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); PyBuffer_Release(buf); return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 23:31:20 2015 From: python-checkins at python.org (berker.peksag) Date: Sat, 14 Feb 2015 22:31:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzEzNjM3?= =?utf-8?q?=3A_Improve_exception_message_of_a2b=5F*_functions=2E?= Message-ID: <20150214223055.71250.65403@psf.io> https://hg.python.org/cpython/rev/ad4a8176a71a changeset: 94622:ad4a8176a71a branch: 3.4 parent: 94620:8d32453dd0f7 user: Berker Peksag date: Sun Feb 15 00:31:00 2015 +0200 summary: Issue #13637: Improve exception message of a2b_* functions. Patch by Vajrasky Kok. files: Modules/binascii.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -228,13 +228,13 @@ if (PyObject_GetBuffer(arg, buf, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "argument should be bytes, buffer or ASCII string, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); return 0; } if (!PyBuffer_IsContiguous(buf, 'C')) { PyErr_Format(PyExc_TypeError, "argument should be a contiguous buffer, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); PyBuffer_Release(buf); return 0; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 14 23:45:28 2015 From: python-checkins at python.org (berker.peksag) Date: Sat, 14 Feb 2015 22:45:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_a_whatsnew_entry_for_i?= =?utf-8?q?ssue_=2322003=2E?= Message-ID: <20150214224525.60724.43806@psf.io> https://hg.python.org/cpython/rev/7ae156f07a90 changeset: 94624:7ae156f07a90 user: Berker Peksag date: Sun Feb 15 00:45:57 2015 +0200 summary: Add a whatsnew entry for issue #22003. Patch by David Wilson. files: Doc/whatsnew/3.5.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -400,7 +400,8 @@ (:issue:`21486`, :issue:`21487`, :issue:`20826`) * Many operations on :class:`io.BytesIO` are now 50% to 100% faster. - (Contributed by Serhiy Storchaka in :issue:`15381`.) + (Contributed by Serhiy Storchaka in :issue:`15381` and David Wilson in + :issue:`22003`.) * :func:`marshal.dumps` is now faster (65%-85% with versions 3--4, 20-25% with versions 0--2 on typical data, and up to 5x in best cases). -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Feb 15 06:43:59 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 15 Feb 2015 06:43:59 +0100 Subject: [Python-checkins] Daily reference leaks (7ae156f07a90): sum=1415 Message-ID: results for 7ae156f07a90 on branch "default" -------------------------------------------- test_asyncio leaked [388, 388, 388] references, sum=1164 test_asyncio leaked [84, 85, 85] memory blocks, sum=254 test_collections leaked [-4, 0, 0] references, sum=-4 test_collections leaked [-2, 0, 0] memory blocks, sum=-2 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloglbltRM', '-x'] From python-checkins at python.org Sun Feb 15 12:26:47 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 11:26:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxOTM0?= =?utf-8?q?=3A_test=5Ffile2k_no_longer_create_regular_file_/dev/full_on_Op?= =?utf-8?q?enBSD?= Message-ID: <20150215112646.62567.51995@psf.io> https://hg.python.org/cpython/rev/354c3b65e245 changeset: 94625:354c3b65e245 branch: 2.7 parent: 94619:dfe75713f152 user: Serhiy Storchaka date: Sun Feb 15 13:05:10 2015 +0200 summary: Issue #21934: test_file2k no longer create regular file /dev/full on OpenBSD when run as root. Extended testing with /dev/full. Based on patch by Daniel Dickman. files: Lib/test/test_file2k.py | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py --- a/Lib/test/test_file2k.py +++ b/Lib/test/test_file2k.py @@ -4,6 +4,7 @@ import itertools import select import signal +import stat import subprocess import time from array import array @@ -430,17 +431,22 @@ @unittest.skipUnless(os.name == 'posix', 'test requires a posix system.') def test_write_full(self): - # Issue #17976 - try: - f = open('/dev/full', 'w', 1) - except IOError: - self.skipTest("requires '/dev/full'") - try: + devfull = '/dev/full' + if not (os.path.exists(devfull) and + stat.S_ISCHR(os.stat(devfull).st_mode)): + # Issue #21934: OpenBSD does not have a /dev/full character device + self.skipTest('requires %r' % devfull) + with open(devfull, 'wb', 1) as f: with self.assertRaises(IOError): + f.write('hello\n') + with open(devfull, 'wb', 1) as f: + with self.assertRaises(IOError): + # Issue #17976 f.write('hello') f.write('\n') - finally: - f.close() + with open(devfull, 'wb', 0) as f: + with self.assertRaises(IOError): + f.write('h') @unittest.skipUnless(sys.maxsize > 2**31, "requires 64-bit system") @test_support.precisionbigmemtest(2**31, 2.5, dry_run=False) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 13:39:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 12:39:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323096=3A_Pickle_r?= =?utf-8?q?epresentation_of_floats_with_protocol_0_now_is_the_same?= Message-ID: <20150215123418.62579.26598@psf.io> https://hg.python.org/cpython/rev/8c9121993eb5 changeset: 94632:8c9121993eb5 user: Serhiy Storchaka date: Sun Feb 15 14:18:32 2015 +0200 summary: Issue #23096: Pickle representation of floats with protocol 0 now is the same for both Python and C implementations. files: Misc/NEWS | 3 +++ Modules/_pickle.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #23096: Pickle representation of floats with protocol 0 now is the same + for both Python and C implementations. + - Issue #19105: pprint now more efficiently uses free space at the right. - Issue #14910: Add allow_abbrev parameter to argparse.ArgumentParser. Patch by diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1979,7 +1979,7 @@ if (_Pickler_Write(self, &op, 1) < 0) goto done; - buf = PyOS_double_to_string(x, 'g', 17, 0, NULL); + buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); if (!buf) { PyErr_NoMemory(); goto done; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 13:39:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 12:39:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogVXNlIG9zLmRldm51?= =?utf-8?q?ll_instead_of_hardcoded_=27/dev/null=27=2E?= Message-ID: <20150215123416.71242.18249@psf.io> https://hg.python.org/cpython/rev/7d2018774925 changeset: 94626:7d2018774925 branch: 2.7 user: Serhiy Storchaka date: Sun Feb 15 13:57:49 2015 +0200 summary: Use os.devnull instead of hardcoded '/dev/null'. files: Lib/test/test_cgi.py | 4 ++-- Lib/test/test_sysconfig.py | 4 ++-- Tools/compiler/compile.py | 7 ++----- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -194,9 +194,9 @@ cgi.initlog("%s", "Testing initlog 1") cgi.log("%s", "Testing log 2") self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n") - if os.path.exists("/dev/null"): + if os.path.exists(os.devnull): cgi.logfp = None - cgi.logfile = "/dev/null" + cgi.logfile = os.devnull cgi.initlog("%s", "Testing log 3") cgi.log("Testing log 4") diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -294,7 +294,7 @@ if 'MACOSX_DEPLOYMENT_TARGET' in env: del env['MACOSX_DEPLOYMENT_TARGET'] - with open('/dev/null', 'w') as devnull_fp: + with open(os.devnull, 'w') as devnull_fp: p = subprocess.Popen([ sys.executable, '-c', 'import sysconfig; print(sysconfig.get_platform())', @@ -320,7 +320,7 @@ 'import sysconfig; print(sysconfig.get_platform())', ], stdout=subprocess.PIPE, - stderr=open('/dev/null'), + stderr=open(os.devnull), env=env) test_platform = p.communicate()[0].strip() test_platform = test_platform.decode('utf-8') diff --git a/Tools/compiler/compile.py b/Tools/compiler/compile.py --- a/Tools/compiler/compile.py +++ b/Tools/compiler/compile.py @@ -1,3 +1,4 @@ +import os import sys import getopt @@ -16,11 +17,7 @@ VERBOSE = 1 visitor.ASTVisitor.VERBOSE = visitor.ASTVisitor.VERBOSE + 1 if k == '-q': - if sys.platform[:3]=="win": - f = open('nul', 'wb') # /dev/null fails on Windows... - else: - f = open('/dev/null', 'wb') - sys.stdout = f + sys.stdout = open(os.devnull, 'wb') if k == '-d': DISPLAY = 1 if k == '-c': -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 13:39:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 12:39:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Use_os=2Edevnull_instead_of_hardcoded_=27/dev/null=27=2E?= Message-ID: <20150215123417.62569.30552@psf.io> https://hg.python.org/cpython/rev/56ededda3335 changeset: 94629:56ededda3335 parent: 94624:7ae156f07a90 parent: 94628:7072bbe16a06 user: Serhiy Storchaka date: Sun Feb 15 14:03:11 2015 +0200 summary: Use os.devnull instead of hardcoded '/dev/null'. files: Lib/test/test_asyncio/test_unix_events.py | 6 +++--- Lib/test/test_bz2.py | 10 +++++----- Lib/test/test_cgi.py | 4 ++-- Lib/test/test_subprocess.py | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -295,7 +295,7 @@ def test_create_unix_connection_path_sock(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', sock=object()) + lambda: None, os.devnull, sock=object()) with self.assertRaisesRegex(ValueError, 'path and sock can not be'): self.loop.run_until_complete(coro) @@ -308,14 +308,14 @@ def test_create_unix_connection_nossl_serverhost(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', server_hostname='spam') + lambda: None, os.devnull, server_hostname='spam') with self.assertRaisesRegex(ValueError, 'server_hostname is only meaningful'): self.loop.run_until_complete(coro) def test_create_unix_connection_ssl_noserverhost(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', ssl=True) + lambda: None, os.devnull, ssl=True) with self.assertRaisesRegex( ValueError, 'you have to pass server_hostname when using ssl'): diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -87,11 +87,11 @@ def testBadArgs(self): self.assertRaises(TypeError, BZ2File, 123.456) - self.assertRaises(ValueError, BZ2File, "/dev/null", "z") - self.assertRaises(ValueError, BZ2File, "/dev/null", "rx") - self.assertRaises(ValueError, BZ2File, "/dev/null", "rbt") - self.assertRaises(ValueError, BZ2File, "/dev/null", compresslevel=0) - self.assertRaises(ValueError, BZ2File, "/dev/null", compresslevel=10) + self.assertRaises(ValueError, BZ2File, os.devnull, "z") + self.assertRaises(ValueError, BZ2File, os.devnull, "rx") + self.assertRaises(ValueError, BZ2File, os.devnull, "rbt") + self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=0) + self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=10) def testRead(self): self.createTempFile() diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -186,9 +186,9 @@ cgi.initlog("%s", "Testing initlog 1") cgi.log("%s", "Testing log 2") self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n") - if os.path.exists("/dev/null"): + if os.path.exists(os.devnull): cgi.logfp = None - cgi.logfile = "/dev/null" + cgi.logfile = os.devnull cgi.initlog("%s", "Testing log 3") self.addCleanup(cgi.closelog) cgi.log("Testing log 4") diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1922,7 +1922,7 @@ open_fds = set(fds) # add a bunch more fds for _ in range(9): - fd = os.open("/dev/null", os.O_RDONLY) + fd = os.open(os.devnull, os.O_RDONLY) self.addCleanup(os.close, fd) open_fds.add(fd) @@ -1984,7 +1984,7 @@ open_fds = set() # Add a bunch more fds to pass down. for _ in range(40): - fd = os.open("/dev/null", os.O_RDONLY) + fd = os.open(os.devnull, os.O_RDONLY) open_fds.add(fd) # Leave a two pairs of low ones available for use by the -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 13:39:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 12:39:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogVXNlIG9zLmRldm51?= =?utf-8?q?ll_instead_of_hardcoded_=27/dev/null=27=2E?= Message-ID: <20150215123416.126612.76785@psf.io> https://hg.python.org/cpython/rev/8bb36e8a952e changeset: 94627:8bb36e8a952e branch: 3.4 parent: 94600:908533d5a427 user: Serhiy Storchaka date: Sun Feb 15 13:58:23 2015 +0200 summary: Use os.devnull instead of hardcoded '/dev/null'. files: Lib/test/test_asyncio/test_unix_events.py | 6 +++--- Lib/test/test_bz2.py | 10 +++++----- Lib/test/test_cgi.py | 4 ++-- Lib/test/test_subprocess.py | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -295,7 +295,7 @@ def test_create_unix_connection_path_sock(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', sock=object()) + lambda: None, os.devnull, sock=object()) with self.assertRaisesRegex(ValueError, 'path and sock can not be'): self.loop.run_until_complete(coro) @@ -308,14 +308,14 @@ def test_create_unix_connection_nossl_serverhost(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', server_hostname='spam') + lambda: None, os.devnull, server_hostname='spam') with self.assertRaisesRegex(ValueError, 'server_hostname is only meaningful'): self.loop.run_until_complete(coro) def test_create_unix_connection_ssl_noserverhost(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', ssl=True) + lambda: None, os.devnull, ssl=True) with self.assertRaisesRegex( ValueError, 'you have to pass server_hostname when using ssl'): diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -87,11 +87,11 @@ def testBadArgs(self): self.assertRaises(TypeError, BZ2File, 123.456) - self.assertRaises(ValueError, BZ2File, "/dev/null", "z") - self.assertRaises(ValueError, BZ2File, "/dev/null", "rx") - self.assertRaises(ValueError, BZ2File, "/dev/null", "rbt") - self.assertRaises(ValueError, BZ2File, "/dev/null", compresslevel=0) - self.assertRaises(ValueError, BZ2File, "/dev/null", compresslevel=10) + self.assertRaises(ValueError, BZ2File, os.devnull, "z") + self.assertRaises(ValueError, BZ2File, os.devnull, "rx") + self.assertRaises(ValueError, BZ2File, os.devnull, "rbt") + self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=0) + self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=10) def testRead(self): self.createTempFile() diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -186,9 +186,9 @@ cgi.initlog("%s", "Testing initlog 1") cgi.log("%s", "Testing log 2") self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n") - if os.path.exists("/dev/null"): + if os.path.exists(os.devnull): cgi.logfp = None - cgi.logfile = "/dev/null" + cgi.logfile = os.devnull cgi.initlog("%s", "Testing log 3") self.addCleanup(cgi.closelog) cgi.log("Testing log 4") diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1922,7 +1922,7 @@ open_fds = set(fds) # add a bunch more fds for _ in range(9): - fd = os.open("/dev/null", os.O_RDONLY) + fd = os.open(os.devnull, os.O_RDONLY) self.addCleanup(os.close, fd) open_fds.add(fd) @@ -1984,7 +1984,7 @@ open_fds = set() # Add a bunch more fds to pass down. for _ in range(40): - fd = os.open("/dev/null", os.O_RDONLY) + fd = os.open(os.devnull, os.O_RDONLY) open_fds.add(fd) # Leave a two pairs of low ones available for use by the -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 13:39:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 12:39:23 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNCk6?= =?utf-8?q?_Merge_heads?= Message-ID: <20150215123417.126604.7308@psf.io> https://hg.python.org/cpython/rev/7072bbe16a06 changeset: 94628:7072bbe16a06 branch: 3.4 parent: 94627:8bb36e8a952e parent: 94622:ad4a8176a71a user: Serhiy Storchaka date: Sun Feb 15 14:02:15 2015 +0200 summary: Merge heads files: Doc/library/binascii.rst | 6 ------ Lib/http/server.py | 5 ++++- Lib/test/test_gdb.py | 2 ++ Lib/test/test_httpservers.py | 14 ++++++++++++++ Lib/test/test_zipfile.py | 8 ++++++++ Modules/binascii.c | 4 ++-- Python/frozenmain.c | 15 +++++++++------ 7 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -65,9 +65,6 @@ data. More than one line may be passed at a time. If the optional argument *header* is present and true, underscores will be decoded as spaces. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. function:: b2a_qp(data, quotetabs=False, istext=True, header=False) @@ -156,9 +153,6 @@ of hexadecimal digits (which can be upper or lower case), otherwise a :exc:`TypeError` is raised. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. exception:: Error diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -82,7 +82,10 @@ __version__ = "0.6" -__all__ = ["HTTPServer", "BaseHTTPRequestHandler"] +__all__ = [ + "HTTPServer", "BaseHTTPRequestHandler", + "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler", +] import html import http.client diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -190,6 +190,8 @@ 'linux-vdso.so', 'warning: Could not load shared library symbols for ' 'linux-gate.so', + 'warning: Could not load shared library symbols for ' + 'linux-vdso64.so', 'Do you need "set solib-search-path" or ' '"set sysroot"?', 'warning: Source file is more recent than executable.', diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -760,6 +760,19 @@ self.assertEqual(path, self.translated) +class MiscTestCase(unittest.TestCase): + def test_all(self): + expected = [] + blacklist = {'executable', 'nobody_uid', 'test'} + for name in dir(server): + if name.startswith('_') or name in blacklist: + continue + module_object = getattr(server, name) + if getattr(module_object, '__module__', None) == 'http.server': + expected.append(name) + self.assertCountEqual(server.__all__, expected) + + def test_main(verbose=None): cwd = os.getcwd() try: @@ -769,6 +782,7 @@ SimpleHTTPServerTestCase, CGIHTTPServerTestCase, SimpleHTTPRequestHandlerTestCase, + MiscTestCase, ) finally: os.chdir(cwd) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -648,7 +648,12 @@ if name + 'o' not in namelist: self.assertIn(name + 'c', namelist) + def requiresWriteAccess(self, path): + if not os.access(path, os.W_OK, effective_ids=True): + self.skipTest('requires write access to the installed location') + def test_write_pyfile(self): + self.requiresWriteAccess(os.path.dirname(__file__)) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): @@ -680,6 +685,7 @@ def test_write_python_package(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: zipfp.writepy(packagedir) @@ -693,6 +699,7 @@ def test_write_filtered_python_package(self): import test packagedir = os.path.dirname(test.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: @@ -721,6 +728,7 @@ def test_write_with_optimization(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) # use .pyc if running test in optimization mode, # use .pyo if running test in debug mode optlevel = 1 if __debug__ else 0 diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -228,13 +228,13 @@ if (PyObject_GetBuffer(arg, buf, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "argument should be bytes, buffer or ASCII string, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); return 0; } if (!PyBuffer_IsContiguous(buf, 'C')) { PyErr_Format(PyExc_TypeError, "argument should be a contiguous buffer, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); PyBuffer_Release(buf); return 0; } diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -24,11 +24,13 @@ /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2 = NULL; - argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - goto error; + if (argc > 0) { + argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + goto error; + } } Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ @@ -68,7 +70,8 @@ #ifdef MS_WINDOWS PyInitFrozenExtensions(); #endif /* MS_WINDOWS */ - Py_SetProgramName(argv_copy[0]); + if (argc >= 1) + Py_SetProgramName(argv_copy[0]); Py_Initialize(); #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 13:39:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 12:39:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Use_pickled_data_compatible_with_Python_2_for_testing_pr?= =?utf-8?q?otocols_0-2=2E?= Message-ID: <20150215123418.71242.27972@psf.io> https://hg.python.org/cpython/rev/3e4ed1a23cfc changeset: 94631:3e4ed1a23cfc parent: 94629:56ededda3335 parent: 94630:d92a067464a0 user: Serhiy Storchaka date: Sun Feb 15 14:10:24 2015 +0200 summary: Use pickled data compatible with Python 2 for testing protocols 0-2. files: Lib/test/pickletester.py | 433 +++++++++++++------------- 1 files changed, 217 insertions(+), 216 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -144,21 +144,22 @@ # the object returned by create_data(). DATA0 = ( - b'(lp0\nL0L\naL1L\naF2.0\nac' - b'builtins\ncomplex\n' - b'p1\n(F3.0\nF0.0\ntp2\nRp' - b'3\naL1L\naL-1L\naL255L\naL-' - b'255L\naL-256L\naL65535L\na' - b'L-65535L\naL-65536L\naL2' - b'147483647L\naL-2147483' - b'647L\naL-2147483648L\na(' - b'Vabc\np4\ng4\nccopyreg' - b'\n_reconstructor\np5\n(' - b'c__main__\nC\np6\ncbu' - b'iltins\nobject\np7\nNt' - b'p8\nRp9\n(dp10\nVfoo\np1' - b'1\nL1L\nsVbar\np12\nL2L\nsb' - b'g9\ntp13\nag13\naL5L\na.' + b'(lp0\nL0L\naL1L\naF2.0\n' + b'ac__builtin__\ncomple' + b'x\np1\n(F3.0\nF0.0\ntp2\n' + b'Rp3\naL1L\naL-1L\naL255' + b'L\naL-255L\naL-256L\naL' + b'65535L\naL-65535L\naL-' + b'65536L\naL2147483647L' + b'\naL-2147483647L\naL-2' + b'147483648L\na(Vabc\np4' + b'\ng4\nccopy_reg\n_recon' + b'structor\np5\n(c__main' + b'__\nC\np6\nc__builtin__' + b'\nobject\np7\nNtp8\nRp9\n' + b'(dp10\nVfoo\np11\nL1L\ns' + b'Vbar\np12\nL2L\nsbg9\ntp' + b'13\nag13\naL5L\na.' ) # Disassembly of DATA0 @@ -172,88 +173,88 @@ 14: a APPEND 15: F FLOAT 2.0 20: a APPEND - 21: c GLOBAL 'builtins complex' - 39: p PUT 1 - 42: ( MARK - 43: F FLOAT 3.0 - 48: F FLOAT 0.0 - 53: t TUPLE (MARK at 42) - 54: p PUT 2 - 57: R REDUCE - 58: p PUT 3 - 61: a APPEND - 62: L LONG 1 - 66: a APPEND - 67: L LONG -1 - 72: a APPEND - 73: L LONG 255 - 79: a APPEND - 80: L LONG -255 - 87: a APPEND - 88: L LONG -256 - 95: a APPEND - 96: L LONG 65535 - 104: a APPEND - 105: L LONG -65535 - 114: a APPEND - 115: L LONG -65536 - 124: a APPEND - 125: L LONG 2147483647 - 138: a APPEND - 139: L LONG -2147483647 - 153: a APPEND - 154: L LONG -2147483648 - 168: a APPEND - 169: ( MARK - 170: V UNICODE 'abc' - 175: p PUT 4 - 178: g GET 4 - 181: c GLOBAL 'copyreg _reconstructor' - 205: p PUT 5 - 208: ( MARK - 209: c GLOBAL '__main__ C' - 221: p PUT 6 - 224: c GLOBAL 'builtins object' - 241: p PUT 7 - 244: N NONE - 245: t TUPLE (MARK at 208) - 246: p PUT 8 - 249: R REDUCE - 250: p PUT 9 - 253: ( MARK - 254: d DICT (MARK at 253) - 255: p PUT 10 - 259: V UNICODE 'foo' - 264: p PUT 11 - 268: L LONG 1 - 272: s SETITEM - 273: V UNICODE 'bar' - 278: p PUT 12 - 282: L LONG 2 - 286: s SETITEM - 287: b BUILD - 288: g GET 9 - 291: t TUPLE (MARK at 169) - 292: p PUT 13 - 296: a APPEND - 297: g GET 13 - 301: a APPEND - 302: L LONG 5 - 306: a APPEND - 307: . STOP + 21: c GLOBAL '__builtin__ complex' + 42: p PUT 1 + 45: ( MARK + 46: F FLOAT 3.0 + 51: F FLOAT 0.0 + 56: t TUPLE (MARK at 45) + 57: p PUT 2 + 60: R REDUCE + 61: p PUT 3 + 64: a APPEND + 65: L LONG 1 + 69: a APPEND + 70: L LONG -1 + 75: a APPEND + 76: L LONG 255 + 82: a APPEND + 83: L LONG -255 + 90: a APPEND + 91: L LONG -256 + 98: a APPEND + 99: L LONG 65535 + 107: a APPEND + 108: L LONG -65535 + 117: a APPEND + 118: L LONG -65536 + 127: a APPEND + 128: L LONG 2147483647 + 141: a APPEND + 142: L LONG -2147483647 + 156: a APPEND + 157: L LONG -2147483648 + 171: a APPEND + 172: ( MARK + 173: V UNICODE 'abc' + 178: p PUT 4 + 181: g GET 4 + 184: c GLOBAL 'copy_reg _reconstructor' + 209: p PUT 5 + 212: ( MARK + 213: c GLOBAL '__main__ C' + 225: p PUT 6 + 228: c GLOBAL '__builtin__ object' + 248: p PUT 7 + 251: N NONE + 252: t TUPLE (MARK at 212) + 253: p PUT 8 + 256: R REDUCE + 257: p PUT 9 + 260: ( MARK + 261: d DICT (MARK at 260) + 262: p PUT 10 + 266: V UNICODE 'foo' + 271: p PUT 11 + 275: L LONG 1 + 279: s SETITEM + 280: V UNICODE 'bar' + 285: p PUT 12 + 289: L LONG 2 + 293: s SETITEM + 294: b BUILD + 295: g GET 9 + 298: t TUPLE (MARK at 172) + 299: p PUT 13 + 303: a APPEND + 304: g GET 13 + 308: a APPEND + 309: L LONG 5 + 313: a APPEND + 314: . STOP highest protocol among opcodes = 0 """ DATA1 = ( - b']q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c' - b'builtins\ncomplex\nq\x01' + b']q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c__' + b'builtin__\ncomplex\nq\x01' b'(G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00t' b'q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xffJ' b'\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff' b'\xff\x7fJ\x01\x00\x00\x80J\x00\x00\x00\x80(X\x03\x00\x00\x00ab' - b'cq\x04h\x04ccopyreg\n_reco' + b'cq\x04h\x04ccopy_reg\n_reco' b'nstructor\nq\x05(c__main' - b'__\nC\nq\x06cbuiltins\n' + b'__\nC\nq\x06c__builtin__\n' b'object\nq\x07Ntq\x08Rq\t}q\n(' b'X\x03\x00\x00\x00fooq\x0bK\x01X\x03\x00\x00\x00bar' b'q\x0cK\x02ubh\ttq\rh\rK\x05e.' @@ -267,66 +268,66 @@ 4: K BININT1 0 6: K BININT1 1 8: G BINFLOAT 2.0 - 17: c GLOBAL 'builtins complex' - 35: q BINPUT 1 - 37: ( MARK - 38: G BINFLOAT 3.0 - 47: G BINFLOAT 0.0 - 56: t TUPLE (MARK at 37) - 57: q BINPUT 2 - 59: R REDUCE - 60: q BINPUT 3 - 62: K BININT1 1 - 64: J BININT -1 - 69: K BININT1 255 - 71: J BININT -255 - 76: J BININT -256 - 81: M BININT2 65535 - 84: J BININT -65535 - 89: J BININT -65536 - 94: J BININT 2147483647 - 99: J BININT -2147483647 - 104: J BININT -2147483648 - 109: ( MARK - 110: X BINUNICODE 'abc' - 118: q BINPUT 4 - 120: h BINGET 4 - 122: c GLOBAL 'copyreg _reconstructor' - 146: q BINPUT 5 - 148: ( MARK - 149: c GLOBAL '__main__ C' - 161: q BINPUT 6 - 163: c GLOBAL 'builtins object' - 180: q BINPUT 7 - 182: N NONE - 183: t TUPLE (MARK at 148) - 184: q BINPUT 8 - 186: R REDUCE - 187: q BINPUT 9 - 189: } EMPTY_DICT - 190: q BINPUT 10 - 192: ( MARK - 193: X BINUNICODE 'foo' - 201: q BINPUT 11 - 203: K BININT1 1 - 205: X BINUNICODE 'bar' - 213: q BINPUT 12 - 215: K BININT1 2 - 217: u SETITEMS (MARK at 192) - 218: b BUILD - 219: h BINGET 9 - 221: t TUPLE (MARK at 109) - 222: q BINPUT 13 - 224: h BINGET 13 - 226: K BININT1 5 - 228: e APPENDS (MARK at 3) - 229: . STOP + 17: c GLOBAL '__builtin__ complex' + 38: q BINPUT 1 + 40: ( MARK + 41: G BINFLOAT 3.0 + 50: G BINFLOAT 0.0 + 59: t TUPLE (MARK at 40) + 60: q BINPUT 2 + 62: R REDUCE + 63: q BINPUT 3 + 65: K BININT1 1 + 67: J BININT -1 + 72: K BININT1 255 + 74: J BININT -255 + 79: J BININT -256 + 84: M BININT2 65535 + 87: J BININT -65535 + 92: J BININT -65536 + 97: J BININT 2147483647 + 102: J BININT -2147483647 + 107: J BININT -2147483648 + 112: ( MARK + 113: X BINUNICODE 'abc' + 121: q BINPUT 4 + 123: h BINGET 4 + 125: c GLOBAL 'copy_reg _reconstructor' + 150: q BINPUT 5 + 152: ( MARK + 153: c GLOBAL '__main__ C' + 165: q BINPUT 6 + 167: c GLOBAL '__builtin__ object' + 187: q BINPUT 7 + 189: N NONE + 190: t TUPLE (MARK at 152) + 191: q BINPUT 8 + 193: R REDUCE + 194: q BINPUT 9 + 196: } EMPTY_DICT + 197: q BINPUT 10 + 199: ( MARK + 200: X BINUNICODE 'foo' + 208: q BINPUT 11 + 210: K BININT1 1 + 212: X BINUNICODE 'bar' + 220: q BINPUT 12 + 222: K BININT1 2 + 224: u SETITEMS (MARK at 199) + 225: b BUILD + 226: h BINGET 9 + 228: t TUPLE (MARK at 112) + 229: q BINPUT 13 + 231: h BINGET 13 + 233: K BININT1 5 + 235: e APPENDS (MARK at 3) + 236: . STOP highest protocol among opcodes = 1 """ DATA2 = ( b'\x80\x02]q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c' - b'builtins\ncomplex\n' + b'__builtin__\ncomplex\n' b'q\x01G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00' b'\x86q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xff' b'J\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff' @@ -346,52 +347,52 @@ 6: K BININT1 0 8: K BININT1 1 10: G BINFLOAT 2.0 - 19: c GLOBAL 'builtins complex' - 37: q BINPUT 1 - 39: G BINFLOAT 3.0 - 48: G BINFLOAT 0.0 - 57: \x86 TUPLE2 - 58: q BINPUT 2 - 60: R REDUCE - 61: q BINPUT 3 - 63: K BININT1 1 - 65: J BININT -1 - 70: K BININT1 255 - 72: J BININT -255 - 77: J BININT -256 - 82: M BININT2 65535 - 85: J BININT -65535 - 90: J BININT -65536 - 95: J BININT 2147483647 - 100: J BININT -2147483647 - 105: J BININT -2147483648 - 110: ( MARK - 111: X BINUNICODE 'abc' - 119: q BINPUT 4 - 121: h BINGET 4 - 123: c GLOBAL '__main__ C' - 135: q BINPUT 5 - 137: ) EMPTY_TUPLE - 138: \x81 NEWOBJ - 139: q BINPUT 6 - 141: } EMPTY_DICT - 142: q BINPUT 7 - 144: ( MARK - 145: X BINUNICODE 'foo' - 153: q BINPUT 8 - 155: K BININT1 1 - 157: X BINUNICODE 'bar' - 165: q BINPUT 9 - 167: K BININT1 2 - 169: u SETITEMS (MARK at 144) - 170: b BUILD - 171: h BINGET 6 - 173: t TUPLE (MARK at 110) - 174: q BINPUT 10 - 176: h BINGET 10 - 178: K BININT1 5 - 180: e APPENDS (MARK at 5) - 181: . STOP + 19: c GLOBAL '__builtin__ complex' + 40: q BINPUT 1 + 42: G BINFLOAT 3.0 + 51: G BINFLOAT 0.0 + 60: \x86 TUPLE2 + 61: q BINPUT 2 + 63: R REDUCE + 64: q BINPUT 3 + 66: K BININT1 1 + 68: J BININT -1 + 73: K BININT1 255 + 75: J BININT -255 + 80: J BININT -256 + 85: M BININT2 65535 + 88: J BININT -65535 + 93: J BININT -65536 + 98: J BININT 2147483647 + 103: J BININT -2147483647 + 108: J BININT -2147483648 + 113: ( MARK + 114: X BINUNICODE 'abc' + 122: q BINPUT 4 + 124: h BINGET 4 + 126: c GLOBAL '__main__ C' + 138: q BINPUT 5 + 140: ) EMPTY_TUPLE + 141: \x81 NEWOBJ + 142: q BINPUT 6 + 144: } EMPTY_DICT + 145: q BINPUT 7 + 147: ( MARK + 148: X BINUNICODE 'foo' + 156: q BINPUT 8 + 158: K BININT1 1 + 160: X BINUNICODE 'bar' + 168: q BINPUT 9 + 170: K BININT1 2 + 172: u SETITEMS (MARK at 147) + 173: b BUILD + 174: h BINGET 6 + 176: t TUPLE (MARK at 113) + 177: q BINPUT 10 + 179: h BINGET 10 + 181: K BININT1 5 + 183: e APPENDS (MARK at 5) + 184: . STOP highest protocol among opcodes = 2 """ @@ -570,14 +571,14 @@ xname = X.__name__.encode('ascii') # Protocol 0 (text mode pickle): """ - 0: ( MARK - 1: i INST '__main__ X' (MARK at 0) - 15: p PUT 0 - 18: ( MARK - 19: d DICT (MARK at 18) - 20: p PUT 1 - 23: b BUILD - 24: . STOP + 0: ( MARK + 1: i INST '__main__ X' (MARK at 0) + 13: p PUT 0 + 16: ( MARK + 17: d DICT (MARK at 16) + 18: p PUT 1 + 21: b BUILD + 22: . STOP """ pickle0 = (b"(i__main__\n" b"X\n" @@ -587,15 +588,15 @@ # Protocol 1 (binary mode pickle) """ - 0: ( MARK - 1: c GLOBAL '__main__ X' - 15: q BINPUT 0 - 17: o OBJ (MARK at 0) - 18: q BINPUT 1 - 20: } EMPTY_DICT - 21: q BINPUT 2 - 23: b BUILD - 24: . STOP + 0: ( MARK + 1: c GLOBAL '__main__ X' + 13: q BINPUT 0 + 15: o OBJ (MARK at 0) + 16: q BINPUT 1 + 18: } EMPTY_DICT + 19: q BINPUT 2 + 21: b BUILD + 22: . STOP """ pickle1 = (b'(c__main__\n' b'X\n' @@ -604,16 +605,16 @@ # Protocol 2 (pickle2 = b'\x80\x02' + pickle1) """ - 0: \x80 PROTO 2 - 2: ( MARK - 3: c GLOBAL '__main__ X' - 17: q BINPUT 0 - 19: o OBJ (MARK at 2) - 20: q BINPUT 1 - 22: } EMPTY_DICT - 23: q BINPUT 2 - 25: b BUILD - 26: . STOP + 0: \x80 PROTO 2 + 2: ( MARK + 3: c GLOBAL '__main__ X' + 15: q BINPUT 0 + 17: o OBJ (MARK at 2) + 18: q BINPUT 1 + 20: } EMPTY_DICT + 21: q BINPUT 2 + 23: b BUILD + 24: . STOP """ pickle2 = (b'\x80\x02(c__main__\n' b'X\n' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 13:39:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 12:39:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Use_pickled_da?= =?utf-8?q?ta_compatible_with_Python_2_for_testing_protocols_0-2=2E?= Message-ID: <20150215123417.60740.41315@psf.io> https://hg.python.org/cpython/rev/d92a067464a0 changeset: 94630:d92a067464a0 branch: 3.4 parent: 94628:7072bbe16a06 user: Serhiy Storchaka date: Sun Feb 15 14:10:03 2015 +0200 summary: Use pickled data compatible with Python 2 for testing protocols 0-2. files: Lib/test/pickletester.py | 433 +++++++++++++------------- 1 files changed, 217 insertions(+), 216 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -144,21 +144,22 @@ # the object returned by create_data(). DATA0 = ( - b'(lp0\nL0L\naL1L\naF2.0\nac' - b'builtins\ncomplex\n' - b'p1\n(F3.0\nF0.0\ntp2\nRp' - b'3\naL1L\naL-1L\naL255L\naL-' - b'255L\naL-256L\naL65535L\na' - b'L-65535L\naL-65536L\naL2' - b'147483647L\naL-2147483' - b'647L\naL-2147483648L\na(' - b'Vabc\np4\ng4\nccopyreg' - b'\n_reconstructor\np5\n(' - b'c__main__\nC\np6\ncbu' - b'iltins\nobject\np7\nNt' - b'p8\nRp9\n(dp10\nVfoo\np1' - b'1\nL1L\nsVbar\np12\nL2L\nsb' - b'g9\ntp13\nag13\naL5L\na.' + b'(lp0\nL0L\naL1L\naF2.0\n' + b'ac__builtin__\ncomple' + b'x\np1\n(F3.0\nF0.0\ntp2\n' + b'Rp3\naL1L\naL-1L\naL255' + b'L\naL-255L\naL-256L\naL' + b'65535L\naL-65535L\naL-' + b'65536L\naL2147483647L' + b'\naL-2147483647L\naL-2' + b'147483648L\na(Vabc\np4' + b'\ng4\nccopy_reg\n_recon' + b'structor\np5\n(c__main' + b'__\nC\np6\nc__builtin__' + b'\nobject\np7\nNtp8\nRp9\n' + b'(dp10\nVfoo\np11\nL1L\ns' + b'Vbar\np12\nL2L\nsbg9\ntp' + b'13\nag13\naL5L\na.' ) # Disassembly of DATA0 @@ -172,88 +173,88 @@ 14: a APPEND 15: F FLOAT 2.0 20: a APPEND - 21: c GLOBAL 'builtins complex' - 39: p PUT 1 - 42: ( MARK - 43: F FLOAT 3.0 - 48: F FLOAT 0.0 - 53: t TUPLE (MARK at 42) - 54: p PUT 2 - 57: R REDUCE - 58: p PUT 3 - 61: a APPEND - 62: L LONG 1 - 66: a APPEND - 67: L LONG -1 - 72: a APPEND - 73: L LONG 255 - 79: a APPEND - 80: L LONG -255 - 87: a APPEND - 88: L LONG -256 - 95: a APPEND - 96: L LONG 65535 - 104: a APPEND - 105: L LONG -65535 - 114: a APPEND - 115: L LONG -65536 - 124: a APPEND - 125: L LONG 2147483647 - 138: a APPEND - 139: L LONG -2147483647 - 153: a APPEND - 154: L LONG -2147483648 - 168: a APPEND - 169: ( MARK - 170: V UNICODE 'abc' - 175: p PUT 4 - 178: g GET 4 - 181: c GLOBAL 'copyreg _reconstructor' - 205: p PUT 5 - 208: ( MARK - 209: c GLOBAL '__main__ C' - 221: p PUT 6 - 224: c GLOBAL 'builtins object' - 241: p PUT 7 - 244: N NONE - 245: t TUPLE (MARK at 208) - 246: p PUT 8 - 249: R REDUCE - 250: p PUT 9 - 253: ( MARK - 254: d DICT (MARK at 253) - 255: p PUT 10 - 259: V UNICODE 'foo' - 264: p PUT 11 - 268: L LONG 1 - 272: s SETITEM - 273: V UNICODE 'bar' - 278: p PUT 12 - 282: L LONG 2 - 286: s SETITEM - 287: b BUILD - 288: g GET 9 - 291: t TUPLE (MARK at 169) - 292: p PUT 13 - 296: a APPEND - 297: g GET 13 - 301: a APPEND - 302: L LONG 5 - 306: a APPEND - 307: . STOP + 21: c GLOBAL '__builtin__ complex' + 42: p PUT 1 + 45: ( MARK + 46: F FLOAT 3.0 + 51: F FLOAT 0.0 + 56: t TUPLE (MARK at 45) + 57: p PUT 2 + 60: R REDUCE + 61: p PUT 3 + 64: a APPEND + 65: L LONG 1 + 69: a APPEND + 70: L LONG -1 + 75: a APPEND + 76: L LONG 255 + 82: a APPEND + 83: L LONG -255 + 90: a APPEND + 91: L LONG -256 + 98: a APPEND + 99: L LONG 65535 + 107: a APPEND + 108: L LONG -65535 + 117: a APPEND + 118: L LONG -65536 + 127: a APPEND + 128: L LONG 2147483647 + 141: a APPEND + 142: L LONG -2147483647 + 156: a APPEND + 157: L LONG -2147483648 + 171: a APPEND + 172: ( MARK + 173: V UNICODE 'abc' + 178: p PUT 4 + 181: g GET 4 + 184: c GLOBAL 'copy_reg _reconstructor' + 209: p PUT 5 + 212: ( MARK + 213: c GLOBAL '__main__ C' + 225: p PUT 6 + 228: c GLOBAL '__builtin__ object' + 248: p PUT 7 + 251: N NONE + 252: t TUPLE (MARK at 212) + 253: p PUT 8 + 256: R REDUCE + 257: p PUT 9 + 260: ( MARK + 261: d DICT (MARK at 260) + 262: p PUT 10 + 266: V UNICODE 'foo' + 271: p PUT 11 + 275: L LONG 1 + 279: s SETITEM + 280: V UNICODE 'bar' + 285: p PUT 12 + 289: L LONG 2 + 293: s SETITEM + 294: b BUILD + 295: g GET 9 + 298: t TUPLE (MARK at 172) + 299: p PUT 13 + 303: a APPEND + 304: g GET 13 + 308: a APPEND + 309: L LONG 5 + 313: a APPEND + 314: . STOP highest protocol among opcodes = 0 """ DATA1 = ( - b']q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c' - b'builtins\ncomplex\nq\x01' + b']q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c__' + b'builtin__\ncomplex\nq\x01' b'(G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00t' b'q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xffJ' b'\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff' b'\xff\x7fJ\x01\x00\x00\x80J\x00\x00\x00\x80(X\x03\x00\x00\x00ab' - b'cq\x04h\x04ccopyreg\n_reco' + b'cq\x04h\x04ccopy_reg\n_reco' b'nstructor\nq\x05(c__main' - b'__\nC\nq\x06cbuiltins\n' + b'__\nC\nq\x06c__builtin__\n' b'object\nq\x07Ntq\x08Rq\t}q\n(' b'X\x03\x00\x00\x00fooq\x0bK\x01X\x03\x00\x00\x00bar' b'q\x0cK\x02ubh\ttq\rh\rK\x05e.' @@ -267,66 +268,66 @@ 4: K BININT1 0 6: K BININT1 1 8: G BINFLOAT 2.0 - 17: c GLOBAL 'builtins complex' - 35: q BINPUT 1 - 37: ( MARK - 38: G BINFLOAT 3.0 - 47: G BINFLOAT 0.0 - 56: t TUPLE (MARK at 37) - 57: q BINPUT 2 - 59: R REDUCE - 60: q BINPUT 3 - 62: K BININT1 1 - 64: J BININT -1 - 69: K BININT1 255 - 71: J BININT -255 - 76: J BININT -256 - 81: M BININT2 65535 - 84: J BININT -65535 - 89: J BININT -65536 - 94: J BININT 2147483647 - 99: J BININT -2147483647 - 104: J BININT -2147483648 - 109: ( MARK - 110: X BINUNICODE 'abc' - 118: q BINPUT 4 - 120: h BINGET 4 - 122: c GLOBAL 'copyreg _reconstructor' - 146: q BINPUT 5 - 148: ( MARK - 149: c GLOBAL '__main__ C' - 161: q BINPUT 6 - 163: c GLOBAL 'builtins object' - 180: q BINPUT 7 - 182: N NONE - 183: t TUPLE (MARK at 148) - 184: q BINPUT 8 - 186: R REDUCE - 187: q BINPUT 9 - 189: } EMPTY_DICT - 190: q BINPUT 10 - 192: ( MARK - 193: X BINUNICODE 'foo' - 201: q BINPUT 11 - 203: K BININT1 1 - 205: X BINUNICODE 'bar' - 213: q BINPUT 12 - 215: K BININT1 2 - 217: u SETITEMS (MARK at 192) - 218: b BUILD - 219: h BINGET 9 - 221: t TUPLE (MARK at 109) - 222: q BINPUT 13 - 224: h BINGET 13 - 226: K BININT1 5 - 228: e APPENDS (MARK at 3) - 229: . STOP + 17: c GLOBAL '__builtin__ complex' + 38: q BINPUT 1 + 40: ( MARK + 41: G BINFLOAT 3.0 + 50: G BINFLOAT 0.0 + 59: t TUPLE (MARK at 40) + 60: q BINPUT 2 + 62: R REDUCE + 63: q BINPUT 3 + 65: K BININT1 1 + 67: J BININT -1 + 72: K BININT1 255 + 74: J BININT -255 + 79: J BININT -256 + 84: M BININT2 65535 + 87: J BININT -65535 + 92: J BININT -65536 + 97: J BININT 2147483647 + 102: J BININT -2147483647 + 107: J BININT -2147483648 + 112: ( MARK + 113: X BINUNICODE 'abc' + 121: q BINPUT 4 + 123: h BINGET 4 + 125: c GLOBAL 'copy_reg _reconstructor' + 150: q BINPUT 5 + 152: ( MARK + 153: c GLOBAL '__main__ C' + 165: q BINPUT 6 + 167: c GLOBAL '__builtin__ object' + 187: q BINPUT 7 + 189: N NONE + 190: t TUPLE (MARK at 152) + 191: q BINPUT 8 + 193: R REDUCE + 194: q BINPUT 9 + 196: } EMPTY_DICT + 197: q BINPUT 10 + 199: ( MARK + 200: X BINUNICODE 'foo' + 208: q BINPUT 11 + 210: K BININT1 1 + 212: X BINUNICODE 'bar' + 220: q BINPUT 12 + 222: K BININT1 2 + 224: u SETITEMS (MARK at 199) + 225: b BUILD + 226: h BINGET 9 + 228: t TUPLE (MARK at 112) + 229: q BINPUT 13 + 231: h BINGET 13 + 233: K BININT1 5 + 235: e APPENDS (MARK at 3) + 236: . STOP highest protocol among opcodes = 1 """ DATA2 = ( b'\x80\x02]q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c' - b'builtins\ncomplex\n' + b'__builtin__\ncomplex\n' b'q\x01G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00' b'\x86q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xff' b'J\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff' @@ -346,52 +347,52 @@ 6: K BININT1 0 8: K BININT1 1 10: G BINFLOAT 2.0 - 19: c GLOBAL 'builtins complex' - 37: q BINPUT 1 - 39: G BINFLOAT 3.0 - 48: G BINFLOAT 0.0 - 57: \x86 TUPLE2 - 58: q BINPUT 2 - 60: R REDUCE - 61: q BINPUT 3 - 63: K BININT1 1 - 65: J BININT -1 - 70: K BININT1 255 - 72: J BININT -255 - 77: J BININT -256 - 82: M BININT2 65535 - 85: J BININT -65535 - 90: J BININT -65536 - 95: J BININT 2147483647 - 100: J BININT -2147483647 - 105: J BININT -2147483648 - 110: ( MARK - 111: X BINUNICODE 'abc' - 119: q BINPUT 4 - 121: h BINGET 4 - 123: c GLOBAL '__main__ C' - 135: q BINPUT 5 - 137: ) EMPTY_TUPLE - 138: \x81 NEWOBJ - 139: q BINPUT 6 - 141: } EMPTY_DICT - 142: q BINPUT 7 - 144: ( MARK - 145: X BINUNICODE 'foo' - 153: q BINPUT 8 - 155: K BININT1 1 - 157: X BINUNICODE 'bar' - 165: q BINPUT 9 - 167: K BININT1 2 - 169: u SETITEMS (MARK at 144) - 170: b BUILD - 171: h BINGET 6 - 173: t TUPLE (MARK at 110) - 174: q BINPUT 10 - 176: h BINGET 10 - 178: K BININT1 5 - 180: e APPENDS (MARK at 5) - 181: . STOP + 19: c GLOBAL '__builtin__ complex' + 40: q BINPUT 1 + 42: G BINFLOAT 3.0 + 51: G BINFLOAT 0.0 + 60: \x86 TUPLE2 + 61: q BINPUT 2 + 63: R REDUCE + 64: q BINPUT 3 + 66: K BININT1 1 + 68: J BININT -1 + 73: K BININT1 255 + 75: J BININT -255 + 80: J BININT -256 + 85: M BININT2 65535 + 88: J BININT -65535 + 93: J BININT -65536 + 98: J BININT 2147483647 + 103: J BININT -2147483647 + 108: J BININT -2147483648 + 113: ( MARK + 114: X BINUNICODE 'abc' + 122: q BINPUT 4 + 124: h BINGET 4 + 126: c GLOBAL '__main__ C' + 138: q BINPUT 5 + 140: ) EMPTY_TUPLE + 141: \x81 NEWOBJ + 142: q BINPUT 6 + 144: } EMPTY_DICT + 145: q BINPUT 7 + 147: ( MARK + 148: X BINUNICODE 'foo' + 156: q BINPUT 8 + 158: K BININT1 1 + 160: X BINUNICODE 'bar' + 168: q BINPUT 9 + 170: K BININT1 2 + 172: u SETITEMS (MARK at 147) + 173: b BUILD + 174: h BINGET 6 + 176: t TUPLE (MARK at 113) + 177: q BINPUT 10 + 179: h BINGET 10 + 181: K BININT1 5 + 183: e APPENDS (MARK at 5) + 184: . STOP highest protocol among opcodes = 2 """ @@ -570,14 +571,14 @@ xname = X.__name__.encode('ascii') # Protocol 0 (text mode pickle): """ - 0: ( MARK - 1: i INST '__main__ X' (MARK at 0) - 15: p PUT 0 - 18: ( MARK - 19: d DICT (MARK at 18) - 20: p PUT 1 - 23: b BUILD - 24: . STOP + 0: ( MARK + 1: i INST '__main__ X' (MARK at 0) + 13: p PUT 0 + 16: ( MARK + 17: d DICT (MARK at 16) + 18: p PUT 1 + 21: b BUILD + 22: . STOP """ pickle0 = (b"(i__main__\n" b"X\n" @@ -587,15 +588,15 @@ # Protocol 1 (binary mode pickle) """ - 0: ( MARK - 1: c GLOBAL '__main__ X' - 15: q BINPUT 0 - 17: o OBJ (MARK at 0) - 18: q BINPUT 1 - 20: } EMPTY_DICT - 21: q BINPUT 2 - 23: b BUILD - 24: . STOP + 0: ( MARK + 1: c GLOBAL '__main__ X' + 13: q BINPUT 0 + 15: o OBJ (MARK at 0) + 16: q BINPUT 1 + 18: } EMPTY_DICT + 19: q BINPUT 2 + 21: b BUILD + 22: . STOP """ pickle1 = (b'(c__main__\n' b'X\n' @@ -604,16 +605,16 @@ # Protocol 2 (pickle2 = b'\x80\x02' + pickle1) """ - 0: \x80 PROTO 2 - 2: ( MARK - 3: c GLOBAL '__main__ X' - 17: q BINPUT 0 - 19: o OBJ (MARK at 2) - 20: q BINPUT 1 - 22: } EMPTY_DICT - 23: q BINPUT 2 - 25: b BUILD - 26: . STOP + 0: \x80 PROTO 2 + 2: ( MARK + 3: c GLOBAL '__main__ X' + 15: q BINPUT 0 + 17: o OBJ (MARK at 2) + 18: q BINPUT 1 + 20: } EMPTY_DICT + 21: q BINPUT 2 + 23: b BUILD + 24: . STOP """ pickle2 = (b'\x80\x02(c__main__\n' b'X\n' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 15:22:50 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 14:22:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319681=3A_Test_the_repr_of_partial_with_more_tha?= =?utf-8?q?n_one_keyword_argument=2E?= Message-ID: <20150215142249.62569.58760@psf.io> https://hg.python.org/cpython/rev/6f80e8bcb5ad changeset: 94634:6f80e8bcb5ad parent: 94632:8c9121993eb5 parent: 94633:138c2afd9f1f user: Serhiy Storchaka date: Sun Feb 15 16:22:11 2015 +0200 summary: Issue #19681: Test the repr of partial with more than one keyword argument. files: Lib/test/test_functools.py | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -155,9 +155,9 @@ def test_repr(self): args = (object(), object()) args_repr = ', '.join(repr(a) for a in args) - #kwargs = {'a': object(), 'b': object()} - kwargs = {'a': object()} - kwargs_repr = ', '.join("%s=%r" % (k, v) for k, v in kwargs.items()) + kwargs = {'a': object(), 'b': object()} + kwargs_reprs = ['a={a!r}, b={b!r}'.format_map(kwargs), + 'b={b!r}, a={a!r}'.format_map(kwargs)] if self.partial is c_functools.partial: name = 'functools.partial' else: @@ -172,12 +172,14 @@ repr(f)) f = self.partial(capture, **kwargs) - self.assertEqual('{}({!r}, {})'.format(name, capture, kwargs_repr), - repr(f)) + self.assertIn(repr(f), + ['{}({!r}, {})'.format(name, capture, kwargs_repr) + for kwargs_repr in kwargs_reprs]) f = self.partial(capture, *args, **kwargs) - self.assertEqual('{}({!r}, {}, {})'.format(name, capture, args_repr, kwargs_repr), - repr(f)) + self.assertIn(repr(f), + ['{}({!r}, {}, {})'.format(name, capture, args_repr, kwargs_repr) + for kwargs_repr in kwargs_reprs]) def test_pickle(self): f = self.partial(signature, 'asdf', bar=True) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 15:22:50 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 14:22:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE5Njgx?= =?utf-8?q?=3A_Test_the_repr_of_partial_with_more_than_one_keyword_argumen?= =?utf-8?q?t=2E?= Message-ID: <20150215142249.126624.82979@psf.io> https://hg.python.org/cpython/rev/138c2afd9f1f changeset: 94633:138c2afd9f1f branch: 3.4 parent: 94630:d92a067464a0 user: Serhiy Storchaka date: Sun Feb 15 16:20:47 2015 +0200 summary: Issue #19681: Test the repr of partial with more than one keyword argument. files: Lib/test/test_functools.py | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -155,9 +155,9 @@ def test_repr(self): args = (object(), object()) args_repr = ', '.join(repr(a) for a in args) - #kwargs = {'a': object(), 'b': object()} - kwargs = {'a': object()} - kwargs_repr = ', '.join("%s=%r" % (k, v) for k, v in kwargs.items()) + kwargs = {'a': object(), 'b': object()} + kwargs_reprs = ['a={a!r}, b={b!r}'.format_map(kwargs), + 'b={b!r}, a={a!r}'.format_map(kwargs)] if self.partial is c_functools.partial: name = 'functools.partial' else: @@ -172,12 +172,14 @@ repr(f)) f = self.partial(capture, **kwargs) - self.assertEqual('{}({!r}, {})'.format(name, capture, kwargs_repr), - repr(f)) + self.assertIn(repr(f), + ['{}({!r}, {})'.format(name, capture, kwargs_repr) + for kwargs_repr in kwargs_reprs]) f = self.partial(capture, *args, **kwargs) - self.assertEqual('{}({!r}, {}, {})'.format(name, capture, args_repr, kwargs_repr), - repr(f)) + self.assertIn(repr(f), + ['{}({!r}, {}, {})'.format(name, capture, args_repr, kwargs_repr) + for kwargs_repr in kwargs_reprs]) def test_pickle(self): f = self.partial(signature, 'asdf', bar=True) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 18:08:11 2015 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 15 Feb 2015 17:08:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323146=3A_Fix_mishandling_of_absolute_Windows_pa?= =?utf-8?q?ths_with_forward_slashes_in?= Message-ID: <20150215170701.126608.55905@psf.io> https://hg.python.org/cpython/rev/0de45993c21c changeset: 94636:0de45993c21c parent: 94634:6f80e8bcb5ad parent: 94635:0f8f24dab34b user: Antoine Pitrou date: Sun Feb 15 18:06:54 2015 +0100 summary: Issue #23146: Fix mishandling of absolute Windows paths with forward slashes in pathlib. Detected and fixed by Serhiy. files: Lib/pathlib.py | 4 +++ Lib/test/test_pathlib.py | 36 +++++++++++++++------------ Misc/NEWS | 3 ++ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -73,6 +73,10 @@ # parts. This makes the result of parsing e.g. # ("C:", "/", "a") reasonably intuitive. for part in it: + if not part: + continue + if altsep: + part = part.replace(altsep, sep) drv = self.splitroot(part)[0] if drv: break diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -102,31 +102,35 @@ check = self._check_parse_parts # First part is anchored check(['c:'], ('c:', '', ['c:'])) - check(['c:\\'], ('c:', '\\', ['c:\\'])) - check(['\\'], ('', '\\', ['\\'])) + check(['c:/'], ('c:', '\\', ['c:\\'])) + check(['/'], ('', '\\', ['\\'])) check(['c:a'], ('c:', '', ['c:', 'a'])) - check(['c:\\a'], ('c:', '\\', ['c:\\', 'a'])) - check(['\\a'], ('', '\\', ['\\', 'a'])) + check(['c:/a'], ('c:', '\\', ['c:\\', 'a'])) + check(['/a'], ('', '\\', ['\\', 'a'])) # UNC paths - check(['\\\\a\\b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['\\\\a\\b\\'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['\\\\a\\b\\c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) + check(['//a/b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['//a/b/'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['//a/b/c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) # Second part is anchored, so that the first part is ignored check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c'])) - check(['a', 'Z:\\b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) - check(['a', '\\b', 'c'], ('', '\\', ['\\', 'b', 'c'])) + check(['a', 'Z:/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) # UNC paths - check(['a', '\\\\b\\c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + check(['a', '//b/c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) # Collapsing and stripping excess slashes - check(['a', 'Z:\\\\b\\\\c\\', 'd\\'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) + check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) # UNC paths - check(['a', '\\\\b\\c\\\\', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + check(['a', '//b/c//', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) # Extended paths - check(['\\\\?\\c:\\'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) - check(['\\\\?\\c:\\a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) + check(['//?/c:/'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) + check(['//?/c:/a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) + check(['//?/c:/a', '/b'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b'])) # Extended UNC paths (format is "\\?\UNC\server\share") - check(['\\\\?\\UNC\\b\\c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) - check(['\\\\?\\UNC\\b\\c\\d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) + check(['//?/UNC/b/c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) + check(['//?/UNC/b/c/d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) + # Second part has a root but not drive + check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c'])) + check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) + check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c'])) def test_splitroot(self): f = self.flavour.splitroot diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #23146: Fix mishandling of absolute Windows paths with forward + slashes in pathlib. + - Issue #23096: Pickle representation of floats with protocol 0 now is the same for both Python and C implementations. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 18:08:11 2015 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 15 Feb 2015 17:08:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMTQ2?= =?utf-8?q?=3A_Fix_mishandling_of_absolute_Windows_paths_with_forward_slas?= =?utf-8?q?hes_in?= Message-ID: <20150215170700.126604.71533@psf.io> https://hg.python.org/cpython/rev/0f8f24dab34b changeset: 94635:0f8f24dab34b branch: 3.4 parent: 94633:138c2afd9f1f user: Antoine Pitrou date: Sun Feb 15 18:03:59 2015 +0100 summary: Issue #23146: Fix mishandling of absolute Windows paths with forward slashes in pathlib. Detected and fixed by Serhiy. files: Lib/pathlib.py | 4 +++ Lib/test/test_pathlib.py | 36 +++++++++++++++------------ Misc/NEWS | 3 ++ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -73,6 +73,10 @@ # parts. This makes the result of parsing e.g. # ("C:", "/", "a") reasonably intuitive. for part in it: + if not part: + continue + if altsep: + part = part.replace(altsep, sep) drv = self.splitroot(part)[0] if drv: break diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -105,31 +105,35 @@ check = self._check_parse_parts # First part is anchored check(['c:'], ('c:', '', ['c:'])) - check(['c:\\'], ('c:', '\\', ['c:\\'])) - check(['\\'], ('', '\\', ['\\'])) + check(['c:/'], ('c:', '\\', ['c:\\'])) + check(['/'], ('', '\\', ['\\'])) check(['c:a'], ('c:', '', ['c:', 'a'])) - check(['c:\\a'], ('c:', '\\', ['c:\\', 'a'])) - check(['\\a'], ('', '\\', ['\\', 'a'])) + check(['c:/a'], ('c:', '\\', ['c:\\', 'a'])) + check(['/a'], ('', '\\', ['\\', 'a'])) # UNC paths - check(['\\\\a\\b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['\\\\a\\b\\'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['\\\\a\\b\\c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) + check(['//a/b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['//a/b/'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['//a/b/c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) # Second part is anchored, so that the first part is ignored check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c'])) - check(['a', 'Z:\\b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) - check(['a', '\\b', 'c'], ('', '\\', ['\\', 'b', 'c'])) + check(['a', 'Z:/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) # UNC paths - check(['a', '\\\\b\\c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + check(['a', '//b/c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) # Collapsing and stripping excess slashes - check(['a', 'Z:\\\\b\\\\c\\', 'd\\'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) + check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) # UNC paths - check(['a', '\\\\b\\c\\\\', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + check(['a', '//b/c//', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) # Extended paths - check(['\\\\?\\c:\\'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) - check(['\\\\?\\c:\\a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) + check(['//?/c:/'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) + check(['//?/c:/a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) + check(['//?/c:/a', '/b'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b'])) # Extended UNC paths (format is "\\?\UNC\server\share") - check(['\\\\?\\UNC\\b\\c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) - check(['\\\\?\\UNC\\b\\c\\d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) + check(['//?/UNC/b/c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) + check(['//?/UNC/b/c/d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) + # Second part has a root but not drive + check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c'])) + check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) + check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c'])) def test_splitroot(self): f = self.flavour.splitroot diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #23146: Fix mishandling of absolute Windows paths with forward + slashes in pathlib. + - Issue #23421: Fixed compression in tarfile CLI. Patch by wdv4758h. - Issue #23361: Fix possible overflow in Windows subprocess creation code. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 18:12:37 2015 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 15 Feb 2015 17:12:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323239=3A_ssl=2Ema?= =?utf-8?q?tch=5Fhostname=28=29_now_supports_matching_of_IP_addresses=2E?= Message-ID: <20150215171226.60720.49929@psf.io> https://hg.python.org/cpython/rev/b15a5f239e8a changeset: 94637:b15a5f239e8a user: Antoine Pitrou date: Sun Feb 15 18:12:20 2015 +0100 summary: Issue #23239: ssl.match_hostname() now supports matching of IP addresses. files: Doc/library/ssl.rst | 11 +++++++---- Lib/ssl.py | 23 ++++++++++++++++++++++- Lib/test/test_ssl.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -344,10 +344,9 @@ Verify that *cert* (in decoded format as returned by :meth:`SSLSocket.getpeercert`) matches the given *hostname*. The rules applied are those for checking the identity of HTTPS servers as outlined - in :rfc:`2818` and :rfc:`6125`, except that IP addresses are not currently - supported. In addition to HTTPS, this function should be suitable for - checking the identity of servers in various SSL-based protocols such as - FTPS, IMAPS, POPS and others. + in :rfc:`2818` and :rfc:`6125`. In addition to HTTPS, this function + should be suitable for checking the identity of servers in various + SSL-based protocols such as FTPS, IMAPS, POPS and others. :exc:`CertificateError` is raised on failure. On success, the function returns nothing:: @@ -369,6 +368,10 @@ IDN A-labels such as ``www*.xn--pthon-kva.org`` are still supported, but ``x*.python.org`` no longer matches ``xn--tda.python.org``. + .. versionchanged:: 3.5 + Matching of IP addresses, when present in the subjectAltName field + of the certificate, is now supported. + .. function:: cert_time_to_seconds(cert_time) Return the time in seconds since the Epoch, given the ``cert_time`` diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -87,6 +87,7 @@ ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY """ +import ipaddress import textwrap import re import sys @@ -242,6 +243,17 @@ return pat.match(hostname) +def _ipaddress_match(ipname, host_ip): + """Exact matching of IP addresses. + + RFC 6125 explicitly doesn't define an algorithm for this + (section 1.7.2 - "Out of Scope"). + """ + # OpenSSL may add a trailing newline to a subjectAltName's IP address + ip = ipaddress.ip_address(ipname.rstrip()) + return ip == host_ip + + def match_hostname(cert, hostname): """Verify that *cert* (in decoded format as returned by SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 @@ -254,11 +266,20 @@ raise ValueError("empty or no certificate, match_hostname needs a " "SSL socket or SSL context with either " "CERT_OPTIONAL or CERT_REQUIRED") + try: + host_ip = ipaddress.ip_address(hostname) + except ValueError: + # Not an IP address (common case) + host_ip = None dnsnames = [] san = cert.get('subjectAltName', ()) for key, value in san: if key == 'DNS': - if _dnsname_match(value, hostname): + if host_ip is None and _dnsname_match(value, hostname): + return + dnsnames.append(value) + elif key == 'IP Address': + if host_ip is not None and _ipaddress_match(value, host_ip): return dnsnames.append(value) if not dnsnames: diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -383,6 +383,8 @@ self.assertRaises(ssl.CertificateError, ssl.match_hostname, cert, hostname) + # -- Hostname matching -- + cert = {'subject': ((('commonName', 'example.com'),),)} ok(cert, 'example.com') ok(cert, 'ExAmple.cOm') @@ -468,6 +470,28 @@ # Only commonName is considered fail(cert, 'California') + # -- IPv4 matching -- + cert = {'subject': ((('commonName', 'example.com'),),), + 'subjectAltName': (('DNS', 'example.com'), + ('IP Address', '10.11.12.13'), + ('IP Address', '14.15.16.17'))} + ok(cert, '10.11.12.13') + ok(cert, '14.15.16.17') + fail(cert, '14.15.16.18') + fail(cert, 'example.net') + + # -- IPv6 matching -- + cert = {'subject': ((('commonName', 'example.com'),),), + 'subjectAltName': (('DNS', 'example.com'), + ('IP Address', '2001:0:0:0:0:0:0:CAFE\n'), + ('IP Address', '2003:0:0:0:0:0:0:BABA\n'))} + ok(cert, '2001::cafe') + ok(cert, '2003::baba') + fail(cert, '2003::bebe') + fail(cert, 'example.net') + + # -- Miscellaneous -- + # Neither commonName nor subjectAltName cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT', 'subject': ((('countryName', 'US'),), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #23239: ssl.match_hostname() now supports matching of IP addresses. + - Issue #23146: Fix mishandling of absolute Windows paths with forward slashes in pathlib. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 23:33:28 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 22:33:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODg1?= =?utf-8?q?=3A_Fixed_arbitrary_code_execution_vulnerability_in_the_dbm=2Ed?= =?utf-8?q?umb?= Message-ID: <20150215223323.72255.78246@psf.io> https://hg.python.org/cpython/rev/693bf15b4314 changeset: 94639:693bf15b4314 branch: 3.4 parent: 94635:0f8f24dab34b user: Serhiy Storchaka date: Mon Feb 16 00:30:43 2015 +0200 summary: Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb module. Original patch by Claudiu Popa. files: Lib/dbm/dumb.py | 3 ++- Lib/test/test_dbm_dumb.py | 9 +++++++++ Misc/NEWS | 3 +++ 3 files changed, 14 insertions(+), 1 deletions(-) diff --git a/Lib/dbm/dumb.py b/Lib/dbm/dumb.py --- a/Lib/dbm/dumb.py +++ b/Lib/dbm/dumb.py @@ -21,6 +21,7 @@ """ +import ast as _ast import io as _io import os as _os import collections @@ -85,7 +86,7 @@ with f: for line in f: line = line.rstrip() - key, pos_and_siz_pair = eval(line) + key, pos_and_siz_pair = _ast.literal_eval(line) key = key.encode('Latin-1') self._index[key] = pos_and_siz_pair diff --git a/Lib/test/test_dbm_dumb.py b/Lib/test/test_dbm_dumb.py --- a/Lib/test/test_dbm_dumb.py +++ b/Lib/test/test_dbm_dumb.py @@ -217,6 +217,15 @@ self.assertEqual(str(cm.exception), "DBM object has already been closed") + def test_eval(self): + with open(_fname + '.dir', 'w') as stream: + stream.write("str(print('Hacked!')), 0\n") + with support.captured_stdout() as stdout: + with self.assertRaises(ValueError): + with dumbdbm.open(_fname) as f: + pass + self.assertEqual(stdout.getvalue(), '') + def tearDown(self): _delete_files() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb + module. Original patch by Claudiu Popa. + - Issue #23146: Fix mishandling of absolute Windows paths with forward slashes in pathlib. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 23:33:28 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 22:33:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyODg1?= =?utf-8?q?=3A_Fixed_arbitrary_code_execution_vulnerability_in_the_dumbdbm?= Message-ID: <20150215223322.60736.81117@psf.io> https://hg.python.org/cpython/rev/02865d22a98d changeset: 94638:02865d22a98d branch: 2.7 parent: 94626:7d2018774925 user: Serhiy Storchaka date: Mon Feb 16 00:29:52 2015 +0200 summary: Issue #22885: Fixed arbitrary code execution vulnerability in the dumbdbm module. Original patch by Claudiu Popa. files: Lib/dumbdbm.py | 3 ++- Lib/test/test_dumbdbm.py | 8 ++++++++ Misc/NEWS | 3 +++ 3 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Lib/dumbdbm.py b/Lib/dumbdbm.py --- a/Lib/dumbdbm.py +++ b/Lib/dumbdbm.py @@ -21,6 +21,7 @@ """ +import ast as _ast import os as _os import __builtin__ import UserDict @@ -85,7 +86,7 @@ with f: for line in f: line = line.rstrip() - key, pos_and_siz_pair = eval(line) + key, pos_and_siz_pair = _ast.literal_eval(line) self._index[key] = pos_and_siz_pair # Write the index dict to the directory file. The original directory diff --git a/Lib/test/test_dumbdbm.py b/Lib/test/test_dumbdbm.py --- a/Lib/test/test_dumbdbm.py +++ b/Lib/test/test_dumbdbm.py @@ -160,6 +160,14 @@ self.assertEqual(expected, got) f.close() + def test_eval(self): + with open(_fname + '.dir', 'w') as stream: + stream.write("str(__import__('sys').stdout.write('Hacked!')), 0\n") + with test_support.captured_stdout() as stdout: + with self.assertRaises(ValueError): + dumbdbm.open(_fname).close() + self.assertEqual(stdout.getvalue(), '') + def tearDown(self): _delete_files() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #22885: Fixed arbitrary code execution vulnerability in the dumbdbm + module. Original patch by Claudiu Popa. + - Issue #21849: Fixed xmlrpclib serialization of non-ASCII unicode strings in the multiprocessing module. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 15 23:33:28 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 22:33:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322885=3A_Fixed_arbitrary_code_execution_vulnera?= =?utf-8?q?bility_in_the_dbm=2Edumb?= Message-ID: <20150215223323.60728.80260@psf.io> https://hg.python.org/cpython/rev/cf6a62b0ef3b changeset: 94640:cf6a62b0ef3b parent: 94637:b15a5f239e8a parent: 94639:693bf15b4314 user: Serhiy Storchaka date: Mon Feb 16 00:32:41 2015 +0200 summary: Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb module. Original patch by Claudiu Popa. files: Lib/dbm/dumb.py | 3 ++- Lib/test/test_dbm_dumb.py | 9 +++++++++ Misc/NEWS | 3 +++ 3 files changed, 14 insertions(+), 1 deletions(-) diff --git a/Lib/dbm/dumb.py b/Lib/dbm/dumb.py --- a/Lib/dbm/dumb.py +++ b/Lib/dbm/dumb.py @@ -21,6 +21,7 @@ """ +import ast as _ast import io as _io import os as _os import collections @@ -95,7 +96,7 @@ with f: for line in f: line = line.rstrip() - key, pos_and_siz_pair = eval(line) + key, pos_and_siz_pair = _ast.literal_eval(line) key = key.encode('Latin-1') self._index[key] = pos_and_siz_pair diff --git a/Lib/test/test_dbm_dumb.py b/Lib/test/test_dbm_dumb.py --- a/Lib/test/test_dbm_dumb.py +++ b/Lib/test/test_dbm_dumb.py @@ -225,6 +225,15 @@ with dumbdbm.open(_fname, 'n') as f: self.assertEqual(f.keys(), []) + def test_eval(self): + with open(_fname + '.dir', 'w') as stream: + stream.write("str(print('Hacked!')), 0\n") + with support.captured_stdout() as stdout: + with self.assertRaises(ValueError): + with dumbdbm.open(_fname) as f: + pass + self.assertEqual(stdout.getvalue(), '') + def tearDown(self): _delete_files() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb + module. Original patch by Claudiu Popa. + - Issue #23239: ssl.match_hostname() now supports matching of IP addresses. - Issue #23146: Fix mishandling of absolute Windows paths with forward -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 00:52:02 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 23:52:02 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_Merge_heads?= Message-ID: <20150215235133.62565.29239@psf.io> https://hg.python.org/cpython/rev/13ffc5ea7fe8 changeset: 94642:13ffc5ea7fe8 branch: 2.7 parent: 94638:02865d22a98d parent: 94641:080de3ad205a user: Serhiy Storchaka date: Mon Feb 16 01:50:04 2015 +0200 summary: Merge heads files: Lib/test/test_cgi.py | 4 ++-- Lib/test/test_sysconfig.py | 4 ++-- Tools/compiler/compile.py | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -194,9 +194,9 @@ cgi.initlog("%s", "Testing initlog 1") cgi.log("%s", "Testing log 2") self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n") - if os.path.exists(os.devnull): + if os.path.exists("/dev/null"): cgi.logfp = None - cgi.logfile = os.devnull + cgi.logfile = "/dev/null" cgi.initlog("%s", "Testing log 3") cgi.log("Testing log 4") diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -294,7 +294,7 @@ if 'MACOSX_DEPLOYMENT_TARGET' in env: del env['MACOSX_DEPLOYMENT_TARGET'] - with open(os.devnull, 'w') as devnull_fp: + with open('/dev/null', 'w') as devnull_fp: p = subprocess.Popen([ sys.executable, '-c', 'import sysconfig; print(sysconfig.get_platform())', @@ -320,7 +320,7 @@ 'import sysconfig; print(sysconfig.get_platform())', ], stdout=subprocess.PIPE, - stderr=open(os.devnull), + stderr=open('/dev/null'), env=env) test_platform = p.communicate()[0].strip() test_platform = test_platform.decode('utf-8') diff --git a/Tools/compiler/compile.py b/Tools/compiler/compile.py --- a/Tools/compiler/compile.py +++ b/Tools/compiler/compile.py @@ -1,4 +1,3 @@ -import os import sys import getopt @@ -17,7 +16,11 @@ VERBOSE = 1 visitor.ASTVisitor.VERBOSE = visitor.ASTVisitor.VERBOSE + 1 if k == '-q': - sys.stdout = open(os.devnull, 'wb') + if sys.platform[:3]=="win": + f = open('nul', 'wb') # /dev/null fails on Windows... + else: + f = open('/dev/null', 'wb') + sys.stdout = f if k == '-d': DISPLAY = 1 if k == '-c': -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 00:52:02 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 15 Feb 2015 23:52:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backed_out_cha?= =?utf-8?q?ngeset_7d2018774925?= Message-ID: <20150215235133.71240.20900@psf.io> https://hg.python.org/cpython/rev/080de3ad205a changeset: 94641:080de3ad205a branch: 2.7 parent: 94626:7d2018774925 user: Serhiy Storchaka date: Mon Feb 16 01:49:22 2015 +0200 summary: Backed out changeset 7d2018774925 files: Lib/test/test_cgi.py | 4 ++-- Lib/test/test_sysconfig.py | 4 ++-- Tools/compiler/compile.py | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -194,9 +194,9 @@ cgi.initlog("%s", "Testing initlog 1") cgi.log("%s", "Testing log 2") self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n") - if os.path.exists(os.devnull): + if os.path.exists("/dev/null"): cgi.logfp = None - cgi.logfile = os.devnull + cgi.logfile = "/dev/null" cgi.initlog("%s", "Testing log 3") cgi.log("Testing log 4") diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -294,7 +294,7 @@ if 'MACOSX_DEPLOYMENT_TARGET' in env: del env['MACOSX_DEPLOYMENT_TARGET'] - with open(os.devnull, 'w') as devnull_fp: + with open('/dev/null', 'w') as devnull_fp: p = subprocess.Popen([ sys.executable, '-c', 'import sysconfig; print(sysconfig.get_platform())', @@ -320,7 +320,7 @@ 'import sysconfig; print(sysconfig.get_platform())', ], stdout=subprocess.PIPE, - stderr=open(os.devnull), + stderr=open('/dev/null'), env=env) test_platform = p.communicate()[0].strip() test_platform = test_platform.decode('utf-8') diff --git a/Tools/compiler/compile.py b/Tools/compiler/compile.py --- a/Tools/compiler/compile.py +++ b/Tools/compiler/compile.py @@ -1,4 +1,3 @@ -import os import sys import getopt @@ -17,7 +16,11 @@ VERBOSE = 1 visitor.ASTVisitor.VERBOSE = visitor.ASTVisitor.VERBOSE + 1 if k == '-q': - sys.stdout = open(os.devnull, 'wb') + if sys.platform[:3]=="win": + f = open('nul', 'wb') # /dev/null fails on Windows... + else: + f = open('/dev/null', 'wb') + sys.stdout = f if k == '-d': DISPLAY = 1 if k == '-c': -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 02:36:40 2015 From: python-checkins at python.org (berker.peksag) Date: Mon, 16 Feb 2015 01:36:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Fix_typo_in_os=2Esupports=5Feffective=5Fids_documentatio?= =?utf-8?q?n=2E?= Message-ID: <20150216013608.72269.39080@psf.io> https://hg.python.org/cpython/rev/fea664de7fc7 changeset: 94644:fea664de7fc7 parent: 94640:cf6a62b0ef3b parent: 94643:be1c9482b6af user: Berker Peksag date: Mon Feb 16 03:36:45 2015 +0200 summary: Fix typo in os.supports_effective_ids documentation. files: Doc/library/os.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2195,7 +2195,8 @@ contain :func:`os.access`, otherwise it will be empty. To check whether you can use the *effective_ids* parameter for - :func:`os.access`, use the ``in`` operator on ``supports_dir_fd``, like so:: + :func:`os.access`, use the ``in`` operator on ``supports_effective_ids``, + like so:: os.access in os.supports_effective_ids -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 02:36:40 2015 From: python-checkins at python.org (berker.peksag) Date: Mon, 16 Feb 2015 01:36:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_typo_in_os?= =?utf-8?q?=2Esupports=5Feffective=5Fids_documentation=2E?= Message-ID: <20150216013608.60728.65527@psf.io> https://hg.python.org/cpython/rev/be1c9482b6af changeset: 94643:be1c9482b6af branch: 3.4 parent: 94639:693bf15b4314 user: Berker Peksag date: Mon Feb 16 03:36:10 2015 +0200 summary: Fix typo in os.supports_effective_ids documentation. files: Doc/library/os.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2159,7 +2159,8 @@ contain :func:`os.access`, otherwise it will be empty. To check whether you can use the *effective_ids* parameter for - :func:`os.access`, use the ``in`` operator on ``supports_dir_fd``, like so:: + :func:`os.access`, use the ``in`` operator on ``supports_effective_ids``, + like so:: os.access in os.supports_effective_ids -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 03:36:12 2015 From: python-checkins at python.org (berker.peksag) Date: Mon, 16 Feb 2015 02:36:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317753=3A_effective=5Fids_unavailable_on_Windows?= =?utf-8?q?=2E?= Message-ID: <20150216023607.126618.5962@psf.io> https://hg.python.org/cpython/rev/964753cf09de changeset: 94646:964753cf09de parent: 94644:fea664de7fc7 parent: 94645:59716f28ed30 user: Berker Peksag date: Mon Feb 16 04:36:43 2015 +0200 summary: Issue #17753: effective_ids unavailable on Windows. files: Lib/test/test_zipfile.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -680,7 +680,9 @@ self.assertIn(name + 'c', namelist) def requiresWriteAccess(self, path): - if not os.access(path, os.W_OK, effective_ids=True): + # effective_ids unavailable on windows + if not os.access(path, os.W_OK, + effective_ids=os.access in os.supports_effective_ids): self.skipTest('requires write access to the installed location') def test_write_pyfile(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 03:36:12 2015 From: python-checkins at python.org (berker.peksag) Date: Mon, 16 Feb 2015 02:36:12 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE3NzUz?= =?utf-8?q?=3A_effective=5Fids_unavailable_on_Windows=2E?= Message-ID: <20150216023607.72265.89291@psf.io> https://hg.python.org/cpython/rev/59716f28ed30 changeset: 94645:59716f28ed30 branch: 3.4 parent: 94643:be1c9482b6af user: Berker Peksag date: Mon Feb 16 04:36:18 2015 +0200 summary: Issue #17753: effective_ids unavailable on Windows. files: Lib/test/test_zipfile.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -649,7 +649,9 @@ self.assertIn(name + 'c', namelist) def requiresWriteAccess(self, path): - if not os.access(path, os.W_OK, effective_ids=True): + # effective_ids unavailable on windows + if not os.access(path, os.W_OK, + effective_ids=os.access in os.supports_effective_ids): self.skipTest('requires write access to the installed location') def test_write_pyfile(self): -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Feb 16 06:27:16 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 16 Feb 2015 06:27:16 +0100 Subject: [Python-checkins] Daily reference leaks (cf6a62b0ef3b): sum=481 Message-ID: results for cf6a62b0ef3b on branch "default" -------------------------------------------- test_asyncio leaked [388, 388, 388] references, sum=1164 test_asyncio leaked [84, 85, 85] memory blocks, sum=254 test_distutils leaked [-388, 0, 0] references, sum=-388 test_distutils leaked [-84, 2, 0] memory blocks, sum=-82 test_eintr leaked [0, -388, 0] references, sum=-388 test_eintr leaked [0, -84, 2] memory blocks, sum=-82 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloghaDopt', '-x'] From python-checkins at python.org Mon Feb 16 07:13:56 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 06:13:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzMTE1?= =?utf-8?q?=3A_Fixed_compilation_on_OpenBSD_=28Py=5FMIN_is_not_defined_in_?= =?utf-8?b?Mi43KS4=?= Message-ID: <20150216060554.72279.3178@psf.io> https://hg.python.org/cpython/rev/a1391786abcd changeset: 94647:a1391786abcd branch: 2.7 parent: 94642:13ffc5ea7fe8 user: Serhiy Storchaka date: Mon Feb 16 08:05:10 2015 +0200 summary: Issue #23115: Fixed compilation on OpenBSD (Py_MIN is not defined in 2.7). files: Python/random.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/random.c b/Python/random.c --- a/Python/random.c +++ b/Python/random.c @@ -102,7 +102,7 @@ py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal) { while (size > 0) { - Py_ssize_t len = Py_MIN(size, 256); + Py_ssize_t len = size < 256 ? size : 256; int res = getentropy(buffer, len); if (res < 0) { if (fatal) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 07:37:36 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 06:37:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320069=3A_Fixed_te?= =?utf-8?q?st=5Fos_on_Solaris=3A_error_message_is_platform_depended=2E?= Message-ID: <20150216063603.62573.20772@psf.io> https://hg.python.org/cpython/rev/4cea99f51bfe changeset: 94648:4cea99f51bfe parent: 94646:964753cf09de user: Serhiy Storchaka date: Mon Feb 16 08:35:18 2015 +0200 summary: Issue #20069: Fixed test_os on Solaris: error message is platform depended. files: Lib/test/test_os.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1075,7 +1075,7 @@ def test_chown_without_permission(self): uid_1, uid_2 = all_users[:2] gid = os.stat(support.TESTFN).st_gid - with self.assertRaisesRegex(PermissionError, "Operation not permitted"): + with self.assertRaises(PermissionError): os.chown(support.TESTFN, uid_1, gid) os.chown(support.TESTFN, uid_2, gid) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 08:04:29 2015 From: python-checkins at python.org (berker.peksag) Date: Mon, 16 Feb 2015 07:04:29 +0000 Subject: [Python-checkins] =?utf-8?q?devguide=3A_Update_git_mirror_URL_to_?= =?utf-8?q?python/cpython=2E?= Message-ID: <20150216070048.71236.95413@psf.io> https://hg.python.org/devguide/rev/0081fea8977a changeset: 728:0081fea8977a user: Berker Peksag date: Mon Feb 16 09:01:27 2015 +0200 summary: Update git mirror URL to python/cpython. files: faq.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -167,17 +167,17 @@ While the main workflow for core developers requires Mercurial, if you just want to generate patches with ``git diff`` and post them to the -`issue tracker`_, Petri Lehtinen maintains a `git mirror`_ of the main +`issue tracker`_, there is a semi-offical read-only `git mirror`_ of the main `CPython repository`_. To create a local clone based on this mirror rather than the main repository:: - git clone git://github.com/akheron/cpython + git clone git://github.com/python/cpython The mirror's master branch tracks the main repository's default branch, while the maintenance branch names (``2.7``, ``3.4``, etc) are mapped directly. -.. _git mirror: https://github.com/akheron/cpython +.. _git mirror: https://github.com/python/cpython .. _CPython repository: https://hg.python.org/cpython Please only use this approach if you're already an experienced Git user and -- Repository URL: https://hg.python.org/devguide From python-checkins at python.org Mon Feb 16 08:41:49 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 07:41:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_few_compiler_warning?= =?utf-8?q?s=2E?= Message-ID: <20150216074050.72273.36327@psf.io> https://hg.python.org/cpython/rev/f402a6511559 changeset: 94649:f402a6511559 user: Serhiy Storchaka date: Mon Feb 16 09:40:12 2015 +0200 summary: Fixed few compiler warnings. files: Modules/cjkcodecs/_codecs_iso2022.c | 7 +++---- Modules/faulthandler.c | 2 +- Python/ceval_gil.h | 4 ++-- Python/pylifecycle.c | 2 +- Python/pystate.c | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Modules/cjkcodecs/_codecs_iso2022.c b/Modules/cjkcodecs/_codecs_iso2022.c --- a/Modules/cjkcodecs/_codecs_iso2022.c +++ b/Modules/cjkcodecs/_codecs_iso2022.c @@ -292,7 +292,7 @@ const unsigned char **inbuf, Py_ssize_t *inleft) { unsigned char charset, designation; - Py_ssize_t i, esclen; + Py_ssize_t i, esclen = 0; for (i = 1;i < MAX_ESCSEQLEN;i++) { if (i >= *inleft) @@ -307,10 +307,9 @@ } } - if (i >= MAX_ESCSEQLEN) + switch (esclen) { + case 0: return 1; /* unterminated escape sequence */ - - switch (esclen) { case 3: if (INBYTE2 == '$') { charset = INBYTE3 | CHARSET_DBCS; diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -458,7 +458,7 @@ assert(st == PY_LOCK_FAILURE); /* get the thread holding the GIL, NULL if no thread hold the GIL */ - current = _Py_atomic_load_relaxed(&_PyThreadState_Current); + current = (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); write(thread.fd, thread.header, (int)thread.header_len); diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h --- a/Python/ceval_gil.h +++ b/Python/ceval_gil.h @@ -191,7 +191,7 @@ if (_Py_atomic_load_relaxed(&gil_drop_request) && tstate != NULL) { MUTEX_LOCK(switch_mutex); /* Not switched yet => wait */ - if (_Py_atomic_load_relaxed(&gil_last_holder) == tstate) { + if ((PyThreadState*)_Py_atomic_load_relaxed(&gil_last_holder) == tstate) { RESET_GIL_DROP_REQUEST(); /* NOTE: if COND_WAIT does not atomically start waiting when releasing the mutex, another thread can run through, take @@ -239,7 +239,7 @@ _Py_atomic_store_relaxed(&gil_locked, 1); _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil_locked, /*is_write=*/1); - if (tstate != _Py_atomic_load_relaxed(&gil_last_holder)) { + if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(&gil_last_holder)) { _Py_atomic_store_relaxed(&gil_last_holder, tstate); ++gil_switch_number; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1258,7 +1258,7 @@ PyErr_PrintEx(0); } else { - tstate = _Py_atomic_load_relaxed(&_PyThreadState_Current); + tstate = (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); if (tstate != NULL) { fputc('\n', stderr); fflush(stderr); diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -403,7 +403,7 @@ void PyThreadState_Delete(PyThreadState *tstate) { - if (tstate == _Py_atomic_load_relaxed(&_PyThreadState_Current)) + if (tstate == (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) Py_FatalError("PyThreadState_Delete: tstate is still current"); #ifdef WITH_THREAD if (autoInterpreterState && PyThread_get_key_value(autoTLSkey) == tstate) @@ -662,7 +662,7 @@ { /* Must be the tstate for this thread */ assert(PyGILState_GetThisThreadState()==tstate); - return tstate == _Py_atomic_load_relaxed(&_PyThreadState_Current); + return tstate == (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); } /* Internal initialization/finalization functions called by -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 12:35:53 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 11:35:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzNDQ2?= =?utf-8?q?=3A_Use_PyMem=5FNew_instead_of_PyMem=5FMalloc_to_avoid_possible?= =?utf-8?q?_integer?= Message-ID: <20150216113449.71236.45820@psf.io> https://hg.python.org/cpython/rev/d83884b3a427 changeset: 94650:d83884b3a427 branch: 2.7 parent: 94647:a1391786abcd user: Serhiy Storchaka date: Mon Feb 16 13:16:07 2015 +0200 summary: Issue #23446: Use PyMem_New instead of PyMem_Malloc to avoid possible integer overflows. Added few missed PyErr_NoMemory(). files: Modules/_ctypes/_ctypes.c | 9 ++++++--- Modules/_ctypes/stgdict.c | 12 ++++++++---- Modules/_localemodule.c | 4 ++-- Modules/_ssl.c | 7 ++++--- Python/peephole.c | 8 +++++--- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4469,8 +4469,11 @@ slicelen); } - dest = (wchar_t *)PyMem_Malloc( - slicelen * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, slicelen); + if (dest == NULL) { + PyErr_NoMemory(); + return NULL; + } for (cur = start, i = 0; i < slicelen; cur += step, i++) { @@ -5250,7 +5253,7 @@ return PyUnicode_FromWideChar(ptr + start, len); } - dest = (wchar_t *)PyMem_Malloc(len * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, len); if (dest == NULL) return PyErr_NoMemory(); for (cur = start, i = 0; i < len; cur += step, i++) { diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -80,14 +80,18 @@ if (src->format) { dst->format = PyMem_Malloc(strlen(src->format) + 1); - if (dst->format == NULL) + if (dst->format == NULL) { + PyErr_NoMemory(); return -1; + } strcpy(dst->format, src->format); } if (src->shape) { dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim); - if (dst->shape == NULL) + if (dst->shape == NULL) { + PyErr_NoMemory(); return -1; + } memcpy(dst->shape, src->shape, sizeof(Py_ssize_t) * src->ndim); } @@ -388,7 +392,7 @@ union_size = 0; total_align = align ? align : 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; @@ -406,7 +410,7 @@ union_size = 0; total_align = 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -314,7 +314,7 @@ } /* Convert the unicode strings to wchar[]. */ len1 = PyUnicode_GET_SIZE(os1) + 1; - ws1 = PyMem_MALLOC(len1 * sizeof(wchar_t)); + ws1 = PyMem_NEW(wchar_t, len1); if (!ws1) { PyErr_NoMemory(); goto done; @@ -323,7 +323,7 @@ goto done; ws1[len1 - 1] = 0; len2 = PyUnicode_GET_SIZE(os2) + 1; - ws2 = PyMem_MALLOC(len2 * sizeof(wchar_t)); + ws2 = PyMem_NEW(wchar_t, len2); if (!ws2) { PyErr_NoMemory(); goto done; diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3891,10 +3891,11 @@ if (_ssl_locks == NULL) { _ssl_locks_count = CRYPTO_num_locks(); - _ssl_locks = (PyThread_type_lock *) - PyMem_Malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); - if (_ssl_locks == NULL) + _ssl_locks = PyMem_New(PyThread_type_lock, _ssl_locks_count); + if (_ssl_locks == NULL) { + PyErr_NoMemory(); return 0; + } memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); for (i = 0; i < _ssl_locks_count; i++) { diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -242,7 +242,7 @@ static unsigned int * markblocks(unsigned char *code, Py_ssize_t len) { - unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int)); + unsigned int *blocks = PyMem_New(unsigned int, len); int i,j, opcode, blockcnt = 0; if (blocks == NULL) { @@ -343,9 +343,11 @@ goto exitUnchanged; /* Mapping to new jump targets after NOPs are removed */ - addrmap = (int *)PyMem_Malloc(codelen * sizeof(int)); - if (addrmap == NULL) + addrmap = PyMem_New(int, codelen); + if (addrmap == NULL) { + PyErr_NoMemory(); goto exitError; + } blocks = markblocks(codestr, codelen); if (blocks == NULL) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 12:35:52 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 11:35:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323446=3A_Use_PyMem=5FNew_instead_of_PyMem=5FMal?= =?utf-8?q?loc_to_avoid_possible_integer?= Message-ID: <20150216113451.71224.75758@psf.io> https://hg.python.org/cpython/rev/d12c7938c4b0 changeset: 94652:d12c7938c4b0 parent: 94649:f402a6511559 parent: 94651:036a2aceae93 user: Serhiy Storchaka date: Mon Feb 16 13:33:32 2015 +0200 summary: Issue #23446: Use PyMem_New instead of PyMem_Malloc to avoid possible integer overflows. Added few missed PyErr_NoMemory(). files: Modules/_ctypes/_ctypes.c | 9 ++++++--- Modules/_ctypes/stgdict.c | 12 ++++++++---- Modules/_localemodule.c | 2 +- Modules/_ssl.c | 7 ++++--- Modules/_testbuffer.c | 2 +- Modules/_testcapimodule.c | 2 +- Modules/getpath.c | 2 +- Modules/posixmodule.c | 20 ++++++++++---------- Modules/pyexpat.c | 4 ++-- Modules/socketmodule.c | 6 ++++-- Modules/unicodedata.c | 4 ++-- Modules/zipimport.c | 2 +- Objects/unicodeobject.c | 22 +++++----------------- PC/winreg.c | 6 +++--- Python/peephole.c | 4 ++-- 15 files changed, 51 insertions(+), 53 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4305,8 +4305,11 @@ slicelen); } - dest = (wchar_t *)PyMem_Malloc( - slicelen * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, slicelen); + if (dest == NULL) { + PyErr_NoMemory(); + return NULL; + } for (cur = start, i = 0; i < slicelen; cur += step, i++) { @@ -4986,7 +4989,7 @@ return PyUnicode_FromWideChar(ptr + start, len); } - dest = (wchar_t *)PyMem_Malloc(len * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, len); if (dest == NULL) return PyErr_NoMemory(); for (cur = start, i = 0; i < len; cur += step, i++) { diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -76,14 +76,18 @@ if (src->format) { dst->format = PyMem_Malloc(strlen(src->format) + 1); - if (dst->format == NULL) + if (dst->format == NULL) { + PyErr_NoMemory(); return -1; + } strcpy(dst->format, src->format); } if (src->shape) { dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim); - if (dst->shape == NULL) + if (dst->shape == NULL) { + PyErr_NoMemory(); return -1; + } memcpy(dst->shape, src->shape, sizeof(Py_ssize_t) * src->ndim); } @@ -380,7 +384,7 @@ union_size = 0; total_align = align ? align : 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; @@ -398,7 +402,7 @@ union_size = 0; total_align = 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -254,7 +254,7 @@ /* assume no change in size, first */ n1 = n1 + 1; - buf = PyMem_Malloc(n1 * sizeof(wchar_t)); + buf = PyMem_New(wchar_t, n1); if (!buf) { PyErr_NoMemory(); goto exit; diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4287,10 +4287,11 @@ if (_ssl_locks == NULL) { _ssl_locks_count = CRYPTO_num_locks(); - _ssl_locks = (PyThread_type_lock *) - PyMem_Malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); - if (_ssl_locks == NULL) + _ssl_locks = PyMem_New(PyThread_type_lock, _ssl_locks_count); + if (_ssl_locks == NULL) { + PyErr_NoMemory(); return 0; + } memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); for (i = 0; i < _ssl_locks_count; i++) { diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -850,7 +850,7 @@ Py_ssize_t *dest; Py_ssize_t x, i; - dest = PyMem_Malloc(len * (sizeof *dest)); + dest = PyMem_New(Py_ssize_t, len); if (dest == NULL) { PyErr_NoMemory(); return NULL; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1517,7 +1517,7 @@ if (!PyArg_ParseTuple(args, "Un", &unicode, &buflen)) return NULL; - buffer = PyMem_Malloc(buflen * sizeof(wchar_t)); + buffer = PyMem_New(wchar_t, buflen); if (buffer == NULL) return PyErr_NoMemory(); diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -735,7 +735,7 @@ bufsz += wcslen(zip_path) + 1; bufsz += wcslen(exec_prefix) + 1; - buf = (wchar_t *)PyMem_Malloc(bufsz * sizeof(wchar_t)); + buf = PyMem_New(wchar_t, bufsz); if (buf == NULL) { Py_FatalError( "Not enough memory for dynamic PYTHONPATH"); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1620,7 +1620,7 @@ if(!buf_size) return FALSE; - buf = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); + buf = PyMem_New(wchar_t, buf_size+1); if (!buf) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -4472,7 +4472,7 @@ len = wcslen(path->wide); } /* The +5 is so we can append "\\*.*\0" */ - wnamebuf = PyMem_Malloc((len + 5) * sizeof(wchar_t)); + wnamebuf = PyMem_New(wchar_t, len + 5); if (!wnamebuf) { PyErr_NoMemory(); goto exit; @@ -4809,7 +4809,7 @@ Py_ARRAY_LENGTH(woutbuf), woutbuf, &wtemp); if (result > Py_ARRAY_LENGTH(woutbuf)) { - woutbufp = PyMem_Malloc(result * sizeof(wchar_t)); + woutbufp = PyMem_New(wchar_t, result); if (!woutbufp) return PyErr_NoMemory(); result = GetFullPathNameW(wpath, result, woutbufp, &wtemp); @@ -4923,7 +4923,7 @@ if(!buf_size) return win32_error_object("GetFinalPathNameByHandle", path); - target_path = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); + target_path = PyMem_New(wchar_t, buf_size+1); if(!target_path) return PyErr_NoMemory(); @@ -5041,7 +5041,7 @@ return NULL; } - mountpath = (wchar_t *)PyMem_Malloc(buflen * sizeof(wchar_t)); + mountpath = PyMem_New(wchar_t, buflen); if (mountpath == NULL) return PyErr_NoMemory(); @@ -8421,9 +8421,9 @@ #endif #ifdef __APPLE__ - groups = PyMem_Malloc(ngroups * sizeof(int)); -#else - groups = PyMem_Malloc(ngroups * sizeof(gid_t)); + groups = PyMem_New(int, ngroups); +#else + groups = PyMem_New(gid_t, ngroups); #endif if (groups == NULL) return PyErr_NoMemory(); @@ -8523,7 +8523,7 @@ /* groups will fit in existing array */ alt_grouplist = grouplist; } else { - alt_grouplist = PyMem_Malloc(n * sizeof(gid_t)); + alt_grouplist = PyMem_New(gid_t, n); if (alt_grouplist == NULL) { errno = EINVAL; return posix_error(); @@ -8549,7 +8549,7 @@ /* Avoid malloc(0) */ alt_grouplist = grouplist; } else { - alt_grouplist = PyMem_Malloc(n * sizeof(gid_t)); + alt_grouplist = PyMem_New(gid_t, n); if (alt_grouplist == NULL) { errno = EINVAL; return posix_error(); diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1093,7 +1093,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - new_parser->handlers = PyMem_Malloc(sizeof(PyObject *) * i); + new_parser->handlers = PyMem_New(PyObject *, i); if (!new_parser->handlers) { Py_DECREF(new_parser); return PyErr_NoMemory(); @@ -1416,7 +1416,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - self->handlers = PyMem_Malloc(sizeof(PyObject *) * i); + self->handlers = PyMem_New(PyObject *, i); if (!self->handlers) { Py_DECREF(self); return PyErr_NoMemory(); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4213,9 +4213,11 @@ /* MSDN says ERROR_MORE_DATA may occur because DNS allows longer names */ - name = PyMem_Malloc(size * sizeof(wchar_t)); - if (!name) + name = PyMem_New(wchar_t, size); + if (!name) { + PyErr_NoMemory(); return NULL; + } if (!GetComputerNameExW(ComputerNamePhysicalDnsHostname, name, &size)) diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -556,7 +556,7 @@ /* Overallocate at most 10 characters. */ space = (isize > 10 ? 10 : isize) + isize; osize = space; - output = PyMem_Malloc(space * sizeof(Py_UCS4)); + output = PyMem_New(Py_UCS4, space); if (!output) { PyErr_NoMemory(); return NULL; @@ -703,7 +703,7 @@ /* We allocate a buffer for the output. If we find that we made no changes, we still return the NFD result. */ - output = PyMem_Malloc(len * sizeof(Py_UCS4)); + output = PyMem_New(Py_UCS4, len); if (!output) { PyErr_NoMemory(); Py_DECREF(result); diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -233,7 +233,7 @@ Py_ssize_t len; len = PyUnicode_GET_LENGTH(prefix) + PyUnicode_GET_LENGTH(name) + 1; - p = buf = PyMem_Malloc(sizeof(Py_UCS4) * len); + p = buf = PyMem_New(Py_UCS4, len); if (buf == NULL) { PyErr_NoMemory(); return NULL; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2186,7 +2186,7 @@ } switch (kind) { case PyUnicode_2BYTE_KIND: - result = PyMem_Malloc(len * sizeof(Py_UCS2)); + result = PyMem_New(Py_UCS2, len); if (!result) return PyErr_NoMemory(); assert(skind == PyUnicode_1BYTE_KIND); @@ -2197,7 +2197,7 @@ result); return result; case PyUnicode_4BYTE_KIND: - result = PyMem_Malloc(len * sizeof(Py_UCS4)); + result = PyMem_New(Py_UCS4, len); if (!result) return PyErr_NoMemory(); if (skind == PyUnicode_2BYTE_KIND) { @@ -2239,11 +2239,7 @@ if (copy_null) targetlen++; if (!target) { - if (PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(Py_UCS4) < targetlen) { - PyErr_NoMemory(); - return NULL; - } - target = PyMem_Malloc(targetlen * sizeof(Py_UCS4)); + target = PyMem_New(Py_UCS4, targetlen); if (!target) { PyErr_NoMemory(); return NULL; @@ -2817,12 +2813,7 @@ buflen = unicode_aswidechar(unicode, NULL, 0); if (buflen == -1) return NULL; - if (PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(wchar_t) < buflen) { - PyErr_NoMemory(); - return NULL; - } - - buffer = PyMem_MALLOC(buflen * sizeof(wchar_t)); + buffer = PyMem_NEW(wchar_t, buflen); if (buffer == NULL) { PyErr_NoMemory(); return NULL; @@ -3515,10 +3506,7 @@ wstr = smallbuf; } else { - if (wlen > PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) - return PyErr_NoMemory(); - - wstr = PyMem_Malloc((wlen+1) * sizeof(wchar_t)); + wstr = PyMem_New(wchar_t, wlen+1); if (!wstr) return PyErr_NoMemory(); } diff --git a/PC/winreg.c b/PC/winreg.c --- a/PC/winreg.c +++ b/PC/winreg.c @@ -939,7 +939,7 @@ wchar_t *data = (wchar_t *)retDataBuf; int len = retDataSize / 2; int s = countStrings(data, len); - wchar_t **str = (wchar_t **)PyMem_Malloc(sizeof(wchar_t *)*s); + wchar_t **str = PyMem_New(wchar_t *, s); if (str == NULL) return PyErr_NoMemory(); @@ -1206,7 +1206,7 @@ ++retDataSize; bufDataSize = retDataSize; bufValueSize = retValueSize; - retValueBuf = (wchar_t *)PyMem_Malloc(sizeof(wchar_t) * retValueSize); + retValueBuf = PyMem_New(wchar_t, retValueSize); if (retValueBuf == NULL) return PyErr_NoMemory(); retDataBuf = (BYTE *)PyMem_Malloc(retDataSize); @@ -1277,7 +1277,7 @@ return PyErr_SetFromWindowsErrWithFunction(retValueSize, "ExpandEnvironmentStrings"); } - retValue = (wchar_t *)PyMem_Malloc(retValueSize * sizeof(wchar_t)); + retValue = PyMem_New(wchar_t, retValueSize); if (retValue == NULL) { return PyErr_NoMemory(); } diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -290,7 +290,7 @@ static unsigned int * markblocks(unsigned char *code, Py_ssize_t len) { - unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int)); + unsigned int *blocks = PyMem_New(unsigned int, len); int i,j, opcode, blockcnt = 0; if (blocks == NULL) { @@ -398,7 +398,7 @@ goto exitUnchanged; /* Mapping to new jump targets after NOPs are removed */ - addrmap = (int *)PyMem_Malloc(codelen * sizeof(int)); + addrmap = PyMem_New(int, codelen); if (addrmap == NULL) { PyErr_NoMemory(); goto exitError; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 12:35:52 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 11:35:52 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDQ2?= =?utf-8?q?=3A_Use_PyMem=5FNew_instead_of_PyMem=5FMalloc_to_avoid_possible?= =?utf-8?q?_integer?= Message-ID: <20150216113449.60738.84196@psf.io> https://hg.python.org/cpython/rev/036a2aceae93 changeset: 94651:036a2aceae93 branch: 3.4 parent: 94645:59716f28ed30 user: Serhiy Storchaka date: Mon Feb 16 13:28:22 2015 +0200 summary: Issue #23446: Use PyMem_New instead of PyMem_Malloc to avoid possible integer overflows. Added few missed PyErr_NoMemory(). files: Modules/_ctypes/_ctypes.c | 9 ++++++--- Modules/_ctypes/stgdict.c | 12 ++++++++---- Modules/_localemodule.c | 2 +- Modules/_ssl.c | 7 ++++--- Modules/_testbuffer.c | 2 +- Modules/_testcapimodule.c | 2 +- Modules/getpath.c | 2 +- Modules/posixmodule.c | 20 ++++++++++---------- Modules/pyexpat.c | 4 ++-- Modules/socketmodule.c | 6 ++++-- Modules/unicodedata.c | 4 ++-- Modules/zipimport.c | 2 +- Objects/unicodeobject.c | 22 +++++----------------- PC/winreg.c | 6 +++--- Python/peephole.c | 4 ++-- 15 files changed, 51 insertions(+), 53 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4305,8 +4305,11 @@ slicelen); } - dest = (wchar_t *)PyMem_Malloc( - slicelen * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, slicelen); + if (dest == NULL) { + PyErr_NoMemory(); + return NULL; + } for (cur = start, i = 0; i < slicelen; cur += step, i++) { @@ -4986,7 +4989,7 @@ return PyUnicode_FromWideChar(ptr + start, len); } - dest = (wchar_t *)PyMem_Malloc(len * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, len); if (dest == NULL) return PyErr_NoMemory(); for (cur = start, i = 0; i < len; cur += step, i++) { diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -76,14 +76,18 @@ if (src->format) { dst->format = PyMem_Malloc(strlen(src->format) + 1); - if (dst->format == NULL) + if (dst->format == NULL) { + PyErr_NoMemory(); return -1; + } strcpy(dst->format, src->format); } if (src->shape) { dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim); - if (dst->shape == NULL) + if (dst->shape == NULL) { + PyErr_NoMemory(); return -1; + } memcpy(dst->shape, src->shape, sizeof(Py_ssize_t) * src->ndim); } @@ -380,7 +384,7 @@ union_size = 0; total_align = align ? align : 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; @@ -398,7 +402,7 @@ union_size = 0; total_align = 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -254,7 +254,7 @@ /* assume no change in size, first */ n1 = n1 + 1; - buf = PyMem_Malloc(n1 * sizeof(wchar_t)); + buf = PyMem_New(wchar_t, n1); if (!buf) { PyErr_NoMemory(); goto exit; diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3838,10 +3838,11 @@ if (_ssl_locks == NULL) { _ssl_locks_count = CRYPTO_num_locks(); - _ssl_locks = (PyThread_type_lock *) - PyMem_Malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); - if (_ssl_locks == NULL) + _ssl_locks = PyMem_New(PyThread_type_lock, _ssl_locks_count); + if (_ssl_locks == NULL) { + PyErr_NoMemory(); return 0; + } memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); for (i = 0; i < _ssl_locks_count; i++) { diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -850,7 +850,7 @@ Py_ssize_t *dest; Py_ssize_t x, i; - dest = PyMem_Malloc(len * (sizeof *dest)); + dest = PyMem_New(Py_ssize_t, len); if (dest == NULL) { PyErr_NoMemory(); return NULL; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1516,7 +1516,7 @@ if (!PyArg_ParseTuple(args, "Un", &unicode, &buflen)) return NULL; - buffer = PyMem_Malloc(buflen * sizeof(wchar_t)); + buffer = PyMem_New(wchar_t, buflen); if (buffer == NULL) return PyErr_NoMemory(); diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -735,7 +735,7 @@ bufsz += wcslen(zip_path) + 1; bufsz += wcslen(exec_prefix) + 1; - buf = (wchar_t *)PyMem_Malloc(bufsz * sizeof(wchar_t)); + buf = PyMem_New(wchar_t, bufsz); if (buf == NULL) { Py_FatalError( "Not enough memory for dynamic PYTHONPATH"); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1638,7 +1638,7 @@ if(!buf_size) return FALSE; - buf = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); + buf = PyMem_New(wchar_t, buf_size+1); if (!buf) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -3627,7 +3627,7 @@ len = wcslen(path->wide); } /* The +5 is so we can append "\\*.*\0" */ - wnamebuf = PyMem_Malloc((len + 5) * sizeof(wchar_t)); + wnamebuf = PyMem_New(wchar_t, len + 5); if (!wnamebuf) { PyErr_NoMemory(); goto exit; @@ -3917,7 +3917,7 @@ Py_ARRAY_LENGTH(woutbuf), woutbuf, &wtemp); if (result > Py_ARRAY_LENGTH(woutbuf)) { - woutbufp = PyMem_Malloc(result * sizeof(wchar_t)); + woutbufp = PyMem_New(wchar_t, result); if (!woutbufp) return PyErr_NoMemory(); result = GetFullPathNameW(wpath, result, woutbufp, &wtemp); @@ -3997,7 +3997,7 @@ if(!buf_size) return win32_error_object("GetFinalPathNameByHandle", po); - target_path = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); + target_path = PyMem_New(wchar_t, buf_size+1); if(!target_path) return PyErr_NoMemory(); @@ -4082,7 +4082,7 @@ return NULL; } - mountpath = (wchar_t *)PyMem_Malloc(buflen * sizeof(wchar_t)); + mountpath = PyMem_New(wchar_t, buflen); if (mountpath == NULL) return PyErr_NoMemory(); @@ -6213,9 +6213,9 @@ #endif #ifdef __APPLE__ - groups = PyMem_Malloc(ngroups * sizeof(int)); -#else - groups = PyMem_Malloc(ngroups * sizeof(gid_t)); + groups = PyMem_New(int, ngroups); +#else + groups = PyMem_New(gid_t, ngroups); #endif if (groups == NULL) return PyErr_NoMemory(); @@ -6293,7 +6293,7 @@ /* groups will fit in existing array */ alt_grouplist = grouplist; } else { - alt_grouplist = PyMem_Malloc(n * sizeof(gid_t)); + alt_grouplist = PyMem_New(gid_t, n); if (alt_grouplist == NULL) { errno = EINVAL; return posix_error(); @@ -6319,7 +6319,7 @@ /* Avoid malloc(0) */ alt_grouplist = grouplist; } else { - alt_grouplist = PyMem_Malloc(n * sizeof(gid_t)); + alt_grouplist = PyMem_New(gid_t, n); if (alt_grouplist == NULL) { errno = EINVAL; return posix_error(); diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -928,7 +928,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - new_parser->handlers = PyMem_Malloc(sizeof(PyObject *) * i); + new_parser->handlers = PyMem_New(PyObject *, i); if (!new_parser->handlers) { Py_DECREF(new_parser); return PyErr_NoMemory(); @@ -1121,7 +1121,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - self->handlers = PyMem_Malloc(sizeof(PyObject *) * i); + self->handlers = PyMem_New(PyObject *, i); if (!self->handlers) { Py_DECREF(self); return PyErr_NoMemory(); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4126,9 +4126,11 @@ /* MSDN says ERROR_MORE_DATA may occur because DNS allows longer names */ - name = PyMem_Malloc(size * sizeof(wchar_t)); - if (!name) + name = PyMem_New(wchar_t, size); + if (!name) { + PyErr_NoMemory(); return NULL; + } if (!GetComputerNameExW(ComputerNamePhysicalDnsHostname, name, &size)) diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -556,7 +556,7 @@ /* Overallocate at most 10 characters. */ space = (isize > 10 ? 10 : isize) + isize; osize = space; - output = PyMem_Malloc(space * sizeof(Py_UCS4)); + output = PyMem_New(Py_UCS4, space); if (!output) { PyErr_NoMemory(); return NULL; @@ -703,7 +703,7 @@ /* We allocate a buffer for the output. If we find that we made no changes, we still return the NFD result. */ - output = PyMem_Malloc(len * sizeof(Py_UCS4)); + output = PyMem_New(Py_UCS4, len); if (!output) { PyErr_NoMemory(); Py_DECREF(result); diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -233,7 +233,7 @@ Py_ssize_t len; len = PyUnicode_GET_LENGTH(prefix) + PyUnicode_GET_LENGTH(name) + 1; - p = buf = PyMem_Malloc(sizeof(Py_UCS4) * len); + p = buf = PyMem_New(Py_UCS4, len); if (buf == NULL) { PyErr_NoMemory(); return NULL; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2186,7 +2186,7 @@ } switch (kind) { case PyUnicode_2BYTE_KIND: - result = PyMem_Malloc(len * sizeof(Py_UCS2)); + result = PyMem_New(Py_UCS2, len); if (!result) return PyErr_NoMemory(); assert(skind == PyUnicode_1BYTE_KIND); @@ -2197,7 +2197,7 @@ result); return result; case PyUnicode_4BYTE_KIND: - result = PyMem_Malloc(len * sizeof(Py_UCS4)); + result = PyMem_New(Py_UCS4, len); if (!result) return PyErr_NoMemory(); if (skind == PyUnicode_2BYTE_KIND) { @@ -2239,11 +2239,7 @@ if (copy_null) targetlen++; if (!target) { - if (PY_SSIZE_T_MAX / sizeof(Py_UCS4) < targetlen) { - PyErr_NoMemory(); - return NULL; - } - target = PyMem_Malloc(targetlen * sizeof(Py_UCS4)); + target = PyMem_New(Py_UCS4, targetlen); if (!target) { PyErr_NoMemory(); return NULL; @@ -2852,12 +2848,7 @@ buflen = unicode_aswidechar(unicode, NULL, 0); if (buflen == -1) return NULL; - if (PY_SSIZE_T_MAX / sizeof(wchar_t) < buflen) { - PyErr_NoMemory(); - return NULL; - } - - buffer = PyMem_MALLOC(buflen * sizeof(wchar_t)); + buffer = PyMem_NEW(wchar_t, buflen); if (buffer == NULL) { PyErr_NoMemory(); return NULL; @@ -3550,10 +3541,7 @@ wstr = smallbuf; } else { - if (wlen > PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) - return PyErr_NoMemory(); - - wstr = PyMem_Malloc((wlen+1) * sizeof(wchar_t)); + wstr = PyMem_New(wchar_t, wlen+1); if (!wstr) return PyErr_NoMemory(); } diff --git a/PC/winreg.c b/PC/winreg.c --- a/PC/winreg.c +++ b/PC/winreg.c @@ -939,7 +939,7 @@ wchar_t *data = (wchar_t *)retDataBuf; int len = retDataSize / 2; int s = countStrings(data, len); - wchar_t **str = (wchar_t **)PyMem_Malloc(sizeof(wchar_t *)*s); + wchar_t **str = PyMem_New(wchar_t *, s); if (str == NULL) return PyErr_NoMemory(); @@ -1206,7 +1206,7 @@ ++retDataSize; bufDataSize = retDataSize; bufValueSize = retValueSize; - retValueBuf = (wchar_t *)PyMem_Malloc(sizeof(wchar_t) * retValueSize); + retValueBuf = PyMem_New(wchar_t, retValueSize); if (retValueBuf == NULL) return PyErr_NoMemory(); retDataBuf = (BYTE *)PyMem_Malloc(retDataSize); @@ -1277,7 +1277,7 @@ return PyErr_SetFromWindowsErrWithFunction(retValueSize, "ExpandEnvironmentStrings"); } - retValue = (wchar_t *)PyMem_Malloc(retValueSize * sizeof(wchar_t)); + retValue = PyMem_New(wchar_t, retValueSize); if (retValue == NULL) { return PyErr_NoMemory(); } diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -290,7 +290,7 @@ static unsigned int * markblocks(unsigned char *code, Py_ssize_t len) { - unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int)); + unsigned int *blocks = PyMem_New(unsigned int, len); int i,j, opcode, blockcnt = 0; if (blocks == NULL) { @@ -398,7 +398,7 @@ goto exitUnchanged; /* Mapping to new jump targets after NOPs are removed */ - addrmap = (int *)PyMem_Malloc(codelen * sizeof(int)); + addrmap = PyMem_New(int, codelen); if (addrmap == NULL) { PyErr_NoMemory(); goto exitError; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 20:14:27 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 19:14:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20150216191413.60726.40885@psf.io> https://hg.python.org/cpython/rev/c0e79e080307 changeset: 94655:c0e79e080307 parent: 94653:a84ae2ccd220 parent: 94654:b139f9d44a20 user: Serhiy Storchaka date: Mon Feb 16 20:54:23 2015 +0200 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 20:14:27 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 19:14:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Shoould_be_Py?= =?utf-8?b?X01JTiwgbm90IFB5X01BWC4=?= Message-ID: <20150216191413.60740.56660@psf.io> https://hg.python.org/cpython/rev/b139f9d44a20 changeset: 94654:b139f9d44a20 branch: 3.4 parent: 94651:036a2aceae93 user: Serhiy Storchaka date: Mon Feb 16 20:54:03 2015 +0200 summary: Shoould be Py_MIN, not Py_MAX. files: Modules/_tkinter.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -34,7 +34,7 @@ #endif #define CHECK_SIZE(size, elemsize) \ - ((size_t)(size) <= Py_MAX((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) + ((size_t)(size) <= Py_MIN((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, making _tkinter correct for this API means to break earlier -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 20:14:27 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 19:14:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323450=3A_Silenced?= =?utf-8?q?_compiler_warnings_and_added_asserts_in_peephole?= Message-ID: <20150216191414.60734.14465@psf.io> https://hg.python.org/cpython/rev/1eee26b74e4b changeset: 94656:1eee26b74e4b user: Serhiy Storchaka date: Mon Feb 16 21:13:24 2015 +0200 summary: Issue #23450: Silenced compiler warnings and added asserts in peephole optimizer. files: Python/peephole.c | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -18,7 +18,11 @@ || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP) #define JUMPS_ON_TRUE(op) (op==POP_JUMP_IF_TRUE || op==JUMP_IF_TRUE_OR_POP) #define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3)) -#define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255 +#define SETARG(arr, i, val) do { \ + assert(0 <= val && val <= 0xffff); \ + arr[i+2] = (unsigned char)(((unsigned int)val)>>8); \ + arr[i+1] = (unsigned char)(((unsigned int)val) & 255); \ +} while(0) #define CODESIZE(op) (HAS_ARG(op) ? 3 : 1) #define ISBASICBLOCK(blocks, start, bytes) \ (blocks[start]==blocks[start+bytes-1]) @@ -355,7 +359,8 @@ unsigned char *codestr = NULL; unsigned char *lineno; int *addrmap = NULL; - int new_line, cum_orig_line, last_line, tabsiz; + int new_line, cum_orig_line, last_line; + Py_ssize_t tabsiz; PyObject **const_stack = NULL; Py_ssize_t *load_const_stack = NULL; Py_ssize_t const_stack_top = -1; @@ -660,7 +665,8 @@ /* Fixup linenotab */ for (i=0, nops=0 ; i https://hg.python.org/cpython/rev/a84ae2ccd220 changeset: 94653:a84ae2ccd220 user: Serhiy Storchaka date: Mon Feb 16 20:52:17 2015 +0200 summary: Issue #23450: Fixed possible integer overflows. files: Modules/_ctypes/_ctypes.c | 2 +- Modules/_elementtree.c | 57 +++++++++++++++----------- Modules/_sqlite/row.c | 2 +- Modules/_tkinter.c | 45 +++++++++++--------- Objects/bytesobject.c | 2 +- Objects/obmalloc.c | 2 +- Python/codecs.c | 2 +- Python/marshal.c | 2 +- 8 files changed, 64 insertions(+), 50 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -301,7 +301,7 @@ char *new_prefix; char *result; char buf[32]; - int prefix_len; + Py_ssize_t prefix_len; int k; prefix_len = 32 * ndim + 3; diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -11,6 +11,8 @@ *-------------------------------------------------------------------- */ +#define PY_SSIZE_T_CLEAN + #include "Python.h" #include "structmember.h" @@ -185,8 +187,8 @@ PyObject* attrib; /* child elements */ - int length; /* actual number of items */ - int allocated; /* allocated items */ + Py_ssize_t length; /* actual number of items */ + Py_ssize_t allocated; /* allocated items */ /* this either points to _children or to a malloced buffer */ PyObject* *children; @@ -251,7 +253,7 @@ dealloc_extra(ElementObject* self) { ElementObjectExtra *myextra; - int i; + Py_ssize_t i; if (!self->extra) return; @@ -429,9 +431,9 @@ } LOCAL(int) -element_resize(ElementObject* self, int extra) +element_resize(ElementObject* self, Py_ssize_t extra) { - int size; + Py_ssize_t size; PyObject* *children; /* make sure self->children can hold the given number of extra @@ -442,7 +444,7 @@ return -1; } - size = self->extra->length + extra; + size = self->extra->length + extra; /* never overflows */ if (size > self->extra->allocated) { /* use Python 2.4's list growth strategy */ @@ -453,6 +455,8 @@ * be safe. */ size = size ? size : 1; + if ((size_t)size > PY_SSIZE_T_MAX/sizeof(PyObject*)) + goto nomemory; if (self->extra->children != self->extra->_children) { /* Coverity CID #182 size_error: Allocating 1 bytes to pointer * "children", which needs at least 4 bytes. Although it's a @@ -613,7 +617,7 @@ Py_VISIT(JOIN_OBJ(self->tail)); if (self->extra) { - int i; + Py_ssize_t i; Py_VISIT(self->extra->attrib); for (i = 0; i < self->extra->length; ++i) @@ -689,7 +693,7 @@ static PyObject* element_copy(ElementObject* self, PyObject* args) { - int i; + Py_ssize_t i; ElementObject* element; if (!PyArg_ParseTuple(args, ":__copy__")) @@ -728,7 +732,7 @@ static PyObject* element_deepcopy(ElementObject* self, PyObject* args) { - int i; + Py_ssize_t i; ElementObject* element; PyObject* tag; PyObject* attrib; @@ -839,7 +843,7 @@ static PyObject * element_getstate(ElementObject *self) { - int i, noattrib; + Py_ssize_t i, noattrib; PyObject *instancedict = NULL, *children; /* Build a list of children. */ @@ -1077,7 +1081,7 @@ static PyObject* element_find(ElementObject *self, PyObject *args, PyObject *kwds) { - int i; + Py_ssize_t i; PyObject* tag; PyObject* namespaces = Py_None; static char *kwlist[] = {"path", "namespaces", 0}; @@ -1112,7 +1116,7 @@ static PyObject* element_findtext(ElementObject *self, PyObject *args, PyObject *kwds) { - int i; + Py_ssize_t i; PyObject* tag; PyObject* default_value = Py_None; PyObject* namespaces = Py_None; @@ -1153,7 +1157,7 @@ static PyObject* element_findall(ElementObject *self, PyObject *args, PyObject *kwds) { - int i; + Py_ssize_t i; PyObject* out; PyObject* tag; PyObject* namespaces = Py_None; @@ -1238,7 +1242,7 @@ static PyObject* element_getchildren(ElementObject* self, PyObject* args) { - int i; + Py_ssize_t i; PyObject* list; /* FIXME: report as deprecated? */ @@ -1310,11 +1314,9 @@ static PyObject* element_insert(ElementObject* self, PyObject* args) { - int i; - - int index; + Py_ssize_t index, i; PyObject* element; - if (!PyArg_ParseTuple(args, "iO!:insert", &index, + if (!PyArg_ParseTuple(args, "nO!:insert", &index, &Element_Type, &element)) return NULL; @@ -1402,7 +1404,7 @@ static PyObject* element_remove(ElementObject* self, PyObject* args) { - int i; + Py_ssize_t i; PyObject* element; if (!PyArg_ParseTuple(args, "O!:remove", &Element_Type, &element)) @@ -1481,7 +1483,7 @@ element_setitem(PyObject* self_, Py_ssize_t index, PyObject* item) { ElementObject* self = (ElementObject*) self_; - int i; + Py_ssize_t i; PyObject* old; if (!self->extra || index < 0 || index >= self->extra->length) { @@ -2819,12 +2821,13 @@ * message string is the default for the given error_code. */ static void -expat_set_error(enum XML_Error error_code, int line, int column, char *message) +expat_set_error(enum XML_Error error_code, Py_ssize_t line, Py_ssize_t column, + const char *message) { PyObject *errmsg, *error, *position, *code; elementtreestate *st = ET_STATE_GLOBAL; - errmsg = PyUnicode_FromFormat("%s: line %d, column %d", + errmsg = PyUnicode_FromFormat("%s: line %zd, column %zd", message ? message : EXPAT(ErrorString)(error_code), line, column); if (errmsg == NULL) @@ -2848,7 +2851,7 @@ } Py_DECREF(code); - position = Py_BuildValue("(ii)", line, column); + position = Py_BuildValue("(nn)", line, column); if (!position) { Py_DECREF(error); return; @@ -3477,8 +3480,14 @@ break; } + if (PyBytes_GET_SIZE(buffer) > INT_MAX) { + Py_DECREF(buffer); + Py_DECREF(reader); + PyErr_SetString(PyExc_OverflowError, "size does not fit in an int"); + return NULL; + } res = expat_parse( - self, PyBytes_AS_STRING(buffer), PyBytes_GET_SIZE(buffer), 0 + self, PyBytes_AS_STRING(buffer), (int)PyBytes_GET_SIZE(buffer), 0 ); Py_DECREF(buffer); diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c --- a/Modules/_sqlite/row.c +++ b/Modules/_sqlite/row.c @@ -159,7 +159,7 @@ PyObject* pysqlite_row_keys(pysqlite_Row* self, PyObject* args, PyObject* kwargs) { PyObject* list; - int nitems, i; + Py_ssize_t nitems, i; list = PyList_New(0); if (!list) { diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -21,6 +21,7 @@ */ +#define PY_SSIZE_T_CLEAN #include "Python.h" #include @@ -34,7 +35,7 @@ #endif #define CHECK_SIZE(size, elemsize) \ - ((size_t)(size) <= Py_MAX((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) + ((size_t)(size) <= Py_MIN((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) /* If Tcl is compiled for threads, we must also define TCL_THREAD. We define it always; if Tcl is not threaded, the thread functions in @@ -409,7 +410,7 @@ SplitObj(PyObject *arg) { if (PyTuple_Check(arg)) { - int i, size; + Py_ssize_t i, size; PyObject *elem, *newelem, *result; size = PyTuple_Size(arg); @@ -425,7 +426,7 @@ return NULL; } if (!result) { - int k; + Py_ssize_t k; if (newelem == elem) { Py_DECREF(newelem); continue; @@ -446,7 +447,7 @@ /* Fall through, returning arg. */ } else if (PyList_Check(arg)) { - int i, size; + Py_ssize_t i, size; PyObject *elem, *newelem, *result; size = PyList_GET_SIZE(arg); @@ -632,12 +633,12 @@ /* some initial arguments need to be in argv */ if (sync || use) { char *args; - int len = 0; + Py_ssize_t len = 0; if (sync) len += sizeof "-sync"; if (use) - len += strlen(use) + sizeof "-use "; + len += strlen(use) + sizeof "-use "; /* never overflows */ args = (char*)PyMem_Malloc(len); if (!args) { @@ -887,9 +888,14 @@ long longVal; int overflow; - if (PyBytes_Check(value)) + if (PyBytes_Check(value)) { + if (PyBytes_GET_SIZE(value) >= INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "bytes object is too long"); + return NULL; + } return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(value), - PyBytes_GET_SIZE(value)); + (int)PyBytes_GET_SIZE(value)); + } else if (PyBool_Check(value)) return Tcl_NewBooleanObj(PyObject_IsTrue(value)); else if (PyLong_CheckExact(value) && @@ -921,7 +927,7 @@ } for (i = 0; i < size; i++) argv[i] = AsObj(PySequence_Fast_GET_ITEM(value,i)); - result = Tcl_NewListObj(size, argv); + result = Tcl_NewListObj((int)size, argv); PyMem_Free(argv); return result; } @@ -946,7 +952,7 @@ } kind = PyUnicode_KIND(value); if (kind == sizeof(Tcl_UniChar)) - return Tcl_NewUnicodeObj(inbuf, size); + return Tcl_NewUnicodeObj(inbuf, (int)size); allocsize = ((size_t)size) * sizeof(Tcl_UniChar); outbuf = (Tcl_UniChar*)PyMem_Malloc(allocsize); /* Else overflow occurred, and we take the next exit */ @@ -971,7 +977,7 @@ #endif outbuf[i] = ch; } - result = Tcl_NewUnicodeObj(outbuf, size); + result = Tcl_NewUnicodeObj(outbuf, (int)size); PyMem_Free(outbuf); return result; } @@ -1139,10 +1145,10 @@ Tcl_IncrRefCount(objv[i]); } } - *pobjc = objc; + *pobjc = (int)objc; return objv; finally: - Tkapp_CallDeallocArgs(objv, objStore, objc); + Tkapp_CallDeallocArgs(objv, objStore, (int)objc); return NULL; } @@ -1495,7 +1501,6 @@ #ifdef WITH_THREAD TkappObject *self = (TkappObject*)selfptr; if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { - TkappObject *self = (TkappObject*)selfptr; VarEvent *ev; PyObject *res, *exc_type, *exc_val; Tcl_Condition cond = NULL; @@ -2721,20 +2726,20 @@ typedef struct { PyObject* tuple; - int size; /* current size */ - int maxsize; /* allocated size */ + Py_ssize_t size; /* current size */ + Py_ssize_t maxsize; /* allocated size */ } FlattenContext; static int -_bump(FlattenContext* context, int size) +_bump(FlattenContext* context, Py_ssize_t size) { /* expand tuple to hold (at least) size new items. return true if successful, false if an exception was raised */ - int maxsize = context->maxsize * 2; + Py_ssize_t maxsize = context->maxsize * 2; /* never overflows */ if (maxsize < context->size + size) - maxsize = context->size + size; + maxsize = context->size + size; /* never overflows */ context->maxsize = maxsize; @@ -2746,7 +2751,7 @@ { /* add tuple or list to argument tuple (recursively) */ - int i, size; + Py_ssize_t i, size; if (depth > 1000) { PyErr_SetString(PyExc_ValueError, diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -673,7 +673,7 @@ "* wants int"); goto error; } - prec = PyLong_AsSsize_t(v); + prec = _PyLong_AsInt(v); if (prec == -1 && PyErr_Occurred()) goto error; if (prec < 0) diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1339,7 +1339,7 @@ pool = (poolp)usable_arenas->pool_address; assert((block*)pool <= (block*)usable_arenas->address + ARENA_SIZE - POOL_SIZE); - pool->arenaindex = usable_arenas - arenas; + pool->arenaindex = (uint)(usable_arenas - arenas); assert(&arenas[pool->arenaindex] == usable_arenas); pool->szidx = DUMMY_SIZE_IDX; usable_arenas->pool_address += POOL_SIZE; diff --git a/Python/codecs.c b/Python/codecs.c --- a/Python/codecs.c +++ b/Python/codecs.c @@ -1006,7 +1006,7 @@ c = PyUnicode_READ_CHAR(object, i); if (ucnhash_CAPI && ucnhash_CAPI->getname(NULL, c, buffer, sizeof(buffer), 1)) { - replsize = 1+1+1+strlen(buffer)+1; + replsize = 1+1+1+(int)strlen(buffer)+1; } else if (c >= 0x10000) { replsize = 1+1+8; diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -279,7 +279,7 @@ PyErr_SetString(PyExc_ValueError, "too many objects"); goto err; } - w = s; + w = (int)s; Py_INCREF(v); if (_Py_HASHTABLE_SET(p->hashtable, v, w) < 0) { Py_DECREF(v); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 16 22:59:47 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 16 Feb 2015 21:59:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_sizeof_tests_for_Ele?= =?utf-8?q?mentTree_=28issue_=2323450=29=2E?= Message-ID: <20150216215927.72259.65122@psf.io> https://hg.python.org/cpython/rev/f47d683b6c9e changeset: 94657:f47d683b6c9e user: Serhiy Storchaka date: Mon Feb 16 23:58:46 2015 +0200 summary: Fixed sizeof tests for ElementTree (issue #23450). files: Lib/test/test_xml_etree_c.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -55,7 +55,7 @@ def setUp(self): self.elementsize = support.calcobjsize('5P') # extra - self.extra = struct.calcsize('PiiP4P') + self.extra = struct.calcsize('PnnP4P') check_sizeof = support.check_sizeof -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 01:55:58 2015 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 17 Feb 2015 00:55:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogZml4IHB5ZG9jLmFw?= =?utf-8?q?ropos_and_pydoc=2Esynopsis_on_modules_with_empty_docstrings_=28?= =?utf-8?q?=2321548=29?= Message-ID: <20150217004547.4965.55881@psf.io> https://hg.python.org/cpython/rev/9436f43b6df2 changeset: 94658:9436f43b6df2 branch: 3.4 parent: 94654:b139f9d44a20 user: Benjamin Peterson date: Mon Feb 16 19:45:01 2015 -0500 summary: fix pydoc.apropos and pydoc.synopsis on modules with empty docstrings (#21548) Patch by Yuyang Guo and Berker Peksag. files: Lib/pydoc.py | 4 +- Lib/test/test_pydoc.py | 32 ++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 ++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -270,7 +270,7 @@ except: return None del sys.modules['__temp__'] - result = (module.__doc__ or '').splitlines()[0] + result = module.__doc__.splitlines()[0] if module.__doc__ else None # Cache the result. cache[filename] = (mtime, result) return result @@ -2075,7 +2075,7 @@ if onerror: onerror(modname) continue - desc = (module.__doc__ or '').splitlines()[0] + desc = module.__doc__.splitlines()[0] if module.__doc__ else '' path = getattr(module,'__file__',None) name = modname + ' - ' + desc if name.lower().find(key) >= 0: diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -3,12 +3,15 @@ import builtins import contextlib import difflib +import importlib.util import inspect import pydoc +import py_compile import keyword import _pickle import pkgutil import re +import stat import string import test.support import time @@ -557,6 +560,18 @@ self.assertEqual(synopsis, expected) + def test_synopsis_sourceless_empty_doc(self): + with test.support.temp_cwd() as test_dir: + init_path = os.path.join(test_dir, 'foomod42.py') + cached_path = importlib.util.cache_from_source(init_path) + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + py_compile.compile(init_path) + synopsis = pydoc.synopsis(init_path, {}) + self.assertIsNone(synopsis) + synopsis_cached = pydoc.synopsis(cached_path, {}) + self.assertIsNone(synopsis_cached) + def test_splitdoc_with_description(self): example_string = "I Am A Doc\n\n\nHere is my description" self.assertEqual(pydoc.splitdoc(example_string), @@ -612,6 +627,7 @@ def setUp(self): self.test_dir = os.mkdir(TESTFN) self.addCleanup(rmtree, TESTFN) + importlib.invalidate_caches() def test_badimport(self): # This tests the fix for issue 5230, where if pydoc found the module @@ -670,6 +686,22 @@ self.assertEqual(out.getvalue(), '') self.assertEqual(err.getvalue(), '') + def test_apropos_empty_doc(self): + pkgdir = os.path.join(TESTFN, 'walkpkg') + os.mkdir(pkgdir) + self.addCleanup(rmtree, pkgdir) + init_path = os.path.join(pkgdir, '__init__.py') + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + current_mode = stat.S_IMODE(os.stat(pkgdir).st_mode) + try: + os.chmod(pkgdir, current_mode & ~stat.S_IEXEC) + with self.restrict_walk_packages(path=[TESTFN]), captured_stdout() as stdout: + pydoc.apropos('') + self.assertIn('walkpkg', stdout.getvalue()) + finally: + os.chmod(pkgdir, current_mode) + @unittest.skip('causes undesireable side-effects (#20128)') def test_modules(self): # See Helper.listmodules(). diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -506,6 +506,7 @@ Dag Gruneau Filip Gruszczy?ski Thomas Guettler +Yuyang Guo Anuj Gupta Michael Guravage Lars Gust?bel diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty + docstrings. + - Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb module. Original patch by Claudiu Popa. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 01:55:58 2015 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 17 Feb 2015 00:55:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjE1NDgp?= Message-ID: <20150217004547.6005.50886@psf.io> https://hg.python.org/cpython/rev/534b26837a13 changeset: 94659:534b26837a13 parent: 94657:f47d683b6c9e parent: 94658:9436f43b6df2 user: Benjamin Peterson date: Mon Feb 16 19:45:42 2015 -0500 summary: merge 3.4 (#21548) files: Lib/pydoc.py | 4 +- Lib/test/test_pydoc.py | 32 ++++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 ++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -269,7 +269,7 @@ except: return None del sys.modules['__temp__'] - result = (module.__doc__ or '').splitlines()[0] + result = module.__doc__.splitlines()[0] if module.__doc__ else None # Cache the result. cache[filename] = (mtime, result) return result @@ -2073,7 +2073,7 @@ if onerror: onerror(modname) continue - desc = (module.__doc__ or '').splitlines()[0] + desc = module.__doc__.splitlines()[0] if module.__doc__ else '' path = getattr(module,'__file__',None) name = modname + ' - ' + desc if name.lower().find(key) >= 0: diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -2,12 +2,15 @@ import sys import builtins import contextlib +import importlib.util import inspect import pydoc +import py_compile import keyword import _pickle import pkgutil import re +import stat import string import test.support import time @@ -543,6 +546,18 @@ self.assertEqual(synopsis, expected) + def test_synopsis_sourceless_empty_doc(self): + with test.support.temp_cwd() as test_dir: + init_path = os.path.join(test_dir, 'foomod42.py') + cached_path = importlib.util.cache_from_source(init_path) + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + py_compile.compile(init_path) + synopsis = pydoc.synopsis(init_path, {}) + self.assertIsNone(synopsis) + synopsis_cached = pydoc.synopsis(cached_path, {}) + self.assertIsNone(synopsis_cached) + def test_splitdoc_with_description(self): example_string = "I Am A Doc\n\n\nHere is my description" self.assertEqual(pydoc.splitdoc(example_string), @@ -598,6 +613,7 @@ def setUp(self): self.test_dir = os.mkdir(TESTFN) self.addCleanup(rmtree, TESTFN) + importlib.invalidate_caches() def test_badimport(self): # This tests the fix for issue 5230, where if pydoc found the module @@ -656,6 +672,22 @@ self.assertEqual(out.getvalue(), '') self.assertEqual(err.getvalue(), '') + def test_apropos_empty_doc(self): + pkgdir = os.path.join(TESTFN, 'walkpkg') + os.mkdir(pkgdir) + self.addCleanup(rmtree, pkgdir) + init_path = os.path.join(pkgdir, '__init__.py') + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + current_mode = stat.S_IMODE(os.stat(pkgdir).st_mode) + try: + os.chmod(pkgdir, current_mode & ~stat.S_IEXEC) + with self.restrict_walk_packages(path=[TESTFN]), captured_stdout() as stdout: + pydoc.apropos('') + self.assertIn('walkpkg', stdout.getvalue()) + finally: + os.chmod(pkgdir, current_mode) + @unittest.skip('causes undesireable side-effects (#20128)') def test_modules(self): # See Helper.listmodules(). diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -513,6 +513,7 @@ Dag Gruneau Filip Gruszczy?ski Thomas Guettler +Yuyang Guo Anuj Gupta Michael Guravage Lars Gust?bel diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty + docstrings. + - Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb module. Original patch by Claudiu Popa. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Tue Feb 17 06:23:43 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 17 Feb 2015 06:23:43 +0100 Subject: [Python-checkins] Daily reference leaks (f47d683b6c9e): sum=484 Message-ID: results for f47d683b6c9e on branch "default" -------------------------------------------- test_asyncio leaked [388, 388, 388] references, sum=1164 test_asyncio leaked [84, 85, 88] memory blocks, sum=257 test_eintr leaked [-388, 0, 0] references, sum=-388 test_eintr leaked [-84, 2, 0] memory blocks, sum=-82 test_faulthandler leaked [0, -388, 0] references, sum=-388 test_faulthandler leaked [0, -84, 2] memory blocks, sum=-82 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogYpffGe', '-x'] From python-checkins at python.org Tue Feb 17 09:19:55 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 17 Feb 2015 08:19:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322883=3A_Got_rid_?= =?utf-8?q?of_outdated_references_to_PyInt_and_PyString_in_comments=2E?= Message-ID: <20150217081946.126616.13041@psf.io> https://hg.python.org/cpython/rev/2f0c1937d716 changeset: 94660:2f0c1937d716 user: Serhiy Storchaka date: Tue Feb 17 10:14:30 2015 +0200 summary: Issue #22883: Got rid of outdated references to PyInt and PyString in comments. files: Lib/test/test_getargs2.py | 4 ++-- Modules/_io/_iomodule.h | 2 +- Modules/_json.c | 8 ++++---- Modules/_sqlite/connection.h | 2 +- Modules/fcntlmodule.c | 7 ++----- Modules/itertoolsmodule.c | 2 +- Python/ceval.c | 2 +- 7 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -34,8 +34,8 @@ # > ** Changed from previous "range-and-a-half" to "none"; the # > range-and-a-half checking wasn't particularly useful. # -# Plus a C API or two, e.g. PyInt_AsLongMask() -> -# unsigned long and PyInt_AsLongLongMask() -> unsigned +# Plus a C API or two, e.g. PyLong_AsUnsignedLongMask() -> +# unsigned long and PyLong_AsUnsignedLongLongMask() -> unsigned # long long (if that exists). LARGE = 0x7FFFFFFF diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -69,7 +69,7 @@ * Offset type for positioning. */ -/* Printing a variable of type off_t (with e.g., PyString_FromFormat) +/* Printing a variable of type off_t (with e.g., PyUnicode_FromFormat) correctly and without producing compiler warnings is surprisingly painful. We identify an integer type whose size matches off_t and then: (1) cast the off_t to that integer type and (2) use the appropriate conversion diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -827,7 +827,7 @@ static PyObject * _parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) { - /* Read a JSON array from PyString pystr. + /* Read a JSON array from PyUnicode pystr. idx is the index of the first character after the opening brace. *next_idx_ptr is a return-by-reference index to the first character after the closing brace. @@ -899,8 +899,8 @@ } static PyObject * -_parse_constant(PyScannerObject *s, char *constant, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) { - /* Read a JSON constant from PyString pystr. +_parse_constant(PyScannerObject *s, const char *constant, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) { + /* Read a JSON constant. constant is the constant string that was found ("NaN", "Infinity", "-Infinity"). idx is the index of the first character of the constant @@ -932,7 +932,7 @@ the number. Returns a new PyObject representation of that number: - PyInt, PyLong, or PyFloat. + PyLong, or PyFloat. May return other types if parse_int or parse_float are set */ void *str; diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -52,7 +52,7 @@ * first get called with count=0? */ double timeout_started; - /* None for autocommit, otherwise a PyString with the isolation level */ + /* None for autocommit, otherwise a PyUnicode with the isolation level */ PyObject* isolation_level; /* NULL for autocommit, otherwise a string with the BEGIN statement; will be diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -152,11 +152,8 @@ /*[clinic end generated code: output=ad47738c118622bf input=a55a6ee8e494c449]*/ { #define IOCTL_BUFSZ 1024 - /* We use the unsigned non-checked 'I' - format for the 'code' parameter because Python turns 0x8000000 - into either a large positive number (PyLong or PyInt on 64-bit - platforms) or a negative number on others (32-bit PyInt) - whereas the system expects it to be a 32bit bit field value + /* We use the unsigned non-checked 'I' format for the 'code' parameter + because the system expects it to be a 32bit bit field value regardless of it being passed as an int or unsigned long on various platforms. See the termios.TIOCSWINSZ constant across platforms for an example of this. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -3874,7 +3874,7 @@ fast_mode: when cnt an integer < PY_SSIZE_T_MAX and no step is specified. - assert(cnt != PY_SSIZE_T_MAX && long_cnt == NULL && long_step==PyInt(1)); + assert(cnt != PY_SSIZE_T_MAX && long_cnt == NULL && long_step==PyLong(1)); Advances with: cnt += 1 When count hits Y_SSIZE_T_MAX, switch to slow_mode. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4606,7 +4606,7 @@ return result; } -/* Extract a slice index from a PyInt or PyLong or an object with the +/* Extract a slice index from a PyLong or an object with the nb_index slot defined, and store in *pi. Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 09:20:11 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 17 Feb 2015 08:20:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322883=3A_Update_PyInt_to_PyLong_in_C_API_exampl?= =?utf-8?q?e=2E?= Message-ID: <20150217081946.11013.71769@psf.io> https://hg.python.org/cpython/rev/c0b2dacef35c changeset: 94662:c0b2dacef35c parent: 94660:2f0c1937d716 parent: 94661:c8d08de14030 user: Serhiy Storchaka date: Tue Feb 17 10:19:07 2015 +0200 summary: Issue #22883: Update PyInt to PyLong in C API example. files: Doc/extending/newtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -1205,7 +1205,7 @@ { if (strcmp(name, "data") == 0) { - return PyInt_FromLong(obj->data); + return PyLong_FromLong(obj->data); } PyErr_Format(PyExc_AttributeError, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 09:20:11 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 17 Feb 2015 08:20:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODgz?= =?utf-8?q?=3A_Update_PyInt_to_PyLong_in_C_API_example=2E?= Message-ID: <20150217081946.10999.16062@psf.io> https://hg.python.org/cpython/rev/c8d08de14030 changeset: 94661:c8d08de14030 branch: 3.4 parent: 94658:9436f43b6df2 user: Serhiy Storchaka date: Tue Feb 17 10:18:44 2015 +0200 summary: Issue #22883: Update PyInt to PyLong in C API example. files: Doc/extending/newtypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -1205,7 +1205,7 @@ { if (strcmp(name, "data") == 0) { - return PyInt_FromLong(obj->data); + return PyLong_FromLong(obj->data); } PyErr_Format(PyExc_AttributeError, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:14:21 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:14:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDc1?= =?utf-8?q?=2C_asyncio=3A_Fix_test=5Fclose=5Fkill=5Frunning=28=29?= Message-ID: <20150217221418.5033.98143@psf.io> https://hg.python.org/cpython/rev/0f6ddf944521 changeset: 94665:0f6ddf944521 branch: 3.4 user: Victor Stinner date: Tue Feb 17 22:54:11 2015 +0100 summary: Issue #23475, asyncio: Fix test_close_kill_running() Really kill the child process, don't mock completly the Popen.kill() method. This change fix memory leaks and reference leaks. files: Lib/test/test_asyncio/test_subprocess.py | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -355,11 +355,19 @@ create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, *PROGRAM_BLOCKED) transport, protocol = yield from create + + kill_called = False + def kill(): + nonlocal kill_called + kill_called = True + orig_kill() + proc = transport.get_extra_info('subprocess') - proc.kill = mock.Mock() + orig_kill = proc.kill + proc.kill = kill returncode = transport.get_returncode() transport.close() - return (returncode, proc.kill.called) + return (returncode, kill_called) # Ignore "Close running child process: kill ..." log with test_utils.disable_logger(): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:14:21 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:14:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_fix_the_sphinx_extension_for_coroutine_commands?= Message-ID: <20150217221418.5051.77144@psf.io> https://hg.python.org/cpython/rev/73253aead830 changeset: 94667:73253aead830 branch: 3.4 parent: 94665:0f6ddf944521 user: Victor Stinner date: Tue Feb 17 23:08:35 2015 +0100 summary: asyncio doc: fix the sphinx extension for coroutine commands files: Doc/tools/extensions/pyspecific.py | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -148,17 +148,12 @@ class PyCoroutineMixin(object): def handle_signature(self, sig, signode): ret = super(PyCoroutineMixin, self).handle_signature(sig, signode) -# signode.insert(0, addnodes.desc_addname('coroutine ', 'coroutine ')) signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine ')) return ret - def needs_arglist(self): - return False - class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel): def run(self): - # a decorator function is a function after all self.name = 'py:function' return PyModulelevel.run(self) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:14:21 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:14:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogQmFz?= =?utf-8?q?eSubprocessTransport=3A_repr=28=29_mentions_when_the_child_proc?= =?utf-8?q?ess_is?= Message-ID: <20150217221418.5027.54698@psf.io> https://hg.python.org/cpython/rev/0f9da9410914 changeset: 94663:0f9da9410914 branch: 3.4 parent: 94661:c8d08de14030 user: Victor Stinner date: Tue Feb 17 22:50:33 2015 +0100 summary: asyncio: BaseSubprocessTransport: repr() mentions when the child process is running files: Lib/asyncio/base_subprocess.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -57,6 +57,8 @@ info.append('pid=%s' % self._pid) if self._returncode is not None: info.append('returncode=%s' % self._returncode) + else: + info.append('running') stdin = self._pipes.get(0) if stdin is not None: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:14:21 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:14:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio_doc=29?= Message-ID: <20150217221419.12772.41627@psf.io> https://hg.python.org/cpython/rev/6434aab53114 changeset: 94669:6434aab53114 parent: 94666:6f75c7c6e260 parent: 94668:6beaf66f0410 user: Victor Stinner date: Tue Feb 17 23:11:56 2015 +0100 summary: Merge 3.4 (asyncio doc) files: Doc/library/asyncio-sync.rst | 98 +++++++++-------- Doc/tools/extensions/pyspecific.py | 5 - 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -310,6 +310,9 @@ be interrupted between calling :meth:`qsize` and doing an operation on the Queue. + .. versionchanged:: 3.4.3 + New :meth:`join` and :meth:`task_done` methods. + .. method:: empty() Return ``True`` if the queue is empty, ``False`` otherwise. @@ -341,6 +344,20 @@ Return an item if one is immediately available, else raise :exc:`QueueEmpty`. + .. coroutinemethod:: join() + + Block until all items in the queue have been gotten and processed. + + The count of unfinished tasks goes up whenever an item is added to the + queue. The count goes down whenever a consumer thread calls + :meth:`task_done` to indicate that the item was retrieved and all work on + it is complete. When the count of unfinished tasks drops to zero, + :meth:`join` unblocks. + + This method is a :ref:`coroutine `. + + .. versionadded:: 3.4.3 + .. coroutinemethod:: put(item) Put an item into the queue. If the queue is full, wait until a free slot @@ -362,51 +379,6 @@ Number of items in the queue. - .. attribute:: maxsize - - Number of items allowed in the queue. - - -PriorityQueue -^^^^^^^^^^^^^ - -.. class:: PriorityQueue - - A subclass of :class:`Queue`; retrieves entries in priority order (lowest - first). - - Entries are typically tuples of the form: (priority number, data). - - -LifoQueue -^^^^^^^^^ - -.. class:: LifoQueue - - A subclass of :class:`Queue` that retrieves most recently added entries - first. - - -JoinableQueue -^^^^^^^^^^^^^ - -.. class:: JoinableQueue - - A subclass of :class:`Queue` with :meth:`task_done` and :meth:`join` - methods. - - .. coroutinemethod:: join() - - Block until all items in the queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls - :meth:`task_done` to indicate that the item was retrieved and all work on - it is complete. When the count of unfinished tasks drops to zero, - :meth:`join` unblocks. - - This method is a :ref:`coroutine `. - .. method:: task_done() Indicate that a formerly enqueued task is complete. @@ -422,6 +394,42 @@ Raises :exc:`ValueError` if called more times than there were items placed in the queue. + .. versionadded:: 3.4.3 + + .. attribute:: maxsize + + Number of items allowed in the queue. + + +PriorityQueue +^^^^^^^^^^^^^ + +.. class:: PriorityQueue + + A subclass of :class:`Queue`; retrieves entries in priority order (lowest + first). + + Entries are typically tuples of the form: (priority number, data). + + +LifoQueue +^^^^^^^^^ + +.. class:: LifoQueue + + A subclass of :class:`Queue` that retrieves most recently added entries + first. + + +JoinableQueue +^^^^^^^^^^^^^ + +.. class:: JoinableQueue + + Deprecated alias for :class:`Queue`. + + .. deprecated:: 3.4.3 + Exceptions ^^^^^^^^^^ diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -148,17 +148,12 @@ class PyCoroutineMixin(object): def handle_signature(self, sig, signode): ret = super(PyCoroutineMixin, self).handle_signature(sig, signode) -# signode.insert(0, addnodes.desc_addname('coroutine ', 'coroutine ')) signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine ')) return ret - def needs_arglist(self): - return False - class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel): def run(self): - # a decorator function is a function after all self.name = 'py:function' return PyModulelevel.run(self) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:14:21 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:14:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbywgVHVs?= =?utf-8?q?ip_issue_220=3A_Merge_JoinableQueue_with_Queue=2E?= Message-ID: <20150217221418.13138.98823@psf.io> https://hg.python.org/cpython/rev/1f36f0f23e87 changeset: 94664:1f36f0f23e87 branch: 3.4 user: Victor Stinner date: Tue Feb 17 22:53:28 2015 +0100 summary: asyncio, Tulip issue 220: Merge JoinableQueue with Queue. Merge JoinableQueue with Queue. To more closely match the standard Queue, asyncio.Queue has "join" and "task_done". JoinableQueue is deleted. Docstring for Queue.join shouldn't mention threads. Restore JoinableQueue as a deprecated alias for Queue. To more closely match the standard Queue, asyncio.Queue has "join" and "task_done". JoinableQueue remains as a deprecated alias for Queue to avoid needlessly breaking too much code that depended on it. Patch written by A. Jesse Jiryu Davis . files: Lib/asyncio/queues.py | 104 ++++++-------- Lib/test/test_asyncio/test_queues.py | 10 +- 2 files changed, 49 insertions(+), 65 deletions(-) diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -1,7 +1,7 @@ """Queues""" -__all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'JoinableQueue', - 'QueueFull', 'QueueEmpty'] +__all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'QueueFull', 'QueueEmpty', + 'JoinableQueue'] import collections import heapq @@ -49,6 +49,9 @@ self._getters = collections.deque() # Pairs of (item, Future). self._putters = collections.deque() + self._unfinished_tasks = 0 + self._finished = locks.Event(loop=self._loop) + self._finished.set() self._init(maxsize) def _init(self, maxsize): @@ -59,6 +62,8 @@ def _put(self, item): self._queue.append(item) + self._unfinished_tasks += 1 + self._finished.clear() def __repr__(self): return '<{} at {:#x} {}>'.format( @@ -75,6 +80,8 @@ result += ' _getters[{}]'.format(len(self._getters)) if self._putters: result += ' _putters[{}]'.format(len(self._putters)) + if self._unfinished_tasks: + result += ' tasks={}'.format(self._unfinished_tasks) return result def _consume_done_getters(self): @@ -126,9 +133,6 @@ 'queue non-empty, why are getters waiting?') getter = self._getters.popleft() - - # Use _put and _get instead of passing item straight to getter, in - # case a subclass has logic that must run (e.g. JoinableQueue). self._put(item) # getter cannot be cancelled, we just removed done getters @@ -154,9 +158,6 @@ 'queue non-empty, why are getters waiting?') getter = self._getters.popleft() - - # Use _put and _get instead of passing item straight to getter, in - # case a subclass has logic that must run (e.g. JoinableQueue). self._put(item) # getter cannot be cancelled, we just removed done getters @@ -219,56 +220,6 @@ else: raise QueueEmpty - -class PriorityQueue(Queue): - """A subclass of Queue; retrieves entries in priority order (lowest first). - - Entries are typically tuples of the form: (priority number, data). - """ - - def _init(self, maxsize): - self._queue = [] - - def _put(self, item, heappush=heapq.heappush): - heappush(self._queue, item) - - def _get(self, heappop=heapq.heappop): - return heappop(self._queue) - - -class LifoQueue(Queue): - """A subclass of Queue that retrieves most recently added entries first.""" - - def _init(self, maxsize): - self._queue = [] - - def _put(self, item): - self._queue.append(item) - - def _get(self): - return self._queue.pop() - - -class JoinableQueue(Queue): - """A subclass of Queue with task_done() and join() methods.""" - - def __init__(self, maxsize=0, *, loop=None): - super().__init__(maxsize=maxsize, loop=loop) - self._unfinished_tasks = 0 - self._finished = locks.Event(loop=self._loop) - self._finished.set() - - def _format(self): - result = Queue._format(self) - if self._unfinished_tasks: - result += ' tasks={}'.format(self._unfinished_tasks) - return result - - def _put(self, item): - super()._put(item) - self._unfinished_tasks += 1 - self._finished.clear() - def task_done(self): """Indicate that a formerly enqueued task is complete. @@ -294,9 +245,42 @@ """Block until all items in the queue have been gotten and processed. The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls task_done() - to indicate that the item was retrieved and all work on it is complete. + queue. The count goes down whenever a consumer calls task_done() to + indicate that the item was retrieved and all work on it is complete. When the count of unfinished tasks drops to zero, join() unblocks. """ if self._unfinished_tasks > 0: yield from self._finished.wait() + + +class PriorityQueue(Queue): + """A subclass of Queue; retrieves entries in priority order (lowest first). + + Entries are typically tuples of the form: (priority number, data). + """ + + def _init(self, maxsize): + self._queue = [] + + def _put(self, item, heappush=heapq.heappush): + heappush(self._queue, item) + + def _get(self, heappop=heapq.heappop): + return heappop(self._queue) + + +class LifoQueue(Queue): + """A subclass of Queue that retrieves most recently added entries first.""" + + def _init(self, maxsize): + self._queue = [] + + def _put(self, item): + self._queue.append(item) + + def _get(self): + return self._queue.pop() + + +JoinableQueue = Queue +"""Deprecated alias for Queue.""" diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py --- a/Lib/test/test_asyncio/test_queues.py +++ b/Lib/test/test_asyncio/test_queues.py @@ -408,14 +408,14 @@ self.assertEqual([1, 2, 3], items) -class JoinableQueueTests(_QueueTestBase): +class QueueJoinTests(_QueueTestBase): def test_task_done_underflow(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) self.assertRaises(ValueError, q.task_done) def test_task_done(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) for i in range(100): q.put_nowait(i) @@ -452,7 +452,7 @@ self.loop.run_until_complete(asyncio.wait(tasks, loop=self.loop)) def test_join_empty_queue(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) # Test that a queue join()s successfully, and before anything else # (done twice for insurance). @@ -465,7 +465,7 @@ self.loop.run_until_complete(join()) def test_format(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) self.assertEqual(q._format(), 'maxsize=0') q._unfinished_tasks = 2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:14:58 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:14:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbywgVHVs?= =?utf-8?q?ip_issue_220=3A_Update_doc_of_asyncio=2EQueue=2C_add_join_and_t?= =?utf-8?q?ask=5Fdone?= Message-ID: <20150217221418.71226.98183@psf.io> https://hg.python.org/cpython/rev/6beaf66f0410 changeset: 94668:6beaf66f0410 branch: 3.4 user: Victor Stinner date: Tue Feb 17 23:09:52 2015 +0100 summary: asyncio, Tulip issue 220: Update doc of asyncio.Queue, add join and task_done methods files: Doc/library/asyncio-sync.rst | 98 ++++++++++++----------- 1 files changed, 53 insertions(+), 45 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -310,6 +310,9 @@ be interrupted between calling :meth:`qsize` and doing an operation on the Queue. + .. versionchanged:: 3.4.3 + New :meth:`join` and :meth:`task_done` methods. + .. method:: empty() Return ``True`` if the queue is empty, ``False`` otherwise. @@ -341,6 +344,20 @@ Return an item if one is immediately available, else raise :exc:`QueueEmpty`. + .. coroutinemethod:: join() + + Block until all items in the queue have been gotten and processed. + + The count of unfinished tasks goes up whenever an item is added to the + queue. The count goes down whenever a consumer thread calls + :meth:`task_done` to indicate that the item was retrieved and all work on + it is complete. When the count of unfinished tasks drops to zero, + :meth:`join` unblocks. + + This method is a :ref:`coroutine `. + + .. versionadded:: 3.4.3 + .. coroutinemethod:: put(item) Put an item into the queue. If the queue is full, wait until a free slot @@ -362,51 +379,6 @@ Number of items in the queue. - .. attribute:: maxsize - - Number of items allowed in the queue. - - -PriorityQueue -^^^^^^^^^^^^^ - -.. class:: PriorityQueue - - A subclass of :class:`Queue`; retrieves entries in priority order (lowest - first). - - Entries are typically tuples of the form: (priority number, data). - - -LifoQueue -^^^^^^^^^ - -.. class:: LifoQueue - - A subclass of :class:`Queue` that retrieves most recently added entries - first. - - -JoinableQueue -^^^^^^^^^^^^^ - -.. class:: JoinableQueue - - A subclass of :class:`Queue` with :meth:`task_done` and :meth:`join` - methods. - - .. coroutinemethod:: join() - - Block until all items in the queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls - :meth:`task_done` to indicate that the item was retrieved and all work on - it is complete. When the count of unfinished tasks drops to zero, - :meth:`join` unblocks. - - This method is a :ref:`coroutine `. - .. method:: task_done() Indicate that a formerly enqueued task is complete. @@ -422,6 +394,42 @@ Raises :exc:`ValueError` if called more times than there were items placed in the queue. + .. versionadded:: 3.4.3 + + .. attribute:: maxsize + + Number of items allowed in the queue. + + +PriorityQueue +^^^^^^^^^^^^^ + +.. class:: PriorityQueue + + A subclass of :class:`Queue`; retrieves entries in priority order (lowest + first). + + Entries are typically tuples of the form: (priority number, data). + + +LifoQueue +^^^^^^^^^ + +.. class:: LifoQueue + + A subclass of :class:`Queue` that retrieves most recently added entries + first. + + +JoinableQueue +^^^^^^^^^^^^^ + +.. class:: JoinableQueue + + Deprecated alias for :class:`Queue`. + + .. deprecated:: 3.4.3 + Exceptions ^^^^^^^^^^ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:14:58 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:14:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20150217221418.60722.25256@psf.io> https://hg.python.org/cpython/rev/6f75c7c6e260 changeset: 94666:6f75c7c6e260 parent: 94662:c0b2dacef35c parent: 94665:0f6ddf944521 user: Victor Stinner date: Tue Feb 17 22:55:36 2015 +0100 summary: Merge 3.4 (asyncio) files: Lib/asyncio/base_subprocess.py | 2 + Lib/asyncio/queues.py | 104 ++++------ Lib/test/test_asyncio/test_queues.py | 10 +- Lib/test/test_asyncio/test_subprocess.py | 12 +- 4 files changed, 61 insertions(+), 67 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -57,6 +57,8 @@ info.append('pid=%s' % self._pid) if self._returncode is not None: info.append('returncode=%s' % self._returncode) + else: + info.append('running') stdin = self._pipes.get(0) if stdin is not None: diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -1,7 +1,7 @@ """Queues""" -__all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'JoinableQueue', - 'QueueFull', 'QueueEmpty'] +__all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'QueueFull', 'QueueEmpty', + 'JoinableQueue'] import collections import heapq @@ -49,6 +49,9 @@ self._getters = collections.deque() # Pairs of (item, Future). self._putters = collections.deque() + self._unfinished_tasks = 0 + self._finished = locks.Event(loop=self._loop) + self._finished.set() self._init(maxsize) def _init(self, maxsize): @@ -59,6 +62,8 @@ def _put(self, item): self._queue.append(item) + self._unfinished_tasks += 1 + self._finished.clear() def __repr__(self): return '<{} at {:#x} {}>'.format( @@ -75,6 +80,8 @@ result += ' _getters[{}]'.format(len(self._getters)) if self._putters: result += ' _putters[{}]'.format(len(self._putters)) + if self._unfinished_tasks: + result += ' tasks={}'.format(self._unfinished_tasks) return result def _consume_done_getters(self): @@ -126,9 +133,6 @@ 'queue non-empty, why are getters waiting?') getter = self._getters.popleft() - - # Use _put and _get instead of passing item straight to getter, in - # case a subclass has logic that must run (e.g. JoinableQueue). self._put(item) # getter cannot be cancelled, we just removed done getters @@ -154,9 +158,6 @@ 'queue non-empty, why are getters waiting?') getter = self._getters.popleft() - - # Use _put and _get instead of passing item straight to getter, in - # case a subclass has logic that must run (e.g. JoinableQueue). self._put(item) # getter cannot be cancelled, we just removed done getters @@ -219,56 +220,6 @@ else: raise QueueEmpty - -class PriorityQueue(Queue): - """A subclass of Queue; retrieves entries in priority order (lowest first). - - Entries are typically tuples of the form: (priority number, data). - """ - - def _init(self, maxsize): - self._queue = [] - - def _put(self, item, heappush=heapq.heappush): - heappush(self._queue, item) - - def _get(self, heappop=heapq.heappop): - return heappop(self._queue) - - -class LifoQueue(Queue): - """A subclass of Queue that retrieves most recently added entries first.""" - - def _init(self, maxsize): - self._queue = [] - - def _put(self, item): - self._queue.append(item) - - def _get(self): - return self._queue.pop() - - -class JoinableQueue(Queue): - """A subclass of Queue with task_done() and join() methods.""" - - def __init__(self, maxsize=0, *, loop=None): - super().__init__(maxsize=maxsize, loop=loop) - self._unfinished_tasks = 0 - self._finished = locks.Event(loop=self._loop) - self._finished.set() - - def _format(self): - result = Queue._format(self) - if self._unfinished_tasks: - result += ' tasks={}'.format(self._unfinished_tasks) - return result - - def _put(self, item): - super()._put(item) - self._unfinished_tasks += 1 - self._finished.clear() - def task_done(self): """Indicate that a formerly enqueued task is complete. @@ -294,9 +245,42 @@ """Block until all items in the queue have been gotten and processed. The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls task_done() - to indicate that the item was retrieved and all work on it is complete. + queue. The count goes down whenever a consumer calls task_done() to + indicate that the item was retrieved and all work on it is complete. When the count of unfinished tasks drops to zero, join() unblocks. """ if self._unfinished_tasks > 0: yield from self._finished.wait() + + +class PriorityQueue(Queue): + """A subclass of Queue; retrieves entries in priority order (lowest first). + + Entries are typically tuples of the form: (priority number, data). + """ + + def _init(self, maxsize): + self._queue = [] + + def _put(self, item, heappush=heapq.heappush): + heappush(self._queue, item) + + def _get(self, heappop=heapq.heappop): + return heappop(self._queue) + + +class LifoQueue(Queue): + """A subclass of Queue that retrieves most recently added entries first.""" + + def _init(self, maxsize): + self._queue = [] + + def _put(self, item): + self._queue.append(item) + + def _get(self): + return self._queue.pop() + + +JoinableQueue = Queue +"""Deprecated alias for Queue.""" diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py --- a/Lib/test/test_asyncio/test_queues.py +++ b/Lib/test/test_asyncio/test_queues.py @@ -408,14 +408,14 @@ self.assertEqual([1, 2, 3], items) -class JoinableQueueTests(_QueueTestBase): +class QueueJoinTests(_QueueTestBase): def test_task_done_underflow(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) self.assertRaises(ValueError, q.task_done) def test_task_done(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) for i in range(100): q.put_nowait(i) @@ -452,7 +452,7 @@ self.loop.run_until_complete(asyncio.wait(tasks, loop=self.loop)) def test_join_empty_queue(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) # Test that a queue join()s successfully, and before anything else # (done twice for insurance). @@ -465,7 +465,7 @@ self.loop.run_until_complete(join()) def test_format(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) self.assertEqual(q._format(), 'maxsize=0') q._unfinished_tasks = 2 diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -355,11 +355,19 @@ create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, *PROGRAM_BLOCKED) transport, protocol = yield from create + + kill_called = False + def kill(): + nonlocal kill_called + kill_called = True + orig_kill() + proc = transport.get_extra_info('subprocess') - proc.kill = mock.Mock() + orig_kill = proc.kill + proc.kill = kill returncode = transport.get_returncode() transport.close() - return (returncode, proc.kill.called) + return (returncode, kill_called) # Ignore "Close running child process: kill ..." log with test_utils.disable_logger(): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:37:50 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:37:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogRml4?= =?utf-8?q?_warning_in_test=5Fclose=5Fkill=5Frunning=28=29?= Message-ID: <20150217223750.25195.74102@psf.io> https://hg.python.org/cpython/rev/28bfbf91bb53 changeset: 94670:28bfbf91bb53 branch: 3.4 parent: 94668:6beaf66f0410 user: Victor Stinner date: Tue Feb 17 23:36:02 2015 +0100 summary: asyncio: Fix warning in test_close_kill_running() Read process exit status to avoid the "Caught subprocess termination from unknown pid" message. files: Lib/test/test_asyncio/test_subprocess.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -367,6 +367,7 @@ proc.kill = kill returncode = transport.get_returncode() transport.close() + yield from transport._wait() return (returncode, kill_called) # Ignore "Close running child process: kill ..." log -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 17 23:37:50 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 17 Feb 2015 22:37:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20150217223750.5027.77930@psf.io> https://hg.python.org/cpython/rev/9a55a2a1dc6f changeset: 94671:9a55a2a1dc6f parent: 94669:6434aab53114 parent: 94670:28bfbf91bb53 user: Victor Stinner date: Tue Feb 17 23:36:19 2015 +0100 summary: Merge 3.4 (asyncio) files: Lib/test/test_asyncio/test_subprocess.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -367,6 +367,7 @@ proc.kill = kill returncode = transport.get_returncode() transport.close() + yield from transport._wait() return (returncode, kill_called) # Ignore "Close running child process: kill ..." log -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 03:13:34 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 02:13:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjM0MTAp?= Message-ID: <20150218021334.13148.44469@psf.io> https://hg.python.org/cpython/rev/6e3e252cf047 changeset: 94673:6e3e252cf047 parent: 94671:9a55a2a1dc6f parent: 94672:f9ff2a5bbbe2 user: Benjamin Peterson date: Tue Feb 17 21:13:30 2015 -0500 summary: merge 3.4 (#23410) files: Doc/library/http.server.rst | 12 +++++++ Lib/http/server.py | 20 ++++++------ Lib/test/test_httpservers.py | 39 ++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -64,6 +64,18 @@ Contains the server instance. + .. attribute:: close_connection + + Boolean that should be set before :meth:`handle_one_request` returns, + indicating if another request may be expected, or if the connection should + be shut down. + + .. attribute:: requestline + + Contains the string representation of the HTTP request line. The + terminating CRLF is stripped. This attribute should be set by + :meth:`handle_one_request`. If no valid request line was processed, it + should be set to the empty string. .. attribute:: command diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -275,7 +275,7 @@ """ self.command = None # set in case of error on the first line self.request_version = version = self.default_request_version - self.close_connection = 1 + self.close_connection = True requestline = str(self.raw_requestline, 'iso-8859-1') requestline = requestline.rstrip('\r\n') self.requestline = requestline @@ -305,7 +305,7 @@ "Bad request version (%r)" % version) return False if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1": - self.close_connection = 0 + self.close_connection = False if version_number >= (2, 0): self.send_error( HTTPStatus.HTTP_VERSION_NOT_SUPPORTED, @@ -313,7 +313,7 @@ return False elif len(words) == 2: command, path = words - self.close_connection = 1 + self.close_connection = True if command != 'GET': self.send_error( HTTPStatus.BAD_REQUEST, @@ -340,10 +340,10 @@ conntype = self.headers.get('Connection', "") if conntype.lower() == 'close': - self.close_connection = 1 + self.close_connection = True elif (conntype.lower() == 'keep-alive' and self.protocol_version >= "HTTP/1.1"): - self.close_connection = 0 + self.close_connection = False # Examine the headers and look for an Expect directive expect = self.headers.get('Expect', "") if (expect.lower() == "100-continue" and @@ -388,7 +388,7 @@ self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG) return if not self.raw_requestline: - self.close_connection = 1 + self.close_connection = True return if not self.parse_request(): # An error code has been sent, just exit @@ -405,12 +405,12 @@ except socket.timeout as e: #a read or a write timed out. Discard this connection self.log_error("Request timed out: %r", e) - self.close_connection = 1 + self.close_connection = True return def handle(self): """Handle multiple requests if necessary.""" - self.close_connection = 1 + self.close_connection = True self.handle_one_request() while not self.close_connection: @@ -496,9 +496,9 @@ if keyword.lower() == 'connection': if value.lower() == 'close': - self.close_connection = 1 + self.close_connection = True elif value.lower() == 'keep-alive': - self.close_connection = 0 + self.close_connection = False def end_headers(self): """Send the blank line ending the MIME headers.""" diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -616,6 +616,11 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.1') + self.assertSequenceEqual(self.handler.headers.items(), ()) def test_http_1_0(self): result = self.send_typical_request(b'GET / HTTP/1.0\r\n\r\n') @@ -623,6 +628,11 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.0') + self.assertSequenceEqual(self.handler.headers.items(), ()) def test_http_0_9(self): result = self.send_typical_request(b'GET / HTTP/0.9\r\n\r\n') @@ -636,6 +646,12 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.0') + headers = (("Expect", "100-continue"),) + self.assertSequenceEqual(self.handler.headers.items(), headers) def test_with_continue_1_1(self): result = self.send_typical_request(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n') @@ -645,6 +661,12 @@ self.verify_expected_headers(result[2:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.1') + headers = (("Expect", "100-continue"),) + self.assertSequenceEqual(self.handler.headers.items(), headers) def test_header_buffering_of_send_error(self): @@ -730,6 +752,7 @@ result = self.send_typical_request(b'GET ' + b'x' * 65537) self.assertEqual(result[0], b'HTTP/1.1 414 Request-URI Too Long\r\n') self.assertFalse(self.handler.get_called) + self.assertIsInstance(self.handler.requestline, str) def test_header_length(self): # Issue #6791: same for headers @@ -737,6 +760,22 @@ b'GET / HTTP/1.1\r\nX-Foo: bar' + b'r' * 65537 + b'\r\n\r\n') self.assertEqual(result[0], b'HTTP/1.1 400 Line too long\r\n') self.assertFalse(self.handler.get_called) + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + + def test_close_connection(self): + # handle_one_request() should be repeatedly called until + # it sets close_connection + def handle_one_request(): + self.handler.close_connection = next(close_values) + self.handler.handle_one_request = handle_one_request + + close_values = iter((True,)) + self.handler.handle() + self.assertRaises(StopIteration, next, close_values) + + close_values = iter((False, False, True)) + self.handler.handle() + self.assertRaises(StopIteration, next, close_values) class SimpleHTTPRequestHandlerTestCase(unittest.TestCase): """ Test url parsing """ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 03:13:35 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 02:13:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_document_the_r?= =?utf-8?q?equestline_and_close=5Fconnection_attributes=2C_use_real_boolea?= =?utf-8?b?bnMs?= Message-ID: <20150218021334.13146.57117@psf.io> https://hg.python.org/cpython/rev/f9ff2a5bbbe2 changeset: 94672:f9ff2a5bbbe2 branch: 3.4 parent: 94670:28bfbf91bb53 user: Benjamin Peterson date: Tue Feb 17 21:11:10 2015 -0500 summary: document the requestline and close_connection attributes, use real booleans, and add tests (closes #23410) Patch by Martin Panter. files: Doc/library/http.server.rst | 12 +++++++ Lib/http/server.py | 20 ++++++------ Lib/test/test_httpservers.py | 39 ++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -64,6 +64,18 @@ Contains the server instance. + .. attribute:: close_connection + + Boolean that should be set before :meth:`handle_one_request` returns, + indicating if another request may be expected, or if the connection should + be shut down. + + .. attribute:: requestline + + Contains the string representation of the HTTP request line. The + terminating CRLF is stripped. This attribute should be set by + :meth:`handle_one_request`. If no valid request line was processed, it + should be set to the empty string. .. attribute:: command diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -273,7 +273,7 @@ """ self.command = None # set in case of error on the first line self.request_version = version = self.default_request_version - self.close_connection = 1 + self.close_connection = True requestline = str(self.raw_requestline, 'iso-8859-1') requestline = requestline.rstrip('\r\n') self.requestline = requestline @@ -299,14 +299,14 @@ self.send_error(400, "Bad request version (%r)" % version) return False if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1": - self.close_connection = 0 + self.close_connection = False if version_number >= (2, 0): self.send_error(505, "Invalid HTTP Version (%s)" % base_version_number) return False elif len(words) == 2: command, path = words - self.close_connection = 1 + self.close_connection = True if command != 'GET': self.send_error(400, "Bad HTTP/0.9 request type (%r)" % command) @@ -328,10 +328,10 @@ conntype = self.headers.get('Connection', "") if conntype.lower() == 'close': - self.close_connection = 1 + self.close_connection = True elif (conntype.lower() == 'keep-alive' and self.protocol_version >= "HTTP/1.1"): - self.close_connection = 0 + self.close_connection = False # Examine the headers and look for an Expect directive expect = self.headers.get('Expect', "") if (expect.lower() == "100-continue" and @@ -376,7 +376,7 @@ self.send_error(414) return if not self.raw_requestline: - self.close_connection = 1 + self.close_connection = True return if not self.parse_request(): # An error code has been sent, just exit @@ -391,12 +391,12 @@ except socket.timeout as e: #a read or a write timed out. Discard this connection self.log_error("Request timed out: %r", e) - self.close_connection = 1 + self.close_connection = True return def handle(self): """Handle multiple requests if necessary.""" - self.close_connection = 1 + self.close_connection = True self.handle_one_request() while not self.close_connection: @@ -478,9 +478,9 @@ if keyword.lower() == 'connection': if value.lower() == 'close': - self.close_connection = 1 + self.close_connection = True elif value.lower() == 'keep-alive': - self.close_connection = 0 + self.close_connection = False def end_headers(self): """Send the blank line ending the MIME headers.""" diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -616,6 +616,11 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.1') + self.assertSequenceEqual(self.handler.headers.items(), ()) def test_http_1_0(self): result = self.send_typical_request(b'GET / HTTP/1.0\r\n\r\n') @@ -623,6 +628,11 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.0') + self.assertSequenceEqual(self.handler.headers.items(), ()) def test_http_0_9(self): result = self.send_typical_request(b'GET / HTTP/0.9\r\n\r\n') @@ -636,6 +646,12 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.0') + headers = (("Expect", "100-continue"),) + self.assertSequenceEqual(self.handler.headers.items(), headers) def test_with_continue_1_1(self): result = self.send_typical_request(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n') @@ -645,6 +661,12 @@ self.verify_expected_headers(result[2:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.1') + headers = (("Expect", "100-continue"),) + self.assertSequenceEqual(self.handler.headers.items(), headers) def test_header_buffering_of_send_error(self): @@ -730,6 +752,7 @@ result = self.send_typical_request(b'GET ' + b'x' * 65537) self.assertEqual(result[0], b'HTTP/1.1 414 Request-URI Too Long\r\n') self.assertFalse(self.handler.get_called) + self.assertIsInstance(self.handler.requestline, str) def test_header_length(self): # Issue #6791: same for headers @@ -737,6 +760,22 @@ b'GET / HTTP/1.1\r\nX-Foo: bar' + b'r' * 65537 + b'\r\n\r\n') self.assertEqual(result[0], b'HTTP/1.1 400 Line too long\r\n') self.assertFalse(self.handler.get_called) + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + + def test_close_connection(self): + # handle_one_request() should be repeatedly called until + # it sets close_connection + def handle_one_request(): + self.handler.close_connection = next(close_values) + self.handler.handle_one_request = handle_one_request + + close_values = iter((True,)) + self.handler.handle() + self.assertRaises(StopIteration, next, close_values) + + close_values = iter((False, False, True)) + self.handler.handle() + self.assertRaises(StopIteration, next, close_values) class SimpleHTTPRequestHandlerTestCase(unittest.TestCase): """ Test url parsing """ -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Wed Feb 18 06:21:28 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 18 Feb 2015 06:21:28 +0100 Subject: [Python-checkins] Daily reference leaks (9a55a2a1dc6f): sum=6 Message-ID: results for 9a55a2a1dc6f on branch "default" -------------------------------------------- test_asyncio leaked [0, 0, 3] memory blocks, sum=3 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogO13Hj5', '-x'] From python-checkins at python.org Wed Feb 18 07:05:46 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 18 Feb 2015 06:05:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzNDc0?= =?utf-8?q?=3A_Enhanced_locale_testing=2E?= Message-ID: <20150218060546.12770.73533@psf.io> https://hg.python.org/cpython/rev/7ef372f656d1 changeset: 94674:7ef372f656d1 branch: 2.7 parent: 94650:d83884b3a427 user: Serhiy Storchaka date: Wed Feb 18 08:04:26 2015 +0200 summary: Issue #23474: Enhanced locale testing. files: Lib/test/test__locale.py | 32 ++++++++++++++++++++++++--- Lib/test/test_decimal.py | 20 ++++++++++++++++- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -22,7 +22,7 @@ 'da_DK', 'nn_NO', 'cs_CZ', 'de_LU', 'es_BO', 'sq_AL', 'sk_SK', 'fr_CH', 'de_DE', 'sr_YU', 'br_FR', 'nl_BE', 'sv_FI', 'pl_PL', 'fr_CA', 'fo_FO', 'bs_BA', 'fr_LU', 'kl_GL', 'fa_IR', 'de_BE', 'sv_SE', 'it_CH', 'uk_UA', - 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'en_US', + 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'ps_AF.UTF-8', 'en_US', 'es_ES.ISO8859-1', 'fr_FR.ISO8859-15', 'ru_RU.KOI8-R', 'ko_KR.eucKR'] # Workaround for MSVC6(debug) crash bug @@ -35,7 +35,12 @@ # List known locale values to test against when available. # Dict formatted as `` : (, )``. If a # value is not known, use '' . -known_numerics = {'fr_FR' : (',', ''), 'en_US':('.', ',')} +known_numerics = { + 'en_US': ('.', ','), + 'fr_FR' : (',', ' '), + 'de_DE' : (',', '.'), + 'ps_AF.UTF-8' : ('\xd9\xab', '\xd9\xac'), +} class _LocaleTests(unittest.TestCase): @@ -64,10 +69,12 @@ calc_value, known_value, calc_type, data_type, set_locale, used_locale)) + return True @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_nl_langinfo(self): # Test nl_langinfo against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -75,21 +82,30 @@ continue for li, lc in ((RADIXCHAR, "decimal_point"), (THOUSEP, "thousands_sep")): - self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc) + if self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') def test_lc_numeric_localeconv(self): # Test localeconv against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) except Error: continue + formatting = localeconv() for lc in ("decimal_point", "thousands_sep"): - self.numeric_tester('localeconv', localeconv()[lc], lc, loc) + if self.numeric_tester('localeconv', formatting[lc], lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_basic(self): # Test nl_langinfo against localeconv + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -108,10 +124,14 @@ "(set to %s, using %s)" % ( nl_radixchar, li_radixchar, loc, set_locale)) + tested = True + if not tested: + self.skipTest('no suitable locales') def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -129,6 +149,10 @@ if localeconv()['decimal_point'] != '.': self.assertRaises(ValueError, float, localeconv()['decimal_point'].join(['1', '23'])) + tested = True + if not tested: + self.skipTest('no suitable locales') + def test_main(): run_unittest(_LocaleTests) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -32,7 +32,8 @@ from decimal import * import numbers from test.test_support import (run_unittest, run_doctest, requires_unicode, u, - is_resource_enabled, check_py3k_warnings) + is_resource_enabled, check_py3k_warnings, + run_with_locale) import random try: import threading @@ -905,6 +906,23 @@ self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6') self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6') + @run_with_locale('LC_ALL', 'ps_AF.UTF-8') + def test_wide_char_separator_decimal_point(self): + # locale with wide char separator and decimal point + import locale + + decimal_point = locale.localeconv()['decimal_point'] + thousands_sep = locale.localeconv()['thousands_sep'] + if decimal_point != '\xd9\xab': + self.skipTest('inappropriate decimal point separator' + '({!r} not {!r})'.format(decimal_point, '\xd9\xab')) + if thousands_sep != '\xd9\xac': + self.skipTest('inappropriate thousands separator' + '({!r} not {!r})'.format(thousands_sep, '\xd9\xac')) + + self.assertEqual(format(Decimal('100000000.123'), 'n'), + '100\xd9\xac000\xd9\xac000\xd9\xab123') + class DecimalArithmeticOperatorsTest(unittest.TestCase): '''Unit tests for all arithmetic operators, binary and unary.''' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 07:05:46 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 18 Feb 2015 06:05:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323474=3A_Enhanced_locale_testing=2E?= Message-ID: <20150218060546.13146.24352@psf.io> https://hg.python.org/cpython/rev/4f7c5349e801 changeset: 94676:4f7c5349e801 parent: 94673:6e3e252cf047 parent: 94675:b53aadd9cf85 user: Serhiy Storchaka date: Wed Feb 18 08:05:05 2015 +0200 summary: Issue #23474: Enhanced locale testing. files: Lib/test/test__locale.py | 97 +++++++++++++++++---------- Lib/test/test_locale.py | 2 +- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -9,7 +9,6 @@ import sys import unittest from platform import uname -from test.support import run_unittest if uname().system == "Darwin": maj, min, mic = [int(part) for part in uname().release.split(".")] @@ -24,45 +23,52 @@ 'da_DK', 'nn_NO', 'cs_CZ', 'de_LU', 'es_BO', 'sq_AL', 'sk_SK', 'fr_CH', 'de_DE', 'sr_YU', 'br_FR', 'nl_BE', 'sv_FI', 'pl_PL', 'fr_CA', 'fo_FO', 'bs_BA', 'fr_LU', 'kl_GL', 'fa_IR', 'de_BE', 'sv_SE', 'it_CH', 'uk_UA', - 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'en_US', + 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'ps_AF', 'en_US', 'es_ES.ISO8859-1', 'fr_FR.ISO8859-15', 'ru_RU.KOI8-R', 'ko_KR.eucKR'] -# Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to -# workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses -# the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is -# decoded as U+30000020 (an invalid character) by mbstowcs(). -if sys.platform == 'sunos5': - old_locale = locale.setlocale(locale.LC_ALL) - try: - locales = [] - for loc in candidate_locales: - try: - locale.setlocale(locale.LC_ALL, loc) - except Error: - continue - encoding = locale.getpreferredencoding(False) - try: - localeconv() - except Exception as err: - print("WARNING: Skip locale %s (encoding %s): [%s] %s" - % (loc, encoding, type(err), err)) - else: - locales.append(loc) - candidate_locales = locales - finally: - locale.setlocale(locale.LC_ALL, old_locale) +def setUpModule(): + global candidate_locales + # Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to + # workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses + # the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is + # decoded as U+30000020 (an invalid character) by mbstowcs(). + if sys.platform == 'sunos5': + old_locale = locale.setlocale(locale.LC_ALL) + try: + locales = [] + for loc in candidate_locales: + try: + locale.setlocale(locale.LC_ALL, loc) + except Error: + continue + encoding = locale.getpreferredencoding(False) + try: + localeconv() + except Exception as err: + print("WARNING: Skip locale %s (encoding %s): [%s] %s" + % (loc, encoding, type(err), err)) + else: + locales.append(loc) + candidate_locales = locales + finally: + locale.setlocale(locale.LC_ALL, old_locale) -# Workaround for MSVC6(debug) crash bug -if "MSC v.1200" in sys.version: - def accept(loc): - a = loc.split(".") - return not(len(a) == 2 and len(a[-1]) >= 9) - candidate_locales = [loc for loc in candidate_locales if accept(loc)] + # Workaround for MSVC6(debug) crash bug + if "MSC v.1200" in sys.version: + def accept(loc): + a = loc.split(".") + return not(len(a) == 2 and len(a[-1]) >= 9) + candidate_locales = [loc for loc in candidate_locales if accept(loc)] # List known locale values to test against when available. # Dict formatted as `` : (, )``. If a # value is not known, use '' . -known_numerics = {'fr_FR' : (',', ''), 'en_US':('.', ',')} +known_numerics = { + 'en_US': ('.', ','), + 'fr_FR' : (',', ' '), + 'de_DE' : (',', '.'), + 'ps_AF': ('\u066b', '\u066c'), +} class _LocaleTests(unittest.TestCase): @@ -91,10 +97,12 @@ calc_value, known_value, calc_type, data_type, set_locale, used_locale)) + return True @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_nl_langinfo(self): # Test nl_langinfo against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -103,10 +111,14 @@ continue for li, lc in ((RADIXCHAR, "decimal_point"), (THOUSEP, "thousands_sep")): - self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc) + if self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') def test_lc_numeric_localeconv(self): # Test localeconv against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -116,11 +128,15 @@ formatting = localeconv() for lc in ("decimal_point", "thousands_sep"): - self.numeric_tester('localeconv', formatting[lc], lc, loc) + if self.numeric_tester('localeconv', formatting[lc], lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_basic(self): # Test nl_langinfo against localeconv + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -140,10 +156,14 @@ "(set to %s, using %s)" % ( nl_radixchar, li_radixchar, loc, set_locale)) + tested = True + if not tested: + self.skipTest('no suitable locales') def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -162,9 +182,10 @@ if localeconv()['decimal_point'] != '.': self.assertRaises(ValueError, float, localeconv()['decimal_point'].join(['1', '23'])) + tested = True + if not tested: + self.skipTest('no suitable locales') -def test_main(): - run_unittest(_LocaleTests) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -511,7 +511,7 @@ self.skipTest('test needs Turkish locale') loc = locale.getlocale(locale.LC_CTYPE) if verbose: - print('got locale %a' % (loc,)) + print('testing with %a' % (loc,), end=' ', flush=True) locale.setlocale(locale.LC_CTYPE, loc) self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 07:05:46 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 18 Feb 2015 06:05:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDc0?= =?utf-8?q?=3A_Enhanced_locale_testing=2E?= Message-ID: <20150218060546.5045.96401@psf.io> https://hg.python.org/cpython/rev/b53aadd9cf85 changeset: 94675:b53aadd9cf85 branch: 3.4 parent: 94672:f9ff2a5bbbe2 user: Serhiy Storchaka date: Wed Feb 18 08:04:37 2015 +0200 summary: Issue #23474: Enhanced locale testing. files: Lib/test/test__locale.py | 97 +++++++++++++++++---------- Lib/test/test_locale.py | 2 +- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -9,7 +9,6 @@ import sys import unittest from platform import uname -from test.support import run_unittest if uname().system == "Darwin": maj, min, mic = [int(part) for part in uname().release.split(".")] @@ -24,45 +23,52 @@ 'da_DK', 'nn_NO', 'cs_CZ', 'de_LU', 'es_BO', 'sq_AL', 'sk_SK', 'fr_CH', 'de_DE', 'sr_YU', 'br_FR', 'nl_BE', 'sv_FI', 'pl_PL', 'fr_CA', 'fo_FO', 'bs_BA', 'fr_LU', 'kl_GL', 'fa_IR', 'de_BE', 'sv_SE', 'it_CH', 'uk_UA', - 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'en_US', + 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'ps_AF', 'en_US', 'es_ES.ISO8859-1', 'fr_FR.ISO8859-15', 'ru_RU.KOI8-R', 'ko_KR.eucKR'] -# Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to -# workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses -# the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is -# decoded as U+30000020 (an invalid character) by mbstowcs(). -if sys.platform == 'sunos5': - old_locale = locale.setlocale(locale.LC_ALL) - try: - locales = [] - for loc in candidate_locales: - try: - locale.setlocale(locale.LC_ALL, loc) - except Error: - continue - encoding = locale.getpreferredencoding(False) - try: - localeconv() - except Exception as err: - print("WARNING: Skip locale %s (encoding %s): [%s] %s" - % (loc, encoding, type(err), err)) - else: - locales.append(loc) - candidate_locales = locales - finally: - locale.setlocale(locale.LC_ALL, old_locale) +def setUpModule(): + global candidate_locales + # Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to + # workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses + # the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is + # decoded as U+30000020 (an invalid character) by mbstowcs(). + if sys.platform == 'sunos5': + old_locale = locale.setlocale(locale.LC_ALL) + try: + locales = [] + for loc in candidate_locales: + try: + locale.setlocale(locale.LC_ALL, loc) + except Error: + continue + encoding = locale.getpreferredencoding(False) + try: + localeconv() + except Exception as err: + print("WARNING: Skip locale %s (encoding %s): [%s] %s" + % (loc, encoding, type(err), err)) + else: + locales.append(loc) + candidate_locales = locales + finally: + locale.setlocale(locale.LC_ALL, old_locale) -# Workaround for MSVC6(debug) crash bug -if "MSC v.1200" in sys.version: - def accept(loc): - a = loc.split(".") - return not(len(a) == 2 and len(a[-1]) >= 9) - candidate_locales = [loc for loc in candidate_locales if accept(loc)] + # Workaround for MSVC6(debug) crash bug + if "MSC v.1200" in sys.version: + def accept(loc): + a = loc.split(".") + return not(len(a) == 2 and len(a[-1]) >= 9) + candidate_locales = [loc for loc in candidate_locales if accept(loc)] # List known locale values to test against when available. # Dict formatted as `` : (, )``. If a # value is not known, use '' . -known_numerics = {'fr_FR' : (',', ''), 'en_US':('.', ',')} +known_numerics = { + 'en_US': ('.', ','), + 'fr_FR' : (',', ' '), + 'de_DE' : (',', '.'), + 'ps_AF': ('\u066b', '\u066c'), +} class _LocaleTests(unittest.TestCase): @@ -91,10 +97,12 @@ calc_value, known_value, calc_type, data_type, set_locale, used_locale)) + return True @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_nl_langinfo(self): # Test nl_langinfo against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -103,10 +111,14 @@ continue for li, lc in ((RADIXCHAR, "decimal_point"), (THOUSEP, "thousands_sep")): - self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc) + if self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') def test_lc_numeric_localeconv(self): # Test localeconv against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -116,11 +128,15 @@ formatting = localeconv() for lc in ("decimal_point", "thousands_sep"): - self.numeric_tester('localeconv', formatting[lc], lc, loc) + if self.numeric_tester('localeconv', formatting[lc], lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_basic(self): # Test nl_langinfo against localeconv + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -140,10 +156,14 @@ "(set to %s, using %s)" % ( nl_radixchar, li_radixchar, loc, set_locale)) + tested = True + if not tested: + self.skipTest('no suitable locales') def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -162,9 +182,10 @@ if localeconv()['decimal_point'] != '.': self.assertRaises(ValueError, float, localeconv()['decimal_point'].join(['1', '23'])) + tested = True + if not tested: + self.skipTest('no suitable locales') -def test_main(): - run_unittest(_LocaleTests) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -511,7 +511,7 @@ self.skipTest('test needs Turkish locale') loc = locale.getlocale(locale.LC_CTYPE) if verbose: - print('got locale %a' % (loc,)) + print('testing with %a' % (loc,), end=' ', flush=True) locale.setlocale(locale.LC_CTYPE, loc) self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:36 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge_heads?= Message-ID: <20150218135735.62559.67208@psf.io> https://hg.python.org/cpython/rev/e7dcab87ff6c changeset: 94682:e7dcab87ff6c parent: 94680:477d217ba4e8 parent: 94676:4f7c5349e801 user: Benjamin Peterson date: Wed Feb 18 08:56:43 2015 -0500 summary: merge heads files: Lib/test/test__locale.py | 97 +++++++++++++++++---------- Lib/test/test_locale.py | 2 +- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -9,7 +9,6 @@ import sys import unittest from platform import uname -from test.support import run_unittest if uname().system == "Darwin": maj, min, mic = [int(part) for part in uname().release.split(".")] @@ -24,45 +23,52 @@ 'da_DK', 'nn_NO', 'cs_CZ', 'de_LU', 'es_BO', 'sq_AL', 'sk_SK', 'fr_CH', 'de_DE', 'sr_YU', 'br_FR', 'nl_BE', 'sv_FI', 'pl_PL', 'fr_CA', 'fo_FO', 'bs_BA', 'fr_LU', 'kl_GL', 'fa_IR', 'de_BE', 'sv_SE', 'it_CH', 'uk_UA', - 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'en_US', + 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'ps_AF', 'en_US', 'es_ES.ISO8859-1', 'fr_FR.ISO8859-15', 'ru_RU.KOI8-R', 'ko_KR.eucKR'] -# Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to -# workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses -# the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is -# decoded as U+30000020 (an invalid character) by mbstowcs(). -if sys.platform == 'sunos5': - old_locale = locale.setlocale(locale.LC_ALL) - try: - locales = [] - for loc in candidate_locales: - try: - locale.setlocale(locale.LC_ALL, loc) - except Error: - continue - encoding = locale.getpreferredencoding(False) - try: - localeconv() - except Exception as err: - print("WARNING: Skip locale %s (encoding %s): [%s] %s" - % (loc, encoding, type(err), err)) - else: - locales.append(loc) - candidate_locales = locales - finally: - locale.setlocale(locale.LC_ALL, old_locale) +def setUpModule(): + global candidate_locales + # Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to + # workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses + # the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is + # decoded as U+30000020 (an invalid character) by mbstowcs(). + if sys.platform == 'sunos5': + old_locale = locale.setlocale(locale.LC_ALL) + try: + locales = [] + for loc in candidate_locales: + try: + locale.setlocale(locale.LC_ALL, loc) + except Error: + continue + encoding = locale.getpreferredencoding(False) + try: + localeconv() + except Exception as err: + print("WARNING: Skip locale %s (encoding %s): [%s] %s" + % (loc, encoding, type(err), err)) + else: + locales.append(loc) + candidate_locales = locales + finally: + locale.setlocale(locale.LC_ALL, old_locale) -# Workaround for MSVC6(debug) crash bug -if "MSC v.1200" in sys.version: - def accept(loc): - a = loc.split(".") - return not(len(a) == 2 and len(a[-1]) >= 9) - candidate_locales = [loc for loc in candidate_locales if accept(loc)] + # Workaround for MSVC6(debug) crash bug + if "MSC v.1200" in sys.version: + def accept(loc): + a = loc.split(".") + return not(len(a) == 2 and len(a[-1]) >= 9) + candidate_locales = [loc for loc in candidate_locales if accept(loc)] # List known locale values to test against when available. # Dict formatted as `` : (, )``. If a # value is not known, use '' . -known_numerics = {'fr_FR' : (',', ''), 'en_US':('.', ',')} +known_numerics = { + 'en_US': ('.', ','), + 'fr_FR' : (',', ' '), + 'de_DE' : (',', '.'), + 'ps_AF': ('\u066b', '\u066c'), +} class _LocaleTests(unittest.TestCase): @@ -91,10 +97,12 @@ calc_value, known_value, calc_type, data_type, set_locale, used_locale)) + return True @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_nl_langinfo(self): # Test nl_langinfo against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -103,10 +111,14 @@ continue for li, lc in ((RADIXCHAR, "decimal_point"), (THOUSEP, "thousands_sep")): - self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc) + if self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') def test_lc_numeric_localeconv(self): # Test localeconv against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -116,11 +128,15 @@ formatting = localeconv() for lc in ("decimal_point", "thousands_sep"): - self.numeric_tester('localeconv', formatting[lc], lc, loc) + if self.numeric_tester('localeconv', formatting[lc], lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_basic(self): # Test nl_langinfo against localeconv + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -140,10 +156,14 @@ "(set to %s, using %s)" % ( nl_radixchar, li_radixchar, loc, set_locale)) + tested = True + if not tested: + self.skipTest('no suitable locales') def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -162,9 +182,10 @@ if localeconv()['decimal_point'] != '.': self.assertRaises(ValueError, float, localeconv()['decimal_point'].join(['1', '23'])) + tested = True + if not tested: + self.skipTest('no suitable locales') -def test_main(): - run_unittest(_LocaleTests) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -511,7 +511,7 @@ self.skipTest('test needs Turkish locale') loc = locale.getlocale(locale.LC_CTYPE) if verbose: - print('got locale %a' % (loc,)) + print('testing with %a' % (loc,), end=' ', flush=True) locale.setlocale(locale.LC_CTYPE, loc) self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:36 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3?= Message-ID: <20150218135734.60720.71020@psf.io> https://hg.python.org/cpython/rev/2c033f80affa changeset: 94679:2c033f80affa branch: 3.4 parent: 94672:f9ff2a5bbbe2 parent: 94678:221301c8095f user: Benjamin Peterson date: Wed Feb 18 08:55:38 2015 -0500 summary: merge 3.3 files: Misc/README | 1 - Misc/RPM/README | 33 -- Misc/RPM/python-3.4.spec | 389 --------------------------- 3 files changed, 0 insertions(+), 423 deletions(-) diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -21,7 +21,6 @@ README.AIX Information about using Python on AIX README.coverity Information about running Coverity's Prevent on Python README.valgrind Information for Valgrind users, see valgrind-python.supp -RPM (Old) tools to build RPMs SpecialBuilds.txt Describes extra symbols you can set for debug builds svnmap.txt Map of old SVN revs and branches to hg changeset ids valgrind-python.supp Valgrind suppression file, see README.valgrind diff --git a/Misc/RPM/README b/Misc/RPM/README deleted file mode 100644 --- a/Misc/RPM/README +++ /dev/null @@ -1,33 +0,0 @@ -This directory contains support file used to build RPM releases of -Python. Its contents are maintained by Sean Reifschneider -. - -If you wish to build RPMs from the base Python release tar-file, note -that you will have to download the -"doc//html-.tar.bz2" -file from python.org and place it into your "SOURCES" directory for -the build to complete. This is the same directory that you place the -Python-2.3.1 release tar-file in. You can then use the ".spec" file in -this directory to build RPMs. - -You may also wish to pursue RPMs provided by distribution makers to see if -they have one suitable for your uses. If, for example, you just want a -slightly newer version of Python than what the distro provides, you could -pick up the closest SRPM your distro provides, and then modify it to -the newer version, and build that. It may be as simple as just changing -the "version" information in the spec file (or it may require fixing -patches). - -NOTE: I am *NOT* recommending just using the binary RPM, and never do an -install with "--force" or "--nodeps". - -Also worth pursuing may be newer versions provided by similar distros. For -example, a Python 3 SRPM from Fedora may be a good baseline to try building -on CentOS. - -Many newer SRPMs won't install on older distros because of format changes. -You can manually extract these SRPMS with: - - mkdir foo - cd foo - rpm2cpio <../python3-*.src.rpm | cpio -ivd diff --git a/Misc/RPM/python-3.4.spec b/Misc/RPM/python-3.4.spec deleted file mode 100644 --- a/Misc/RPM/python-3.4.spec +++ /dev/null @@ -1,389 +0,0 @@ -########################## -# User-modifiable configs -########################## - -# Is the resulting package and the installed binary named "python" or -# "python2"? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_binsuffix none -%define config_binsuffix 2.6 - -# Build tkinter? "auto" enables it if /usr/bin/wish exists. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_tkinter no -%define config_tkinter yes -%define config_tkinter auto - -# Use pymalloc? The last line (commented or not) determines wether -# pymalloc is used. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_pymalloc no -%define config_pymalloc yes - -# Enable IPV6? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_ipv6 yes -%define config_ipv6 no - -# Build shared libraries or .a library? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_sharedlib no -%define config_sharedlib yes - -# Location of the HTML directory. -%define config_htmldir /var/www/html/python - -################################# -# End of user-modifiable configs -################################# - -%define name python -#--start constants-- -%define version 3.4.3rc1 -%define libvers 3.4 -#--end constants-- -%define release 1pydotorg -%define __prefix /usr - -# kludge to get around rpm define weirdness -%define ipv6 %(if [ "%{config_ipv6}" = yes ]; then echo --enable-ipv6; else echo --disable-ipv6; fi) -%define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) -%define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) -%define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) -%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) -%define sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo --enable-shared; else echo ; fi) -%define include_sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo 1; else echo 0; fi) - -# detect if documentation is available -%define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) - -Summary: An interpreted, interactive, object-oriented programming language. -Name: %{name}%{binsuffix} -Version: %{version} -Release: %{release} -License: PSF -Group: Development/Languages -Source: Python-%{version}.tar.bz2 -%if %{include_docs} -Source1: html-%{version}.tar.bz2 -%endif -BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildPrereq: expat-devel -BuildPrereq: db4-devel -BuildPrereq: gdbm-devel -BuildPrereq: sqlite-devel -Prefix: %{__prefix} -Packager: Sean Reifschneider - -%description -Python is an interpreted, interactive, object-oriented programming -language. It incorporates modules, exceptions, dynamic typing, very high -level dynamic data types, and classes. Python combines remarkable power -with very clear syntax. It has interfaces to many system calls and -libraries, as well as to various window systems, and is extensible in C or -C++. It is also usable as an extension language for applications that need -a programmable interface. Finally, Python is portable: it runs on many -brands of UNIX, on PCs under Windows, MS-DOS, and on the Mac. - -%package devel -Summary: The libraries and header files needed for Python extension development. -Prereq: python%{binsuffix} = %{PACKAGE_VERSION} -Group: Development/Libraries - -%description devel -The Python programming language's interpreter can be extended with -dynamically loaded extensions and can be embedded in other programs. -This package contains the header files and libraries needed to do -these types of tasks. - -Install python-devel if you want to develop Python extensions. The -python package will also need to be installed. You'll probably also -want to install the python-docs package, which contains Python -documentation. - -%if %{include_tkinter} -%package tkinter -Summary: A graphical user interface for the Python scripting language. -Group: Development/Languages -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tkinter -The Tkinter (Tk interface) program is an graphical user interface for -the Python scripting language. - -You should install the tkinter package if you'd like to use a graphical -user interface for Python programming. -%endif - -%package tools -Summary: A collection of development tools included with Python. -Group: Development/Tools -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tools -The Python package includes several development tools that are used -to build python programs. This package contains a selection of those -tools, including the IDLE Python IDE. - -Install python-tools if you want to use these tools to develop -Python programs. You will also need to install the python and -tkinter packages. - -%if %{include_docs} -%package docs -Summary: Python-related documentation. -Group: Development/Documentation - -%description docs -Documentation relating to the Python programming language in HTML and info -formats. -%endif - -%changelog -* Mon Dec 20 2004 Sean Reifschneider [2.4-2pydotorg] -- Changing the idle wrapper so that it passes arguments to idle. - -* Tue Oct 19 2004 Sean Reifschneider [2.4b1-1pydotorg] -- Updating to 2.4. - -* Thu Jul 22 2004 Sean Reifschneider [2.3.4-3pydotorg] -- Paul Tiemann fixes for %{prefix}. -- Adding permission changes for directory as suggested by reimeika.ca -- Adding code to detect when it should be using lib64. -- Adding a define for the location of /var/www/html for docs. - -* Thu May 27 2004 Sean Reifschneider [2.3.4-2pydotorg] -- Including changes from Ian Holsman to build under Red Hat 7.3. -- Fixing some problems with the /usr/local path change. - -* Sat Mar 27 2004 Sean Reifschneider [2.3.2-3pydotorg] -- Being more agressive about finding the paths to fix for - #!/usr/local/bin/python. - -* Sat Feb 07 2004 Sean Reifschneider [2.3.3-2pydotorg] -- Adding code to remove "#!/usr/local/bin/python" from particular files and - causing the RPM build to terminate if there are any unexpected files - which have that line in them. - -* Mon Oct 13 2003 Sean Reifschneider [2.3.2-1pydotorg] -- Adding code to detect wether documentation is available to build. - -* Fri Sep 19 2003 Sean Reifschneider [2.3.1-1pydotorg] -- Updating to the 2.3.1 release. - -* Mon Feb 24 2003 Sean Reifschneider [2.3b1-1pydotorg] -- Updating to 2.3b1 release. - -* Mon Feb 17 2003 Sean Reifschneider [2.3a1-1] -- Updating to 2.3 release. - -* Sun Dec 23 2001 Sean Reifschneider -[Release 2.2-2] -- Added -docs package. -- Added "auto" config_tkinter setting which only enables tk if - /usr/bin/wish exists. - -* Sat Dec 22 2001 Sean Reifschneider -[Release 2.2-1] -- Updated to 2.2. -- Changed the extension to "2" from "2.2". - -* Tue Nov 18 2001 Sean Reifschneider -[Release 2.2c1-1] -- Updated to 2.2c1. - -* Thu Nov 1 2001 Sean Reifschneider -[Release 2.2b1-3] -- Changed the way the sed for fixing the #! in pydoc works. - -* Wed Oct 24 2001 Sean Reifschneider -[Release 2.2b1-2] -- Fixed missing "email" package, thanks to anonymous report on sourceforge. -- Fixed missing "compiler" package. - -* Mon Oct 22 2001 Sean Reifschneider -[Release 2.2b1-1] -- Updated to 2.2b1. - -* Mon Oct 9 2001 Sean Reifschneider -[Release 2.2a4-4] -- otto at balinor.mat.unimi.it mentioned that the license file is missing. - -* Sun Sep 30 2001 Sean Reifschneider -[Release 2.2a4-3] -- Ignacio Vazquez-Abrams pointed out that I had a spruious double-quote in - the spec files. Thanks. - -* Wed Jul 25 2001 Sean Reifschneider -[Release 2.2a1-1] -- Updated to 2.2a1 release. -- Changed idle and pydoc to use binsuffix macro - -####### -# PREP -####### -%prep -%setup -n Python-%{version} - -######## -# BUILD -######## -%build -echo "Setting for ipv6: %{ipv6}" -echo "Setting for pymalloc: %{pymalloc}" -echo "Setting for binsuffix: %{binsuffix}" -echo "Setting for include_tkinter: %{include_tkinter}" -echo "Setting for libdirname: %{libdirname}" -echo "Setting for sharedlib: %{sharedlib}" -echo "Setting for include_sharedlib: %{include_sharedlib}" -./configure --enable-unicode=ucs4 %{sharedlib} %{ipv6} %{pymalloc} --prefix=%{__prefix} -make - -########## -# INSTALL -########## -%install -# set the install path -echo '[install_scripts]' >setup.cfg -echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg - -[ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload -make prefix=$RPM_BUILD_ROOT%{__prefix} install - -# REPLACE PATH IN PYDOC -if [ ! -z "%{binsuffix}" ] -then - ( - cd $RPM_BUILD_ROOT%{__prefix}/bin - mv pydoc pydoc.old - sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ - pydoc.old >pydoc - chmod 755 pydoc - rm -f pydoc.old - ) -fi - -# add the binsuffix -if [ ! -z "%{binsuffix}" ] -then - rm -f $RPM_BUILD_ROOT%{__prefix}/bin/python[0-9a-zA-Z]* - ( cd $RPM_BUILD_ROOT%{__prefix}/bin; - for file in *; do mv "$file" "$file"%{binsuffix}; done ) - ( cd $RPM_BUILD_ROOT%{_mandir}/man1; mv python.1 python%{binsuffix}.1 ) -fi - -######## -# Tools -echo '#!%{__prefix}/bin/env python%{binsuffix}' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'import os, sys' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'os.execvp("%{__prefix}/bin/python%{binsuffix}", ["%{__prefix}/bin/python%{binsuffix}", "%{__prefix}/lib/python%{libvers}/idlelib/idle.py"] + sys.argv[1:])' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'print "Failed to exec Idle"' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'sys.exit(1)' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} -cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} - -# MAKE FILE LISTS -rm -f mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers} -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/python%{libvers}/config$' -e '_tkinter.so$' >mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f -o -type l | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/bin/2to3%{binsuffix}$' | - grep -v -e '/bin/pydoc%{binsuffix}$' | - grep -v -e '/bin/smtpd.py%{binsuffix}$' | - grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files - -rm -f tools.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ - "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files -echo "%{__prefix}"/bin/2to3%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/pydoc%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/smtpd.py%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files - -###### -# Docs -%if %{include_docs} -mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} -( - cd "$RPM_BUILD_ROOT"%{config_htmldir} - bunzip2 < %{SOURCE1} | tar x -) -%endif - -# fix the #! line in installed files -find "$RPM_BUILD_ROOT" -type f -print0 | - xargs -0 grep -l /usr/local/bin/python | while read file -do - FIXFILE="$file" - sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ - "$FIXFILE" >/tmp/fix-python-path.$$ - cat /tmp/fix-python-path.$$ >"$FIXFILE" - rm -f /tmp/fix-python-path.$$ -done - -# check to see if there are any straggling #! lines -find "$RPM_BUILD_ROOT" -type f | xargs egrep -n '^#! */usr/local/bin/python' \ - | grep ':1:#!' >/tmp/python-rpm-files.$$ || true -if [ -s /tmp/python-rpm-files.$$ ] -then - echo '*****************************************************' - cat /tmp/python-rpm-files.$$ - cat <<@EOF - ***************************************************** - There are still files referencing /usr/local/bin/python in the - install directory. They are listed above. Please fix the .spec - file and try again. If you are an end-user, you probably want - to report this to jafo-rpms at tummy.com as well. - ***************************************************** - at EOF - rm -f /tmp/python-rpm-files.$$ - exit 1 -fi -rm -f /tmp/python-rpm-files.$$ - -######## -# CLEAN -######## -%clean -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT -rm -f mainpkg.files tools.files - -######## -# FILES -######## -%files -f mainpkg.files -%defattr(-,root,root) -%doc Misc/README Misc/cheatsheet Misc/Porting -%doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS -%{_mandir}/man1/python%{binsuffix}.1* - -%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} -%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ -%if %{include_sharedlib} -%{__prefix}/%{libdirname}/libpython* -%endif - -%files devel -%defattr(-,root,root) -%{__prefix}/include/python%{libvers}/*.h -%{__prefix}/%{libdirname}/python%{libvers}/config - -%files -f tools.files tools -%defattr(-,root,root) - -%if %{include_tkinter} -%files tkinter -%defattr(-,root,root) -%{__prefix}/%{libdirname}/python%{libvers}/tkinter -%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* -%endif - -%if %{include_docs} -%files docs -%defattr(-,root,root) -%{config_htmldir}/* -%endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:45 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150218135735.12748.37814@psf.io> https://hg.python.org/cpython/rev/b2d238adf802 changeset: 94683:b2d238adf802 parent: 94682:e7dcab87ff6c parent: 94681:78145e6ffb40 user: Benjamin Peterson date: Wed Feb 18 08:56:47 2015 -0500 summary: merge 3.4 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:45 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_RPM_fil?= =?utf-8?q?e=2C_which_is_unused_and_unmaintained?= Message-ID: <20150218135735.25203.45163@psf.io> https://hg.python.org/cpython/rev/ba2b0e6a888f changeset: 94684:ba2b0e6a888f branch: 2.7 parent: 94674:7ef372f656d1 user: Benjamin Peterson date: Wed Feb 18 08:57:27 2015 -0500 summary: remove RPM file, which is unused and unmaintained files: Misc/README | 1 - Misc/RPM/README | 16 - Misc/RPM/python-2.7.spec | 390 --------------------------- 3 files changed, 0 insertions(+), 407 deletions(-) diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -34,7 +34,6 @@ README.OpenBSD Help for building problems on OpenBSD README.valgrind Information for Valgrind users, see valgrind-python.supp RFD Request For Discussion about a Python newsgroup -RPM (Old) tools to build RPMs setuid-prog.c C helper program for set-uid Python scripts SpecialBuilds.txt Describes extra symbols you can set for debug builds TextMate A TextMate bundle for Python development diff --git a/Misc/RPM/README b/Misc/RPM/README deleted file mode 100644 --- a/Misc/RPM/README +++ /dev/null @@ -1,16 +0,0 @@ -This directory contains support file used to build RPM releases of -Python. Its contents are maintained by Sean Reifschneider -. - -It is recommended that RPM builders use the python*.src.rpm file -downloaded from the "ftp.python.org:/pub/python//rpms". These -may be more up to date than the files included in the base Python -release tar-file. - -If you wish to build RPMs from the base Python release tar-file, note -that you will have to download the -"doc//html-.tar.bz2" -file from python.org and place it into your "SOURCES" directory for -the build to complete. This is the same directory that you place the -Python-2.3.1 release tar-file in. You can then use the ".spec" file in -this directory to build RPMs. diff --git a/Misc/RPM/python-2.7.spec b/Misc/RPM/python-2.7.spec deleted file mode 100644 --- a/Misc/RPM/python-2.7.spec +++ /dev/null @@ -1,390 +0,0 @@ -########################## -# User-modifiable configs -########################## - -# Is the resulting package and the installed binary named "python" or -# "python2"? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_binsuffix none -%define config_binsuffix 2.6 - -# Build tkinter? "auto" enables it if /usr/bin/wish exists. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_tkinter no -%define config_tkinter yes -%define config_tkinter auto - -# Use pymalloc? The last line (commented or not) determines wether -# pymalloc is used. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_pymalloc no -%define config_pymalloc yes - -# Enable IPV6? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_ipv6 yes -%define config_ipv6 no - -# Build shared libraries or .a library? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_sharedlib no -%define config_sharedlib yes - -# Location of the HTML directory. -%define config_htmldir /var/www/html/python - -################################# -# End of user-modifiable configs -################################# - -%define name python -#--start constants-- -%define version 2.7.9 -%define libvers 2.7 -#--end constants-- -%define release 1pydotorg -%define __prefix /usr - -# kludge to get around rpm define weirdness -%define ipv6 %(if [ "%{config_ipv6}" = yes ]; then echo --enable-ipv6; else echo --disable-ipv6; fi) -%define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) -%define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) -%define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) -%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) -%define sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo --enable-shared; else echo ; fi) -%define include_sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo 1; else echo 0; fi) - -# detect if documentation is available -%define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) - -Summary: An interpreted, interactive, object-oriented programming language. -Name: %{name}%{binsuffix} -Version: %{version} -Release: %{release} -License: PSF -Group: Development/Languages -Source: Python-%{version}.tar.bz2 -%if %{include_docs} -Source1: html-%{version}.tar.bz2 -%endif -BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildPrereq: expat-devel -BuildPrereq: db4-devel -BuildPrereq: gdbm-devel -BuildPrereq: sqlite-devel -Prefix: %{__prefix} -Packager: Sean Reifschneider - -%description -Python is an interpreted, interactive, object-oriented programming -language. It incorporates modules, exceptions, dynamic typing, very high -level dynamic data types, and classes. Python combines remarkable power -with very clear syntax. It has interfaces to many system calls and -libraries, as well as to various window systems, and is extensible in C or -C++. It is also usable as an extension language for applications that need -a programmable interface. Finally, Python is portable: it runs on many -brands of UNIX, on PCs under Windows, MS-DOS, and OS/2, and on the -Mac. - -%package devel -Summary: The libraries and header files needed for Python extension development. -Prereq: python%{binsuffix} = %{PACKAGE_VERSION} -Group: Development/Libraries - -%description devel -The Python programming language's interpreter can be extended with -dynamically loaded extensions and can be embedded in other programs. -This package contains the header files and libraries needed to do -these types of tasks. - -Install python-devel if you want to develop Python extensions. The -python package will also need to be installed. You'll probably also -want to install the python-docs package, which contains Python -documentation. - -%if %{include_tkinter} -%package tkinter -Summary: A graphical user interface for the Python scripting language. -Group: Development/Languages -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tkinter -The Tkinter (Tk interface) program is an graphical user interface for -the Python scripting language. - -You should install the tkinter package if you'd like to use a graphical -user interface for Python programming. -%endif - -%package tools -Summary: A collection of development tools included with Python. -Group: Development/Tools -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tools -The Python package includes several development tools that are used -to build python programs. This package contains a selection of those -tools, including the IDLE Python IDE. - -Install python-tools if you want to use these tools to develop -Python programs. You will also need to install the python and -tkinter packages. - -%if %{include_docs} -%package docs -Summary: Python-related documentation. -Group: Development/Documentation - -%description docs -Documentation relating to the Python programming language in HTML and info -formats. -%endif - -%changelog -* Mon Dec 20 2004 Sean Reifschneider [2.4-2pydotorg] -- Changing the idle wrapper so that it passes arguments to idle. - -* Tue Oct 19 2004 Sean Reifschneider [2.4b1-1pydotorg] -- Updating to 2.4. - -* Thu Jul 22 2004 Sean Reifschneider [2.3.4-3pydotorg] -- Paul Tiemann fixes for %{prefix}. -- Adding permission changes for directory as suggested by reimeika.ca -- Adding code to detect when it should be using lib64. -- Adding a define for the location of /var/www/html for docs. - -* Thu May 27 2004 Sean Reifschneider [2.3.4-2pydotorg] -- Including changes from Ian Holsman to build under Red Hat 7.3. -- Fixing some problems with the /usr/local path change. - -* Sat Mar 27 2004 Sean Reifschneider [2.3.2-3pydotorg] -- Being more agressive about finding the paths to fix for - #!/usr/local/bin/python. - -* Sat Feb 07 2004 Sean Reifschneider [2.3.3-2pydotorg] -- Adding code to remove "#!/usr/local/bin/python" from particular files and - causing the RPM build to terminate if there are any unexpected files - which have that line in them. - -* Mon Oct 13 2003 Sean Reifschneider [2.3.2-1pydotorg] -- Adding code to detect wether documentation is available to build. - -* Fri Sep 19 2003 Sean Reifschneider [2.3.1-1pydotorg] -- Updating to the 2.3.1 release. - -* Mon Feb 24 2003 Sean Reifschneider [2.3b1-1pydotorg] -- Updating to 2.3b1 release. - -* Mon Feb 17 2003 Sean Reifschneider [2.3a1-1] -- Updating to 2.3 release. - -* Sun Dec 23 2001 Sean Reifschneider -[Release 2.2-2] -- Added -docs package. -- Added "auto" config_tkinter setting which only enables tk if - /usr/bin/wish exists. - -* Sat Dec 22 2001 Sean Reifschneider -[Release 2.2-1] -- Updated to 2.2. -- Changed the extension to "2" from "2.2". - -* Tue Nov 18 2001 Sean Reifschneider -[Release 2.2c1-1] -- Updated to 2.2c1. - -* Thu Nov 1 2001 Sean Reifschneider -[Release 2.2b1-3] -- Changed the way the sed for fixing the #! in pydoc works. - -* Wed Oct 24 2001 Sean Reifschneider -[Release 2.2b1-2] -- Fixed missing "email" package, thanks to anonymous report on sourceforge. -- Fixed missing "compiler" package. - -* Mon Oct 22 2001 Sean Reifschneider -[Release 2.2b1-1] -- Updated to 2.2b1. - -* Mon Oct 9 2001 Sean Reifschneider -[Release 2.2a4-4] -- otto at balinor.mat.unimi.it mentioned that the license file is missing. - -* Sun Sep 30 2001 Sean Reifschneider -[Release 2.2a4-3] -- Ignacio Vazquez-Abrams pointed out that I had a spruious double-quote in - the spec files. Thanks. - -* Wed Jul 25 2001 Sean Reifschneider -[Release 2.2a1-1] -- Updated to 2.2a1 release. -- Changed idle and pydoc to use binsuffix macro - -####### -# PREP -####### -%prep -%setup -n Python-%{version} - -######## -# BUILD -######## -%build -echo "Setting for ipv6: %{ipv6}" -echo "Setting for pymalloc: %{pymalloc}" -echo "Setting for binsuffix: %{binsuffix}" -echo "Setting for include_tkinter: %{include_tkinter}" -echo "Setting for libdirname: %{libdirname}" -echo "Setting for sharedlib: %{sharedlib}" -echo "Setting for include_sharedlib: %{include_sharedlib}" -./configure --enable-unicode=ucs4 %{sharedlib} %{ipv6} %{pymalloc} --prefix=%{__prefix} -make - -########## -# INSTALL -########## -%install -# set the install path -echo '[install_scripts]' >setup.cfg -echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg - -[ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload -make prefix=$RPM_BUILD_ROOT%{__prefix} install - -# REPLACE PATH IN PYDOC -if [ ! -z "%{binsuffix}" ] -then - ( - cd $RPM_BUILD_ROOT%{__prefix}/bin - mv pydoc pydoc.old - sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ - pydoc.old >pydoc - chmod 755 pydoc - rm -f pydoc.old - ) -fi - -# add the binsuffix -if [ ! -z "%{binsuffix}" ] -then - rm -f $RPM_BUILD_ROOT%{__prefix}/bin/python[0-9a-zA-Z]* - ( cd $RPM_BUILD_ROOT%{__prefix}/bin; - for file in *; do mv "$file" "$file"%{binsuffix}; done ) - ( cd $RPM_BUILD_ROOT%{_mandir}/man1; mv python.1 python%{binsuffix}.1 ) -fi - -######## -# Tools -echo '#!%{__prefix}/bin/env python%{binsuffix}' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'import os, sys' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'os.execvp("%{__prefix}/bin/python%{binsuffix}", ["%{__prefix}/bin/python%{binsuffix}", "%{__prefix}/lib/python%{libvers}/idlelib/idle.py"] + sys.argv[1:])' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'print "Failed to exec Idle"' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'sys.exit(1)' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} -cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} - -# MAKE FILE LISTS -rm -f mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers} -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/python%{libvers}/config$' -e '_tkinter.so$' >mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f -o -type l | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/bin/2to3%{binsuffix}$' | - grep -v -e '/bin/pydoc%{binsuffix}$' | - grep -v -e '/bin/smtpd.py%{binsuffix}$' | - grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files - -rm -f tools.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ - "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files -echo "%{__prefix}"/bin/2to3%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/pydoc%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/smtpd.py%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files - -###### -# Docs -%if %{include_docs} -mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} -( - cd "$RPM_BUILD_ROOT"%{config_htmldir} - bunzip2 < %{SOURCE1} | tar x -) -%endif - -# fix the #! line in installed files -find "$RPM_BUILD_ROOT" -type f -print0 | - xargs -0 grep -l /usr/local/bin/python | while read file -do - FIXFILE="$file" - sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ - "$FIXFILE" >/tmp/fix-python-path.$$ - cat /tmp/fix-python-path.$$ >"$FIXFILE" - rm -f /tmp/fix-python-path.$$ -done - -# check to see if there are any straggling #! lines -find "$RPM_BUILD_ROOT" -type f | xargs egrep -n '^#! */usr/local/bin/python' \ - | grep ':1:#!' >/tmp/python-rpm-files.$$ || true -if [ -s /tmp/python-rpm-files.$$ ] -then - echo '*****************************************************' - cat /tmp/python-rpm-files.$$ - cat <<@EOF - ***************************************************** - There are still files referencing /usr/local/bin/python in the - install directory. They are listed above. Please fix the .spec - file and try again. If you are an end-user, you probably want - to report this to jafo-rpms at tummy.com as well. - ***************************************************** - at EOF - rm -f /tmp/python-rpm-files.$$ - exit 1 -fi -rm -f /tmp/python-rpm-files.$$ - -######## -# CLEAN -######## -%clean -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT -rm -f mainpkg.files tools.files - -######## -# FILES -######## -%files -f mainpkg.files -%defattr(-,root,root) -%doc Misc/README Misc/cheatsheet Misc/Porting -%doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS -%{_mandir}/man1/python%{binsuffix}.1* - -%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} -%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ -%if %{include_sharedlib} -%{__prefix}/%{libdirname}/libpython* -%endif - -%files devel -%defattr(-,root,root) -%{__prefix}/include/python%{libvers}/*.h -%{__prefix}/%{libdirname}/python%{libvers}/config - -%files -f tools.files tools -%defattr(-,root,root) - -%if %{include_tkinter} -%files tkinter -%defattr(-,root,root) -%{__prefix}/%{libdirname}/python%{libvers}/lib-tk -%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* -%endif - -%if %{include_docs} -%files docs -%defattr(-,root,root) -%{config_htmldir}/* -%endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:45 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogcmVtb3ZlIFJQTSwg?= =?utf-8?q?since_it=27s_unused_and_unmaintained?= Message-ID: <20150218135734.25207.16109@psf.io> https://hg.python.org/cpython/rev/29316b605ae4 changeset: 94677:29316b605ae4 branch: 3.2 parent: 94401:9fe1d861f486 user: Benjamin Peterson date: Wed Feb 18 08:52:46 2015 -0500 summary: remove RPM, since it's unused and unmaintained files: Misc/README | 1 - Misc/RPM/README | 33 -- Misc/RPM/python-3.2.spec | 390 --------------------------- 3 files changed, 0 insertions(+), 424 deletions(-) diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -20,7 +20,6 @@ python-wing*.wpr Wing IDE project file README The file you're reading now README.valgrind Information for Valgrind users, see valgrind-python.supp -RPM (Old) tools to build RPMs SpecialBuilds.txt Describes extra symbols you can set for debug builds TextMate A TextMate bundle for Python development valgrind-python.supp Valgrind suppression file, see README.valgrind diff --git a/Misc/RPM/README b/Misc/RPM/README deleted file mode 100644 --- a/Misc/RPM/README +++ /dev/null @@ -1,33 +0,0 @@ -This directory contains support file used to build RPM releases of -Python. Its contents are maintained by Sean Reifschneider -. - -If you wish to build RPMs from the base Python release tar-file, note -that you will have to download the -"doc//html-.tar.bz2" -file from python.org and place it into your "SOURCES" directory for -the build to complete. This is the same directory that you place the -Python-2.3.1 release tar-file in. You can then use the ".spec" file in -this directory to build RPMs. - -You may also wish to pursue RPMs provided by distribution makers to see if -they have one suitable for your uses. If, for example, you just want a -slightly newer version of Python than what the distro provides, you could -pick up the closest SRPM your distro provides, and then modify it to -the newer version, and build that. It may be as simple as just changing -the "version" information in the spec file (or it may require fixing -patches). - -NOTE: I am *NOT* recommending just using the binary RPM, and never do an -install with "--force" or "--nodeps". - -Also worth pursuing may be newer versions provided by similar distros. For -example, a Python 3 SRPM from Fedora may be a good baseline to try building -on CentOS. - -Many newer SRPMs won't install on older distros because of format changes. -You can manually extract these SRPMS with: - - mkdir foo - cd foo - rpm2cpio <../python3-*.src.rpm | cpio -ivd diff --git a/Misc/RPM/python-3.2.spec b/Misc/RPM/python-3.2.spec deleted file mode 100644 --- a/Misc/RPM/python-3.2.spec +++ /dev/null @@ -1,390 +0,0 @@ -########################## -# User-modifiable configs -########################## - -# Is the resulting package and the installed binary named "python" or -# "python2"? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_binsuffix none -%define config_binsuffix 2.6 - -# Build tkinter? "auto" enables it if /usr/bin/wish exists. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_tkinter no -%define config_tkinter yes -%define config_tkinter auto - -# Use pymalloc? The last line (commented or not) determines wether -# pymalloc is used. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_pymalloc no -%define config_pymalloc yes - -# Enable IPV6? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_ipv6 yes -%define config_ipv6 no - -# Build shared libraries or .a library? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_sharedlib no -%define config_sharedlib yes - -# Location of the HTML directory. -%define config_htmldir /var/www/html/python - -################################# -# End of user-modifiable configs -################################# - -%define name python -#--start constants-- -%define version 3.2.6 -%define libvers 3.2 -#--end constants-- -%define release 1pydotorg -%define __prefix /usr - -# kludge to get around rpm define weirdness -%define ipv6 %(if [ "%{config_ipv6}" = yes ]; then echo --enable-ipv6; else echo --disable-ipv6; fi) -%define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) -%define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) -%define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) -%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) -%define sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo --enable-shared; else echo ; fi) -%define include_sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo 1; else echo 0; fi) - -# detect if documentation is available -%define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) - -Summary: An interpreted, interactive, object-oriented programming language. -Name: %{name}%{binsuffix} -Version: %{version} -Release: %{release} -License: PSF -Group: Development/Languages -Source: Python-%{version}.tar.bz2 -%if %{include_docs} -Source1: html-%{version}.tar.bz2 -%endif -BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildPrereq: expat-devel -BuildPrereq: db4-devel -BuildPrereq: gdbm-devel -BuildPrereq: sqlite-devel -Prefix: %{__prefix} -Packager: Sean Reifschneider - -%description -Python is an interpreted, interactive, object-oriented programming -language. It incorporates modules, exceptions, dynamic typing, very high -level dynamic data types, and classes. Python combines remarkable power -with very clear syntax. It has interfaces to many system calls and -libraries, as well as to various window systems, and is extensible in C or -C++. It is also usable as an extension language for applications that need -a programmable interface. Finally, Python is portable: it runs on many -brands of UNIX, on PCs under Windows, MS-DOS, and OS/2, and on the -Mac. - -%package devel -Summary: The libraries and header files needed for Python extension development. -Prereq: python%{binsuffix} = %{PACKAGE_VERSION} -Group: Development/Libraries - -%description devel -The Python programming language's interpreter can be extended with -dynamically loaded extensions and can be embedded in other programs. -This package contains the header files and libraries needed to do -these types of tasks. - -Install python-devel if you want to develop Python extensions. The -python package will also need to be installed. You'll probably also -want to install the python-docs package, which contains Python -documentation. - -%if %{include_tkinter} -%package tkinter -Summary: A graphical user interface for the Python scripting language. -Group: Development/Languages -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tkinter -The Tkinter (Tk interface) program is an graphical user interface for -the Python scripting language. - -You should install the tkinter package if you'd like to use a graphical -user interface for Python programming. -%endif - -%package tools -Summary: A collection of development tools included with Python. -Group: Development/Tools -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tools -The Python package includes several development tools that are used -to build python programs. This package contains a selection of those -tools, including the IDLE Python IDE. - -Install python-tools if you want to use these tools to develop -Python programs. You will also need to install the python and -tkinter packages. - -%if %{include_docs} -%package docs -Summary: Python-related documentation. -Group: Development/Documentation - -%description docs -Documentation relating to the Python programming language in HTML and info -formats. -%endif - -%changelog -* Mon Dec 20 2004 Sean Reifschneider [2.4-2pydotorg] -- Changing the idle wrapper so that it passes arguments to idle. - -* Tue Oct 19 2004 Sean Reifschneider [2.4b1-1pydotorg] -- Updating to 2.4. - -* Thu Jul 22 2004 Sean Reifschneider [2.3.4-3pydotorg] -- Paul Tiemann fixes for %{prefix}. -- Adding permission changes for directory as suggested by reimeika.ca -- Adding code to detect when it should be using lib64. -- Adding a define for the location of /var/www/html for docs. - -* Thu May 27 2004 Sean Reifschneider [2.3.4-2pydotorg] -- Including changes from Ian Holsman to build under Red Hat 7.3. -- Fixing some problems with the /usr/local path change. - -* Sat Mar 27 2004 Sean Reifschneider [2.3.2-3pydotorg] -- Being more agressive about finding the paths to fix for - #!/usr/local/bin/python. - -* Sat Feb 07 2004 Sean Reifschneider [2.3.3-2pydotorg] -- Adding code to remove "#!/usr/local/bin/python" from particular files and - causing the RPM build to terminate if there are any unexpected files - which have that line in them. - -* Mon Oct 13 2003 Sean Reifschneider [2.3.2-1pydotorg] -- Adding code to detect wether documentation is available to build. - -* Fri Sep 19 2003 Sean Reifschneider [2.3.1-1pydotorg] -- Updating to the 2.3.1 release. - -* Mon Feb 24 2003 Sean Reifschneider [2.3b1-1pydotorg] -- Updating to 2.3b1 release. - -* Mon Feb 17 2003 Sean Reifschneider [2.3a1-1] -- Updating to 2.3 release. - -* Sun Dec 23 2001 Sean Reifschneider -[Release 2.2-2] -- Added -docs package. -- Added "auto" config_tkinter setting which only enables tk if - /usr/bin/wish exists. - -* Sat Dec 22 2001 Sean Reifschneider -[Release 2.2-1] -- Updated to 2.2. -- Changed the extension to "2" from "2.2". - -* Tue Nov 18 2001 Sean Reifschneider -[Release 2.2c1-1] -- Updated to 2.2c1. - -* Thu Nov 1 2001 Sean Reifschneider -[Release 2.2b1-3] -- Changed the way the sed for fixing the #! in pydoc works. - -* Wed Oct 24 2001 Sean Reifschneider -[Release 2.2b1-2] -- Fixed missing "email" package, thanks to anonymous report on sourceforge. -- Fixed missing "compiler" package. - -* Mon Oct 22 2001 Sean Reifschneider -[Release 2.2b1-1] -- Updated to 2.2b1. - -* Mon Oct 9 2001 Sean Reifschneider -[Release 2.2a4-4] -- otto at balinor.mat.unimi.it mentioned that the license file is missing. - -* Sun Sep 30 2001 Sean Reifschneider -[Release 2.2a4-3] -- Ignacio Vazquez-Abrams pointed out that I had a spruious double-quote in - the spec files. Thanks. - -* Wed Jul 25 2001 Sean Reifschneider -[Release 2.2a1-1] -- Updated to 2.2a1 release. -- Changed idle and pydoc to use binsuffix macro - -####### -# PREP -####### -%prep -%setup -n Python-%{version} - -######## -# BUILD -######## -%build -echo "Setting for ipv6: %{ipv6}" -echo "Setting for pymalloc: %{pymalloc}" -echo "Setting for binsuffix: %{binsuffix}" -echo "Setting for include_tkinter: %{include_tkinter}" -echo "Setting for libdirname: %{libdirname}" -echo "Setting for sharedlib: %{sharedlib}" -echo "Setting for include_sharedlib: %{include_sharedlib}" -./configure --enable-unicode=ucs4 %{sharedlib} %{ipv6} %{pymalloc} --prefix=%{__prefix} -make - -########## -# INSTALL -########## -%install -# set the install path -echo '[install_scripts]' >setup.cfg -echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg - -[ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload -make prefix=$RPM_BUILD_ROOT%{__prefix} install - -# REPLACE PATH IN PYDOC -if [ ! -z "%{binsuffix}" ] -then - ( - cd $RPM_BUILD_ROOT%{__prefix}/bin - mv pydoc pydoc.old - sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ - pydoc.old >pydoc - chmod 755 pydoc - rm -f pydoc.old - ) -fi - -# add the binsuffix -if [ ! -z "%{binsuffix}" ] -then - rm -f $RPM_BUILD_ROOT%{__prefix}/bin/python[0-9a-zA-Z]* - ( cd $RPM_BUILD_ROOT%{__prefix}/bin; - for file in *; do mv "$file" "$file"%{binsuffix}; done ) - ( cd $RPM_BUILD_ROOT%{_mandir}/man1; mv python.1 python%{binsuffix}.1 ) -fi - -######## -# Tools -echo '#!%{__prefix}/bin/env python%{binsuffix}' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'import os, sys' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'os.execvp("%{__prefix}/bin/python%{binsuffix}", ["%{__prefix}/bin/python%{binsuffix}", "%{__prefix}/lib/python%{libvers}/idlelib/idle.py"] + sys.argv[1:])' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'print "Failed to exec Idle"' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'sys.exit(1)' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} -cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} - -# MAKE FILE LISTS -rm -f mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers} -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/python%{libvers}/config$' -e '_tkinter.so$' >mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f -o -type l | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/bin/2to3%{binsuffix}$' | - grep -v -e '/bin/pydoc%{binsuffix}$' | - grep -v -e '/bin/smtpd.py%{binsuffix}$' | - grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files - -rm -f tools.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ - "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files -echo "%{__prefix}"/bin/2to3%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/pydoc%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/smtpd.py%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files - -###### -# Docs -%if %{include_docs} -mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} -( - cd "$RPM_BUILD_ROOT"%{config_htmldir} - bunzip2 < %{SOURCE1} | tar x -) -%endif - -# fix the #! line in installed files -find "$RPM_BUILD_ROOT" -type f -print0 | - xargs -0 grep -l /usr/local/bin/python | while read file -do - FIXFILE="$file" - sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ - "$FIXFILE" >/tmp/fix-python-path.$$ - cat /tmp/fix-python-path.$$ >"$FIXFILE" - rm -f /tmp/fix-python-path.$$ -done - -# check to see if there are any straggling #! lines -find "$RPM_BUILD_ROOT" -type f | xargs egrep -n '^#! */usr/local/bin/python' \ - | grep ':1:#!' >/tmp/python-rpm-files.$$ || true -if [ -s /tmp/python-rpm-files.$$ ] -then - echo '*****************************************************' - cat /tmp/python-rpm-files.$$ - cat <<@EOF - ***************************************************** - There are still files referencing /usr/local/bin/python in the - install directory. They are listed above. Please fix the .spec - file and try again. If you are an end-user, you probably want - to report this to jafo-rpms at tummy.com as well. - ***************************************************** - at EOF - rm -f /tmp/python-rpm-files.$$ - exit 1 -fi -rm -f /tmp/python-rpm-files.$$ - -######## -# CLEAN -######## -%clean -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT -rm -f mainpkg.files tools.files - -######## -# FILES -######## -%files -f mainpkg.files -%defattr(-,root,root) -%doc Misc/README Misc/cheatsheet Misc/Porting -%doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS -%{_mandir}/man1/python%{binsuffix}.1* - -%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} -%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ -%if %{include_sharedlib} -%{__prefix}/%{libdirname}/libpython* -%endif - -%files devel -%defattr(-,root,root) -%{__prefix}/include/python%{libvers}/*.h -%{__prefix}/%{libdirname}/python%{libvers}/config - -%files -f tools.files tools -%defattr(-,root,root) - -%if %{include_tkinter} -%files tkinter -%defattr(-,root,root) -%{__prefix}/%{libdirname}/python%{libvers}/tkinter -%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* -%endif - -%if %{include_docs} -%files docs -%defattr(-,root,root) -%{config_htmldir}/* -%endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:45 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNCk6?= =?utf-8?q?_merge_heads?= Message-ID: <20150218135734.5049.13818@psf.io> https://hg.python.org/cpython/rev/78145e6ffb40 changeset: 94681:78145e6ffb40 branch: 3.4 parent: 94679:2c033f80affa parent: 94675:b53aadd9cf85 user: Benjamin Peterson date: Wed Feb 18 08:56:33 2015 -0500 summary: merge heads files: Lib/test/test__locale.py | 97 +++++++++++++++++---------- Lib/test/test_locale.py | 2 +- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -9,7 +9,6 @@ import sys import unittest from platform import uname -from test.support import run_unittest if uname().system == "Darwin": maj, min, mic = [int(part) for part in uname().release.split(".")] @@ -24,45 +23,52 @@ 'da_DK', 'nn_NO', 'cs_CZ', 'de_LU', 'es_BO', 'sq_AL', 'sk_SK', 'fr_CH', 'de_DE', 'sr_YU', 'br_FR', 'nl_BE', 'sv_FI', 'pl_PL', 'fr_CA', 'fo_FO', 'bs_BA', 'fr_LU', 'kl_GL', 'fa_IR', 'de_BE', 'sv_SE', 'it_CH', 'uk_UA', - 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'en_US', + 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'ps_AF', 'en_US', 'es_ES.ISO8859-1', 'fr_FR.ISO8859-15', 'ru_RU.KOI8-R', 'ko_KR.eucKR'] -# Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to -# workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses -# the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is -# decoded as U+30000020 (an invalid character) by mbstowcs(). -if sys.platform == 'sunos5': - old_locale = locale.setlocale(locale.LC_ALL) - try: - locales = [] - for loc in candidate_locales: - try: - locale.setlocale(locale.LC_ALL, loc) - except Error: - continue - encoding = locale.getpreferredencoding(False) - try: - localeconv() - except Exception as err: - print("WARNING: Skip locale %s (encoding %s): [%s] %s" - % (loc, encoding, type(err), err)) - else: - locales.append(loc) - candidate_locales = locales - finally: - locale.setlocale(locale.LC_ALL, old_locale) +def setUpModule(): + global candidate_locales + # Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to + # workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses + # the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is + # decoded as U+30000020 (an invalid character) by mbstowcs(). + if sys.platform == 'sunos5': + old_locale = locale.setlocale(locale.LC_ALL) + try: + locales = [] + for loc in candidate_locales: + try: + locale.setlocale(locale.LC_ALL, loc) + except Error: + continue + encoding = locale.getpreferredencoding(False) + try: + localeconv() + except Exception as err: + print("WARNING: Skip locale %s (encoding %s): [%s] %s" + % (loc, encoding, type(err), err)) + else: + locales.append(loc) + candidate_locales = locales + finally: + locale.setlocale(locale.LC_ALL, old_locale) -# Workaround for MSVC6(debug) crash bug -if "MSC v.1200" in sys.version: - def accept(loc): - a = loc.split(".") - return not(len(a) == 2 and len(a[-1]) >= 9) - candidate_locales = [loc for loc in candidate_locales if accept(loc)] + # Workaround for MSVC6(debug) crash bug + if "MSC v.1200" in sys.version: + def accept(loc): + a = loc.split(".") + return not(len(a) == 2 and len(a[-1]) >= 9) + candidate_locales = [loc for loc in candidate_locales if accept(loc)] # List known locale values to test against when available. # Dict formatted as `` : (, )``. If a # value is not known, use '' . -known_numerics = {'fr_FR' : (',', ''), 'en_US':('.', ',')} +known_numerics = { + 'en_US': ('.', ','), + 'fr_FR' : (',', ' '), + 'de_DE' : (',', '.'), + 'ps_AF': ('\u066b', '\u066c'), +} class _LocaleTests(unittest.TestCase): @@ -91,10 +97,12 @@ calc_value, known_value, calc_type, data_type, set_locale, used_locale)) + return True @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_nl_langinfo(self): # Test nl_langinfo against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -103,10 +111,14 @@ continue for li, lc in ((RADIXCHAR, "decimal_point"), (THOUSEP, "thousands_sep")): - self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc) + if self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') def test_lc_numeric_localeconv(self): # Test localeconv against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -116,11 +128,15 @@ formatting = localeconv() for lc in ("decimal_point", "thousands_sep"): - self.numeric_tester('localeconv', formatting[lc], lc, loc) + if self.numeric_tester('localeconv', formatting[lc], lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_basic(self): # Test nl_langinfo against localeconv + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -140,10 +156,14 @@ "(set to %s, using %s)" % ( nl_radixchar, li_radixchar, loc, set_locale)) + tested = True + if not tested: + self.skipTest('no suitable locales') def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -162,9 +182,10 @@ if localeconv()['decimal_point'] != '.': self.assertRaises(ValueError, float, localeconv()['decimal_point'].join(['1', '23'])) + tested = True + if not tested: + self.skipTest('no suitable locales') -def test_main(): - run_unittest(_LocaleTests) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -511,7 +511,7 @@ self.skipTest('test needs Turkish locale') loc = locale.getlocale(locale.LC_CTYPE) if verbose: - print('got locale %a' % (loc,)) + print('testing with %a' % (loc,), end=' ', flush=True) locale.setlocale(locale.LC_CTYPE, loc) self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:45 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMyk6?= =?utf-8?q?_merge_3=2E2?= Message-ID: <20150218135734.26272.66117@psf.io> https://hg.python.org/cpython/rev/221301c8095f changeset: 94678:221301c8095f branch: 3.3 parent: 94574:ab2e79c6cf6b parent: 94677:29316b605ae4 user: Benjamin Peterson date: Wed Feb 18 08:54:22 2015 -0500 summary: merge 3.2 files: Misc/README | 1 - Misc/RPM/README | 33 -- Misc/RPM/python-3.3.spec | 390 --------------------------- 3 files changed, 0 insertions(+), 424 deletions(-) diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -21,7 +21,6 @@ README.AIX Information about using Python on AIX README.coverity Information about running Coverity's Prevent on Python README.valgrind Information for Valgrind users, see valgrind-python.supp -RPM (Old) tools to build RPMs svnmap.txt Map of old SVN revs and branches to hg changeset ids SpecialBuilds.txt Describes extra symbols you can set for debug builds TextMate A TextMate bundle for Python development diff --git a/Misc/RPM/README b/Misc/RPM/README deleted file mode 100644 --- a/Misc/RPM/README +++ /dev/null @@ -1,33 +0,0 @@ -This directory contains support file used to build RPM releases of -Python. Its contents are maintained by Sean Reifschneider -. - -If you wish to build RPMs from the base Python release tar-file, note -that you will have to download the -"doc//html-.tar.bz2" -file from python.org and place it into your "SOURCES" directory for -the build to complete. This is the same directory that you place the -Python-2.3.1 release tar-file in. You can then use the ".spec" file in -this directory to build RPMs. - -You may also wish to pursue RPMs provided by distribution makers to see if -they have one suitable for your uses. If, for example, you just want a -slightly newer version of Python than what the distro provides, you could -pick up the closest SRPM your distro provides, and then modify it to -the newer version, and build that. It may be as simple as just changing -the "version" information in the spec file (or it may require fixing -patches). - -NOTE: I am *NOT* recommending just using the binary RPM, and never do an -install with "--force" or "--nodeps". - -Also worth pursuing may be newer versions provided by similar distros. For -example, a Python 3 SRPM from Fedora may be a good baseline to try building -on CentOS. - -Many newer SRPMs won't install on older distros because of format changes. -You can manually extract these SRPMS with: - - mkdir foo - cd foo - rpm2cpio <../python3-*.src.rpm | cpio -ivd diff --git a/Misc/RPM/python-3.3.spec b/Misc/RPM/python-3.3.spec deleted file mode 100644 --- a/Misc/RPM/python-3.3.spec +++ /dev/null @@ -1,390 +0,0 @@ -########################## -# User-modifiable configs -########################## - -# Is the resulting package and the installed binary named "python" or -# "python2"? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_binsuffix none -%define config_binsuffix 2.6 - -# Build tkinter? "auto" enables it if /usr/bin/wish exists. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_tkinter no -%define config_tkinter yes -%define config_tkinter auto - -# Use pymalloc? The last line (commented or not) determines wether -# pymalloc is used. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_pymalloc no -%define config_pymalloc yes - -# Enable IPV6? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_ipv6 yes -%define config_ipv6 no - -# Build shared libraries or .a library? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_sharedlib no -%define config_sharedlib yes - -# Location of the HTML directory. -%define config_htmldir /var/www/html/python - -################################# -# End of user-modifiable configs -################################# - -%define name python -#--start constants-- -%define version 3.3.6 -%define libvers 3.3 -#--end constants-- -%define release 1pydotorg -%define __prefix /usr - -# kludge to get around rpm define weirdness -%define ipv6 %(if [ "%{config_ipv6}" = yes ]; then echo --enable-ipv6; else echo --disable-ipv6; fi) -%define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) -%define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) -%define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) -%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) -%define sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo --enable-shared; else echo ; fi) -%define include_sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo 1; else echo 0; fi) - -# detect if documentation is available -%define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) - -Summary: An interpreted, interactive, object-oriented programming language. -Name: %{name}%{binsuffix} -Version: %{version} -Release: %{release} -License: PSF -Group: Development/Languages -Source: Python-%{version}.tar.bz2 -%if %{include_docs} -Source1: html-%{version}.tar.bz2 -%endif -BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildPrereq: expat-devel -BuildPrereq: db4-devel -BuildPrereq: gdbm-devel -BuildPrereq: sqlite-devel -Prefix: %{__prefix} -Packager: Sean Reifschneider - -%description -Python is an interpreted, interactive, object-oriented programming -language. It incorporates modules, exceptions, dynamic typing, very high -level dynamic data types, and classes. Python combines remarkable power -with very clear syntax. It has interfaces to many system calls and -libraries, as well as to various window systems, and is extensible in C or -C++. It is also usable as an extension language for applications that need -a programmable interface. Finally, Python is portable: it runs on many -brands of UNIX, on PCs under Windows, MS-DOS, and OS/2, and on the -Mac. - -%package devel -Summary: The libraries and header files needed for Python extension development. -Prereq: python%{binsuffix} = %{PACKAGE_VERSION} -Group: Development/Libraries - -%description devel -The Python programming language's interpreter can be extended with -dynamically loaded extensions and can be embedded in other programs. -This package contains the header files and libraries needed to do -these types of tasks. - -Install python-devel if you want to develop Python extensions. The -python package will also need to be installed. You'll probably also -want to install the python-docs package, which contains Python -documentation. - -%if %{include_tkinter} -%package tkinter -Summary: A graphical user interface for the Python scripting language. -Group: Development/Languages -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tkinter -The Tkinter (Tk interface) program is an graphical user interface for -the Python scripting language. - -You should install the tkinter package if you'd like to use a graphical -user interface for Python programming. -%endif - -%package tools -Summary: A collection of development tools included with Python. -Group: Development/Tools -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tools -The Python package includes several development tools that are used -to build python programs. This package contains a selection of those -tools, including the IDLE Python IDE. - -Install python-tools if you want to use these tools to develop -Python programs. You will also need to install the python and -tkinter packages. - -%if %{include_docs} -%package docs -Summary: Python-related documentation. -Group: Development/Documentation - -%description docs -Documentation relating to the Python programming language in HTML and info -formats. -%endif - -%changelog -* Mon Dec 20 2004 Sean Reifschneider [2.4-2pydotorg] -- Changing the idle wrapper so that it passes arguments to idle. - -* Tue Oct 19 2004 Sean Reifschneider [2.4b1-1pydotorg] -- Updating to 2.4. - -* Thu Jul 22 2004 Sean Reifschneider [2.3.4-3pydotorg] -- Paul Tiemann fixes for %{prefix}. -- Adding permission changes for directory as suggested by reimeika.ca -- Adding code to detect when it should be using lib64. -- Adding a define for the location of /var/www/html for docs. - -* Thu May 27 2004 Sean Reifschneider [2.3.4-2pydotorg] -- Including changes from Ian Holsman to build under Red Hat 7.3. -- Fixing some problems with the /usr/local path change. - -* Sat Mar 27 2004 Sean Reifschneider [2.3.2-3pydotorg] -- Being more agressive about finding the paths to fix for - #!/usr/local/bin/python. - -* Sat Feb 07 2004 Sean Reifschneider [2.3.3-2pydotorg] -- Adding code to remove "#!/usr/local/bin/python" from particular files and - causing the RPM build to terminate if there are any unexpected files - which have that line in them. - -* Mon Oct 13 2003 Sean Reifschneider [2.3.2-1pydotorg] -- Adding code to detect wether documentation is available to build. - -* Fri Sep 19 2003 Sean Reifschneider [2.3.1-1pydotorg] -- Updating to the 2.3.1 release. - -* Mon Feb 24 2003 Sean Reifschneider [2.3b1-1pydotorg] -- Updating to 2.3b1 release. - -* Mon Feb 17 2003 Sean Reifschneider [2.3a1-1] -- Updating to 2.3 release. - -* Sun Dec 23 2001 Sean Reifschneider -[Release 2.2-2] -- Added -docs package. -- Added "auto" config_tkinter setting which only enables tk if - /usr/bin/wish exists. - -* Sat Dec 22 2001 Sean Reifschneider -[Release 2.2-1] -- Updated to 2.2. -- Changed the extension to "2" from "2.2". - -* Tue Nov 18 2001 Sean Reifschneider -[Release 2.2c1-1] -- Updated to 2.2c1. - -* Thu Nov 1 2001 Sean Reifschneider -[Release 2.2b1-3] -- Changed the way the sed for fixing the #! in pydoc works. - -* Wed Oct 24 2001 Sean Reifschneider -[Release 2.2b1-2] -- Fixed missing "email" package, thanks to anonymous report on sourceforge. -- Fixed missing "compiler" package. - -* Mon Oct 22 2001 Sean Reifschneider -[Release 2.2b1-1] -- Updated to 2.2b1. - -* Mon Oct 9 2001 Sean Reifschneider -[Release 2.2a4-4] -- otto at balinor.mat.unimi.it mentioned that the license file is missing. - -* Sun Sep 30 2001 Sean Reifschneider -[Release 2.2a4-3] -- Ignacio Vazquez-Abrams pointed out that I had a spruious double-quote in - the spec files. Thanks. - -* Wed Jul 25 2001 Sean Reifschneider -[Release 2.2a1-1] -- Updated to 2.2a1 release. -- Changed idle and pydoc to use binsuffix macro - -####### -# PREP -####### -%prep -%setup -n Python-%{version} - -######## -# BUILD -######## -%build -echo "Setting for ipv6: %{ipv6}" -echo "Setting for pymalloc: %{pymalloc}" -echo "Setting for binsuffix: %{binsuffix}" -echo "Setting for include_tkinter: %{include_tkinter}" -echo "Setting for libdirname: %{libdirname}" -echo "Setting for sharedlib: %{sharedlib}" -echo "Setting for include_sharedlib: %{include_sharedlib}" -./configure --enable-unicode=ucs4 %{sharedlib} %{ipv6} %{pymalloc} --prefix=%{__prefix} -make - -########## -# INSTALL -########## -%install -# set the install path -echo '[install_scripts]' >setup.cfg -echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg - -[ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload -make prefix=$RPM_BUILD_ROOT%{__prefix} install - -# REPLACE PATH IN PYDOC -if [ ! -z "%{binsuffix}" ] -then - ( - cd $RPM_BUILD_ROOT%{__prefix}/bin - mv pydoc pydoc.old - sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ - pydoc.old >pydoc - chmod 755 pydoc - rm -f pydoc.old - ) -fi - -# add the binsuffix -if [ ! -z "%{binsuffix}" ] -then - rm -f $RPM_BUILD_ROOT%{__prefix}/bin/python[0-9a-zA-Z]* - ( cd $RPM_BUILD_ROOT%{__prefix}/bin; - for file in *; do mv "$file" "$file"%{binsuffix}; done ) - ( cd $RPM_BUILD_ROOT%{_mandir}/man1; mv python.1 python%{binsuffix}.1 ) -fi - -######## -# Tools -echo '#!%{__prefix}/bin/env python%{binsuffix}' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'import os, sys' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'os.execvp("%{__prefix}/bin/python%{binsuffix}", ["%{__prefix}/bin/python%{binsuffix}", "%{__prefix}/lib/python%{libvers}/idlelib/idle.py"] + sys.argv[1:])' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'print "Failed to exec Idle"' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'sys.exit(1)' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} -cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} - -# MAKE FILE LISTS -rm -f mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers} -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/python%{libvers}/config$' -e '_tkinter.so$' >mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f -o -type l | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/bin/2to3%{binsuffix}$' | - grep -v -e '/bin/pydoc%{binsuffix}$' | - grep -v -e '/bin/smtpd.py%{binsuffix}$' | - grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files - -rm -f tools.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ - "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files -echo "%{__prefix}"/bin/2to3%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/pydoc%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/smtpd.py%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files - -###### -# Docs -%if %{include_docs} -mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} -( - cd "$RPM_BUILD_ROOT"%{config_htmldir} - bunzip2 < %{SOURCE1} | tar x -) -%endif - -# fix the #! line in installed files -find "$RPM_BUILD_ROOT" -type f -print0 | - xargs -0 grep -l /usr/local/bin/python | while read file -do - FIXFILE="$file" - sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ - "$FIXFILE" >/tmp/fix-python-path.$$ - cat /tmp/fix-python-path.$$ >"$FIXFILE" - rm -f /tmp/fix-python-path.$$ -done - -# check to see if there are any straggling #! lines -find "$RPM_BUILD_ROOT" -type f | xargs egrep -n '^#! */usr/local/bin/python' \ - | grep ':1:#!' >/tmp/python-rpm-files.$$ || true -if [ -s /tmp/python-rpm-files.$$ ] -then - echo '*****************************************************' - cat /tmp/python-rpm-files.$$ - cat <<@EOF - ***************************************************** - There are still files referencing /usr/local/bin/python in the - install directory. They are listed above. Please fix the .spec - file and try again. If you are an end-user, you probably want - to report this to jafo-rpms at tummy.com as well. - ***************************************************** - at EOF - rm -f /tmp/python-rpm-files.$$ - exit 1 -fi -rm -f /tmp/python-rpm-files.$$ - -######## -# CLEAN -######## -%clean -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT -rm -f mainpkg.files tools.files - -######## -# FILES -######## -%files -f mainpkg.files -%defattr(-,root,root) -%doc Misc/README Misc/cheatsheet Misc/Porting -%doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS -%{_mandir}/man1/python%{binsuffix}.1* - -%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} -%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ -%if %{include_sharedlib} -%{__prefix}/%{libdirname}/libpython* -%endif - -%files devel -%defattr(-,root,root) -%{__prefix}/include/python%{libvers}/*.h -%{__prefix}/%{libdirname}/python%{libvers}/config - -%files -f tools.files tools -%defattr(-,root,root) - -%if %{include_tkinter} -%files tkinter -%defattr(-,root,root) -%{__prefix}/%{libdirname}/python%{libvers}/tkinter -%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* -%endif - -%if %{include_docs} -%files docs -%defattr(-,root,root) -%{config_htmldir}/* -%endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:57:45 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:57:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150218135734.25193.19146@psf.io> https://hg.python.org/cpython/rev/477d217ba4e8 changeset: 94680:477d217ba4e8 parent: 94673:6e3e252cf047 parent: 94679:2c033f80affa user: Benjamin Peterson date: Wed Feb 18 08:55:59 2015 -0500 summary: merge 3.4 files: Misc/README | 1 - Misc/RPM/README | 33 -- Misc/RPM/python-3.5.spec | 389 --------------------------- 3 files changed, 0 insertions(+), 423 deletions(-) diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -21,7 +21,6 @@ README.AIX Information about using Python on AIX README.coverity Information about running Coverity's Prevent on Python README.valgrind Information for Valgrind users, see valgrind-python.supp -RPM (Old) tools to build RPMs SpecialBuilds.txt Describes extra symbols you can set for debug builds svnmap.txt Map of old SVN revs and branches to hg changeset ids valgrind-python.supp Valgrind suppression file, see README.valgrind diff --git a/Misc/RPM/README b/Misc/RPM/README deleted file mode 100644 --- a/Misc/RPM/README +++ /dev/null @@ -1,33 +0,0 @@ -This directory contains support file used to build RPM releases of -Python. Its contents are maintained by Sean Reifschneider -. - -If you wish to build RPMs from the base Python release tar-file, note -that you will have to download the -"doc//html-.tar.bz2" -file from python.org and place it into your "SOURCES" directory for -the build to complete. This is the same directory that you place the -Python-2.3.1 release tar-file in. You can then use the ".spec" file in -this directory to build RPMs. - -You may also wish to pursue RPMs provided by distribution makers to see if -they have one suitable for your uses. If, for example, you just want a -slightly newer version of Python than what the distro provides, you could -pick up the closest SRPM your distro provides, and then modify it to -the newer version, and build that. It may be as simple as just changing -the "version" information in the spec file (or it may require fixing -patches). - -NOTE: I am *NOT* recommending just using the binary RPM, and never do an -install with "--force" or "--nodeps". - -Also worth pursuing may be newer versions provided by similar distros. For -example, a Python 3 SRPM from Fedora may be a good baseline to try building -on CentOS. - -Many newer SRPMs won't install on older distros because of format changes. -You can manually extract these SRPMS with: - - mkdir foo - cd foo - rpm2cpio <../python3-*.src.rpm | cpio -ivd diff --git a/Misc/RPM/python-3.5.spec b/Misc/RPM/python-3.5.spec deleted file mode 100644 --- a/Misc/RPM/python-3.5.spec +++ /dev/null @@ -1,389 +0,0 @@ -########################## -# User-modifiable configs -########################## - -# Is the resulting package and the installed binary named "python" or -# "python2"? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_binsuffix none -%define config_binsuffix 2.6 - -# Build tkinter? "auto" enables it if /usr/bin/wish exists. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_tkinter no -%define config_tkinter yes -%define config_tkinter auto - -# Use pymalloc? The last line (commented or not) determines wether -# pymalloc is used. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_pymalloc no -%define config_pymalloc yes - -# Enable IPV6? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_ipv6 yes -%define config_ipv6 no - -# Build shared libraries or .a library? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_sharedlib no -%define config_sharedlib yes - -# Location of the HTML directory. -%define config_htmldir /var/www/html/python - -################################# -# End of user-modifiable configs -################################# - -%define name python -#--start constants-- -%define version 3.5.0a1 -%define libvers 3.5 -#--end constants-- -%define release 1pydotorg -%define __prefix /usr - -# kludge to get around rpm define weirdness -%define ipv6 %(if [ "%{config_ipv6}" = yes ]; then echo --enable-ipv6; else echo --disable-ipv6; fi) -%define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) -%define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) -%define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) -%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) -%define sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo --enable-shared; else echo ; fi) -%define include_sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo 1; else echo 0; fi) - -# detect if documentation is available -%define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) - -Summary: An interpreted, interactive, object-oriented programming language. -Name: %{name}%{binsuffix} -Version: %{version} -Release: %{release} -License: PSF -Group: Development/Languages -Source: Python-%{version}.tar.bz2 -%if %{include_docs} -Source1: html-%{version}.tar.bz2 -%endif -BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildPrereq: expat-devel -BuildPrereq: db4-devel -BuildPrereq: gdbm-devel -BuildPrereq: sqlite-devel -Prefix: %{__prefix} -Packager: Sean Reifschneider - -%description -Python is an interpreted, interactive, object-oriented programming -language. It incorporates modules, exceptions, dynamic typing, very high -level dynamic data types, and classes. Python combines remarkable power -with very clear syntax. It has interfaces to many system calls and -libraries, as well as to various window systems, and is extensible in C or -C++. It is also usable as an extension language for applications that need -a programmable interface. Finally, Python is portable: it runs on many -brands of UNIX, on PCs under Windows, MS-DOS, and on the Mac. - -%package devel -Summary: The libraries and header files needed for Python extension development. -Prereq: python%{binsuffix} = %{PACKAGE_VERSION} -Group: Development/Libraries - -%description devel -The Python programming language's interpreter can be extended with -dynamically loaded extensions and can be embedded in other programs. -This package contains the header files and libraries needed to do -these types of tasks. - -Install python-devel if you want to develop Python extensions. The -python package will also need to be installed. You'll probably also -want to install the python-docs package, which contains Python -documentation. - -%if %{include_tkinter} -%package tkinter -Summary: A graphical user interface for the Python scripting language. -Group: Development/Languages -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tkinter -The Tkinter (Tk interface) program is an graphical user interface for -the Python scripting language. - -You should install the tkinter package if you'd like to use a graphical -user interface for Python programming. -%endif - -%package tools -Summary: A collection of development tools included with Python. -Group: Development/Tools -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tools -The Python package includes several development tools that are used -to build python programs. This package contains a selection of those -tools, including the IDLE Python IDE. - -Install python-tools if you want to use these tools to develop -Python programs. You will also need to install the python and -tkinter packages. - -%if %{include_docs} -%package docs -Summary: Python-related documentation. -Group: Development/Documentation - -%description docs -Documentation relating to the Python programming language in HTML and info -formats. -%endif - -%changelog -* Mon Dec 20 2004 Sean Reifschneider [2.4-2pydotorg] -- Changing the idle wrapper so that it passes arguments to idle. - -* Tue Oct 19 2004 Sean Reifschneider [2.4b1-1pydotorg] -- Updating to 2.4. - -* Thu Jul 22 2004 Sean Reifschneider [2.3.4-3pydotorg] -- Paul Tiemann fixes for %{prefix}. -- Adding permission changes for directory as suggested by reimeika.ca -- Adding code to detect when it should be using lib64. -- Adding a define for the location of /var/www/html for docs. - -* Thu May 27 2004 Sean Reifschneider [2.3.4-2pydotorg] -- Including changes from Ian Holsman to build under Red Hat 7.3. -- Fixing some problems with the /usr/local path change. - -* Sat Mar 27 2004 Sean Reifschneider [2.3.2-3pydotorg] -- Being more agressive about finding the paths to fix for - #!/usr/local/bin/python. - -* Sat Feb 07 2004 Sean Reifschneider [2.3.3-2pydotorg] -- Adding code to remove "#!/usr/local/bin/python" from particular files and - causing the RPM build to terminate if there are any unexpected files - which have that line in them. - -* Mon Oct 13 2003 Sean Reifschneider [2.3.2-1pydotorg] -- Adding code to detect wether documentation is available to build. - -* Fri Sep 19 2003 Sean Reifschneider [2.3.1-1pydotorg] -- Updating to the 2.3.1 release. - -* Mon Feb 24 2003 Sean Reifschneider [2.3b1-1pydotorg] -- Updating to 2.3b1 release. - -* Mon Feb 17 2003 Sean Reifschneider [2.3a1-1] -- Updating to 2.3 release. - -* Sun Dec 23 2001 Sean Reifschneider -[Release 2.2-2] -- Added -docs package. -- Added "auto" config_tkinter setting which only enables tk if - /usr/bin/wish exists. - -* Sat Dec 22 2001 Sean Reifschneider -[Release 2.2-1] -- Updated to 2.2. -- Changed the extension to "2" from "2.2". - -* Tue Nov 18 2001 Sean Reifschneider -[Release 2.2c1-1] -- Updated to 2.2c1. - -* Thu Nov 1 2001 Sean Reifschneider -[Release 2.2b1-3] -- Changed the way the sed for fixing the #! in pydoc works. - -* Wed Oct 24 2001 Sean Reifschneider -[Release 2.2b1-2] -- Fixed missing "email" package, thanks to anonymous report on sourceforge. -- Fixed missing "compiler" package. - -* Mon Oct 22 2001 Sean Reifschneider -[Release 2.2b1-1] -- Updated to 2.2b1. - -* Mon Oct 9 2001 Sean Reifschneider -[Release 2.2a4-4] -- otto at balinor.mat.unimi.it mentioned that the license file is missing. - -* Sun Sep 30 2001 Sean Reifschneider -[Release 2.2a4-3] -- Ignacio Vazquez-Abrams pointed out that I had a spruious double-quote in - the spec files. Thanks. - -* Wed Jul 25 2001 Sean Reifschneider -[Release 2.2a1-1] -- Updated to 2.2a1 release. -- Changed idle and pydoc to use binsuffix macro - -####### -# PREP -####### -%prep -%setup -n Python-%{version} - -######## -# BUILD -######## -%build -echo "Setting for ipv6: %{ipv6}" -echo "Setting for pymalloc: %{pymalloc}" -echo "Setting for binsuffix: %{binsuffix}" -echo "Setting for include_tkinter: %{include_tkinter}" -echo "Setting for libdirname: %{libdirname}" -echo "Setting for sharedlib: %{sharedlib}" -echo "Setting for include_sharedlib: %{include_sharedlib}" -./configure --enable-unicode=ucs4 %{sharedlib} %{ipv6} %{pymalloc} --prefix=%{__prefix} -make - -########## -# INSTALL -########## -%install -# set the install path -echo '[install_scripts]' >setup.cfg -echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg - -[ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload -make prefix=$RPM_BUILD_ROOT%{__prefix} install - -# REPLACE PATH IN PYDOC -if [ ! -z "%{binsuffix}" ] -then - ( - cd $RPM_BUILD_ROOT%{__prefix}/bin - mv pydoc pydoc.old - sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ - pydoc.old >pydoc - chmod 755 pydoc - rm -f pydoc.old - ) -fi - -# add the binsuffix -if [ ! -z "%{binsuffix}" ] -then - rm -f $RPM_BUILD_ROOT%{__prefix}/bin/python[0-9a-zA-Z]* - ( cd $RPM_BUILD_ROOT%{__prefix}/bin; - for file in *; do mv "$file" "$file"%{binsuffix}; done ) - ( cd $RPM_BUILD_ROOT%{_mandir}/man1; mv python.1 python%{binsuffix}.1 ) -fi - -######## -# Tools -echo '#!%{__prefix}/bin/env python%{binsuffix}' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'import os, sys' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'os.execvp("%{__prefix}/bin/python%{binsuffix}", ["%{__prefix}/bin/python%{binsuffix}", "%{__prefix}/lib/python%{libvers}/idlelib/idle.py"] + sys.argv[1:])' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'print "Failed to exec Idle"' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'sys.exit(1)' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} -cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} - -# MAKE FILE LISTS -rm -f mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers} -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/python%{libvers}/config$' -e '_tkinter.so$' >mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f -o -type l | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/bin/2to3%{binsuffix}$' | - grep -v -e '/bin/pydoc%{binsuffix}$' | - grep -v -e '/bin/smtpd.py%{binsuffix}$' | - grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files - -rm -f tools.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ - "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files -echo "%{__prefix}"/bin/2to3%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/pydoc%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/smtpd.py%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files - -###### -# Docs -%if %{include_docs} -mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} -( - cd "$RPM_BUILD_ROOT"%{config_htmldir} - bunzip2 < %{SOURCE1} | tar x -) -%endif - -# fix the #! line in installed files -find "$RPM_BUILD_ROOT" -type f -print0 | - xargs -0 grep -l /usr/local/bin/python | while read file -do - FIXFILE="$file" - sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ - "$FIXFILE" >/tmp/fix-python-path.$$ - cat /tmp/fix-python-path.$$ >"$FIXFILE" - rm -f /tmp/fix-python-path.$$ -done - -# check to see if there are any straggling #! lines -find "$RPM_BUILD_ROOT" -type f | xargs egrep -n '^#! */usr/local/bin/python' \ - | grep ':1:#!' >/tmp/python-rpm-files.$$ || true -if [ -s /tmp/python-rpm-files.$$ ] -then - echo '*****************************************************' - cat /tmp/python-rpm-files.$$ - cat <<@EOF - ***************************************************** - There are still files referencing /usr/local/bin/python in the - install directory. They are listed above. Please fix the .spec - file and try again. If you are an end-user, you probably want - to report this to jafo-rpms at tummy.com as well. - ***************************************************** - at EOF - rm -f /tmp/python-rpm-files.$$ - exit 1 -fi -rm -f /tmp/python-rpm-files.$$ - -######## -# CLEAN -######## -%clean -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT -rm -f mainpkg.files tools.files - -######## -# FILES -######## -%files -f mainpkg.files -%defattr(-,root,root) -%doc Misc/README Misc/cheatsheet Misc/Porting -%doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS -%{_mandir}/man1/python%{binsuffix}.1* - -%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} -%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ -%if %{include_sharedlib} -%{__prefix}/%{libdirname}/libpython* -%endif - -%files devel -%defattr(-,root,root) -%{__prefix}/include/python%{libvers}/*.h -%{__prefix}/%{libdirname}/python%{libvers}/config - -%files -f tools.files tools -%defattr(-,root,root) - -%if %{include_tkinter} -%files tkinter -%defattr(-,root,root) -%{__prefix}/%{libdirname}/python%{libvers}/tkinter -%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* -%endif - -%if %{include_docs} -%files docs -%defattr(-,root,root) -%{config_htmldir}/* -%endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 18 14:59:22 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 18 Feb 2015 13:59:22 +0000 Subject: [Python-checkins] =?utf-8?q?release=3A_the_RPM_spec_file_is_gone_?= =?utf-8?q?now=2C_so_don=27t_update_it?= Message-ID: <20150218135908.12748.23804@psf.io> https://hg.python.org/release/rev/b7529318e7cc changeset: 93:b7529318e7cc user: Benjamin Peterson date: Wed Feb 18 08:59:06 2015 -0500 summary: the RPM spec file is gone now, so don't update it files: release.py | 17 ----------------- 1 files changed, 0 insertions(+), 17 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -136,23 +136,6 @@ def bump(tag): print('Bumping version to %s' % tag) - wanted_file = 'Misc/RPM/python-%s.spec' % tag.basic_version - print('Updating %s' % wanted_file, end=' ') - if not os.path.exists(wanted_file): - specs = os.listdir('Misc/RPM/') - for file in specs: - if file.startswith('python-'): - break - full_path = os.path.join('Misc/RPM/', file) - print('\nrenaming %s to %s' % (full_path, wanted_file)) - run_cmd(['hg', 'rename', '--force', full_path, wanted_file]) - print('File was renamed; please commit') - run_cmd(['hg', 'commit']) - new = '%define version ' + tag.text + \ - '\n%define libvers ' + tag.basic_version - constant_replace(wanted_file, new, '#', '') - print('done') - tweak_patchlevel(tag) print('Updating Lib/idlelib/idlever.py...', end=' ') -- Repository URL: https://hg.python.org/release From python-checkins at python.org Thu Feb 19 03:02:38 2015 From: python-checkins at python.org (steve.dower) Date: Thu, 19 Feb 2015 02:02:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2323482=3A_sqlite3?= =?utf-8?q?=5Fd=2Edll_is_not_included_in_installer?= Message-ID: <20150219020238.10180.88145@psf.io> https://hg.python.org/cpython/rev/70a55b2dee71 changeset: 94685:70a55b2dee71 parent: 94683:b2d238adf802 user: Steve Dower date: Wed Feb 18 18:02:22 2015 -0800 summary: Closes #23482: sqlite3_d.dll is not included in installer files: Tools/msi/lib/lib_files.wxs | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -46,6 +46,13 @@ + + + + + + + -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Thu Feb 19 23:04:21 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 19 Feb 2015 23:04:21 +0100 Subject: [Python-checkins] Daily reference leaks (b2d238adf802): sum=0 Message-ID: results for b2d238adf802 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogqqd4Ku', '-x'] From python-checkins at python.org Thu Feb 19 23:58:24 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 19 Feb 2015 22:58:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjM0ODEp?= Message-ID: <20150219225824.99222.16186@psf.io> https://hg.python.org/cpython/rev/041a27298cf3 changeset: 94688:041a27298cf3 parent: 94685:70a55b2dee71 parent: 94686:c509e6f18d7d user: Benjamin Peterson date: Thu Feb 19 17:58:19 2015 -0500 summary: merge 3.4 (#23481) files: Lib/ssl.py | 6 ++---- Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -164,14 +164,12 @@ # * Prefer any AES-GCM over any AES-CBC for better performance and security # * Then Use HIGH cipher suites as a fallback # * Then Use 3DES as fallback which is secure but slow -# * Finally use RC4 as a fallback which is problematic but needed for -# compatibility some times. # * Disable NULL authentication, NULL encryption, and MD5 MACs for security # reasons _DEFAULT_CIPHERS = ( 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' - 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' - 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' + 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' + '!eNULL:!MD5' ) # Restricted and more secure ciphers for the server side diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #23481: Remove RC4 from the SSL module's default cipher list. + - Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty docstrings. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 19 23:58:24 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 19 Feb 2015 22:58:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_remove_rc4_fro?= =?utf-8?q?m_the_default_client_ciphers_=28closes_=2323481=29?= Message-ID: <20150219225824.29688.64317@psf.io> https://hg.python.org/cpython/rev/c509e6f18d7d changeset: 94686:c509e6f18d7d branch: 3.4 parent: 94681:78145e6ffb40 user: Benjamin Peterson date: Thu Feb 19 17:57:08 2015 -0500 summary: remove rc4 from the default client ciphers (closes #23481) files: Lib/ssl.py | 6 ++---- Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -170,14 +170,12 @@ # * Prefer any AES-GCM over any AES-CBC for better performance and security # * Then Use HIGH cipher suites as a fallback # * Then Use 3DES as fallback which is secure but slow -# * Finally use RC4 as a fallback which is problematic but needed for -# compatibility some times. # * Disable NULL authentication, NULL encryption, and MD5 MACs for security # reasons _DEFAULT_CIPHERS = ( 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' - 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' - 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' + 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' + '!eNULL:!MD5' ) # Restricted and more secure ciphers for the server side diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #23481: Remove RC4 from the SSL module's default cipher list. + - Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty docstrings. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 19 23:58:24 2015 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 19 Feb 2015 22:58:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_rc4_fro?= =?utf-8?q?m_the_default_client_ciphers_=28closes_=2323481=29?= Message-ID: <20150219225824.29670.71275@psf.io> https://hg.python.org/cpython/rev/3596081cfb55 changeset: 94687:3596081cfb55 branch: 2.7 parent: 94684:ba2b0e6a888f user: Benjamin Peterson date: Thu Feb 19 17:57:08 2015 -0500 summary: remove rc4 from the default client ciphers (closes #23481) files: Lib/ssl.py | 6 ++---- Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -157,14 +157,12 @@ # * Prefer any AES-GCM over any AES-CBC for better performance and security # * Then Use HIGH cipher suites as a fallback # * Then Use 3DES as fallback which is secure but slow -# * Finally use RC4 as a fallback which is problematic but needed for -# compatibility some times. # * Disable NULL authentication, NULL encryption, and MD5 MACs for security # reasons _DEFAULT_CIPHERS = ( 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' - 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' - 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' + 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' + '!eNULL:!MD5' ) # Restricted and more secure ciphers for the server side diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,8 @@ - Issue #22885: Fixed arbitrary code execution vulnerability in the dumbdbm module. Original patch by Claudiu Popa. +- Issue #23481: Remove RC4 from the SSL module's default cipher list. + - Issue #21849: Fixed xmlrpclib serialization of non-ASCII unicode strings in the multiprocessing module. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 05:16:11 2015 From: python-checkins at python.org (zach.ware) Date: Fri, 20 Feb 2015 04:16:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_a_typo_poi?= =?utf-8?q?nted_out_on_docs=40?= Message-ID: <20150220041611.29680.52090@psf.io> https://hg.python.org/cpython/rev/c6dd9ada7102 changeset: 94689:c6dd9ada7102 branch: 3.4 parent: 94686:c509e6f18d7d user: Zachary Ware date: Thu Feb 19 22:15:36 2015 -0600 summary: Fix a typo pointed out on docs@ files: Doc/reference/expressions.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1067,7 +1067,7 @@ * Numbers are compared arithmetically. * The values :const:`float('NaN')` and :const:`Decimal('NaN')` are special. - The are identical to themselves, ``x is x`` but are not equal to themselves, + They are identical to themselves, ``x is x`` but are not equal to themselves, ``x != x``. Additionally, comparing any value to a not-a-number value will return ``False``. For example, both ``3 < float('NaN')`` and ``float('NaN') < 3`` will return ``False``. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 05:16:12 2015 From: python-checkins at python.org (zach.ware) Date: Fri, 20 Feb 2015 04:16:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4?= Message-ID: <20150220041611.116401.91676@psf.io> https://hg.python.org/cpython/rev/7b63e7bc5b3d changeset: 94690:7b63e7bc5b3d parent: 94688:041a27298cf3 parent: 94689:c6dd9ada7102 user: Zachary Ware date: Thu Feb 19 22:15:54 2015 -0600 summary: Merge with 3.4 files: Doc/reference/expressions.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1075,7 +1075,7 @@ * Numbers are compared arithmetically. * The values :const:`float('NaN')` and :const:`Decimal('NaN')` are special. - The are identical to themselves, ``x is x`` but are not equal to themselves, + They are identical to themselves, ``x is x`` but are not equal to themselves, ``x != x``. Additionally, comparing any value to a not-a-number value will return ``False``. For example, both ``3 < float('NaN')`` and ``float('NaN') < 3`` will return ``False``. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 05:31:47 2015 From: python-checkins at python.org (zach.ware) Date: Fri, 20 Feb 2015 04:31:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_typo_point?= =?utf-8?q?ed_out_on_docs=40_by_Yaniv_Sayeh?= Message-ID: <20150220043147.10176.1251@psf.io> https://hg.python.org/cpython/rev/a40481bbb62b changeset: 94691:a40481bbb62b branch: 2.7 parent: 94687:3596081cfb55 user: Zachary Ware date: Thu Feb 19 22:28:36 2015 -0600 summary: Fix typo pointed out on docs@ by Yaniv Sayeh files: Doc/library/copy_reg.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/copy_reg.rst b/Doc/library/copy_reg.rst --- a/Doc/library/copy_reg.rst +++ b/Doc/library/copy_reg.rst @@ -14,7 +14,7 @@ module: cPickle module: copy -The :mod:`copy_reg` module offers a way to define fuctions used while pickling +The :mod:`copy_reg` module offers a way to define functions used while pickling specific objects. The :mod:`pickle`, :mod:`cPickle`, and :mod:`copy` modules use those functions when pickling/copying those objects. The module provides configuration information about object constructors which are not classes. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 05:32:13 2015 From: python-checkins at python.org (zach.ware) Date: Fri, 20 Feb 2015 04:32:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Null_merge_with_3=2E4?= Message-ID: <20150220043148.109522.6913@psf.io> https://hg.python.org/cpython/rev/d9a246a2a1c8 changeset: 94693:d9a246a2a1c8 parent: 94690:7b63e7bc5b3d parent: 94692:428cc8aa0843 user: Zachary Ware date: Thu Feb 19 22:31:29 2015 -0600 summary: Null merge with 3.4 (Typo was already fixed on this branch.) files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 05:32:13 2015 From: python-checkins at python.org (zach.ware) Date: Fri, 20 Feb 2015 04:32:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_typo_point?= =?utf-8?q?ed_out_on_docs=40_by_Yaniv_Sayeh?= Message-ID: <20150220043148.109587.66611@psf.io> https://hg.python.org/cpython/rev/428cc8aa0843 changeset: 94692:428cc8aa0843 branch: 3.4 parent: 94689:c6dd9ada7102 user: Zachary Ware date: Thu Feb 19 22:30:15 2015 -0600 summary: Fix typo pointed out on docs@ by Yaniv Sayeh files: Doc/library/copyreg.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -9,7 +9,7 @@ module: pickle module: copy -The :mod:`copyreg` module offers a way to define fuctions used while pickling +The :mod:`copyreg` module offers a way to define functions used while pickling specific objects. The :mod:`pickle` and :mod:`copy` modules use those functions when pickling/copying those objects. The module provides configuration information about object constructors which are not classes. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 08:44:10 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 20 Feb 2015 07:44:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323439=3A_Add_missing_entries_to_http=2Eclient?= =?utf-8?b?Ll9fYWxsX18u?= Message-ID: <20150220074410.4016.53579@psf.io> https://hg.python.org/cpython/rev/95533c9edaaf changeset: 94695:95533c9edaaf parent: 94693:d9a246a2a1c8 parent: 94694:21b31f5438ae user: Berker Peksag date: Fri Feb 20 09:45:05 2015 +0200 summary: Issue #23439: Add missing entries to http.client.__all__. Also, document the LineTooLong exception since it can be raised by the members of public API (e.g. http.client.HTTPResponse). Patch by Martin Panter. files: Doc/library/http.client.rst | 6 ++++++ Lib/http/client.py | 4 +++- Lib/test/test_httplib.py | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 1 deletions(-) diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -169,6 +169,12 @@ status code that we don't understand. +.. exception:: LineTooLong + + A subclass of :exc:`HTTPException`. Raised if an excessively long line + is received in the HTTP protocol from the server. + + The constants defined in this module are: .. data:: HTTP_PORT diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -75,12 +75,14 @@ import collections from urllib.parse import urlsplit +# HTTPMessage, parse_headers(), and the HTTP status code constants are +# intentionally omitted for simplicity __all__ = ["HTTPResponse", "HTTPConnection", "HTTPException", "NotConnected", "UnknownProtocol", "UnknownTransferEncoding", "UnimplementedFileMode", "IncompleteRead", "InvalidURL", "ImproperConnectionState", "CannotSendRequest", "CannotSendHeader", "ResponseNotReady", - "BadStatusLine", "error", "responses"] + "BadStatusLine", "LineTooLong", "error", "responses"] HTTP_PORT = 80 HTTPS_PORT = 443 diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -920,7 +920,22 @@ self.remainder = b"".join(data) raise + class OfflineTest(TestCase): + def test_all(self): + # Documented objects defined in the module should be in __all__ + expected = {"responses"} # White-list documented dict() object + # HTTPMessage, parse_headers(), and the HTTP status code constants are + # intentionally omitted for simplicity + blacklist = {"HTTPMessage", "parse_headers"} + for name in dir(client): + if name in blacklist: + continue + module_object = getattr(client, name) + if getattr(module_object, "__module__", None) == "http.client": + expected.add(name) + self.assertCountEqual(client.__all__, expected) + def test_responses(self): self.assertEqual(client.responses[client.NOT_FOUND], "Not Found") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 08:44:11 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 20 Feb 2015 07:44:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDM5?= =?utf-8?b?OiBBZGQgbWlzc2luZyBlbnRyaWVzIHRvIGh0dHAuY2xpZW50Ll9fYWxsX18u?= Message-ID: <20150220074410.3887.79137@psf.io> https://hg.python.org/cpython/rev/21b31f5438ae changeset: 94694:21b31f5438ae branch: 3.4 parent: 94692:428cc8aa0843 user: Berker Peksag date: Fri Feb 20 09:39:38 2015 +0200 summary: Issue #23439: Add missing entries to http.client.__all__. Also, document the LineTooLong exception since it can be raised by the members of public API (e.g. http.client.HTTPResponse). Patch by Martin Panter. files: Doc/library/http.client.rst | 6 ++++++ Lib/http/client.py | 4 +++- Lib/test/test_httplib.py | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 1 deletions(-) diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -169,6 +169,12 @@ status code that we don't understand. +.. exception:: LineTooLong + + A subclass of :exc:`HTTPException`. Raised if an excessively long line + is received in the HTTP protocol from the server. + + The constants defined in this module are: .. data:: HTTP_PORT diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -74,12 +74,14 @@ import collections from urllib.parse import urlsplit +# HTTPMessage, parse_headers(), and the HTTP status code constants are +# intentionally omitted for simplicity __all__ = ["HTTPResponse", "HTTPConnection", "HTTPException", "NotConnected", "UnknownProtocol", "UnknownTransferEncoding", "UnimplementedFileMode", "IncompleteRead", "InvalidURL", "ImproperConnectionState", "CannotSendRequest", "CannotSendHeader", "ResponseNotReady", - "BadStatusLine", "error", "responses"] + "BadStatusLine", "LineTooLong", "error", "responses"] HTTP_PORT = 80 HTTPS_PORT = 443 diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -708,7 +708,22 @@ self.assertTrue(response.closed) self.assertTrue(conn.sock.file_closed) + class OfflineTest(TestCase): + def test_all(self): + # Documented objects defined in the module should be in __all__ + expected = {"responses"} # White-list documented dict() object + # HTTPMessage, parse_headers(), and the HTTP status code constants are + # intentionally omitted for simplicity + blacklist = {"HTTPMessage", "parse_headers"} + for name in dir(client): + if name in blacklist: + continue + module_object = getattr(client, name) + if getattr(module_object, "__module__", None) == "http.client": + expected.add(name) + self.assertCountEqual(client.__all__, expected) + def test_responses(self): self.assertEqual(client.responses[client.NOT_FOUND], "Not Found") -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Fri Feb 20 09:14:38 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 20 Feb 2015 09:14:38 +0100 Subject: [Python-checkins] Daily reference leaks (041a27298cf3): sum=3 Message-ID: results for 041a27298cf3 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2A88wA', '-x'] From python-checkins at python.org Fri Feb 20 09:50:10 2015 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 20 Feb 2015 08:50:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Improve_struct_cache_local?= =?utf-8?q?ity_by_bring_commonly_accessed_fields_close_together=2E?= Message-ID: <20150220085009.10184.75445@psf.io> https://hg.python.org/cpython/rev/0ba4bcc0a7a6 changeset: 94696:0ba4bcc0a7a6 user: Raymond Hettinger date: Fri Feb 20 00:50:04 2015 -0800 summary: Improve struct cache locality by bring commonly accessed fields close together. files: Modules/_randommodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -78,8 +78,8 @@ typedef struct { PyObject_HEAD + int index; unsigned long state[N]; - int index; } RandomObject; static PyTypeObject Random_Type; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 11:09:36 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 20 Feb 2015 10:09:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxNTQ4?= =?utf-8?q?=3A_Fix_pydoc=2Esynopsis=28=29_and_pydoc=2Eapropos=28=29_on_mod?= =?utf-8?q?ules_with_empty?= Message-ID: <20150220100936.109583.65792@psf.io> https://hg.python.org/cpython/rev/43641e03692a changeset: 94697:43641e03692a branch: 2.7 parent: 94691:a40481bbb62b user: Berker Peksag date: Fri Feb 20 12:10:33 2015 +0200 summary: Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty docstrings. Initial patch by Yuyang Guo. files: Lib/pydoc.py | 4 ++-- Lib/test/test_pydoc.py | 29 +++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -255,7 +255,7 @@ if info and 'b' in info[2]: # binary modules have to be imported try: module = imp.load_module('__temp__', file, filename, info[1:]) except: return None - result = (module.__doc__ or '').splitlines()[0] + result = module.__doc__.splitlines()[0] if module.__doc__ else None del sys.modules['__temp__'] else: # text modules can be directly examined result = source_synopsis(file) @@ -2020,7 +2020,7 @@ path = None else: module = loader.load_module(modname) - desc = (module.__doc__ or '').splitlines()[0] + desc = module.__doc__.splitlines()[0] if module.__doc__ else '' path = getattr(module,'__file__',None) if find(lower(modname + ' - ' + desc), key) >= 0: callback(path, modname, desc) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -3,6 +3,7 @@ import difflib import __builtin__ import re +import py_compile import pydoc import contextlib import inspect @@ -382,6 +383,34 @@ self.assertEqual(stripid(""), "") + def test_synopsis(self): + with test.test_support.temp_cwd() as test_dir: + init_path = os.path.join(test_dir, 'dt.py') + with open(init_path, 'w') as fobj: + fobj.write('''\ +""" +my doc + +second line +""" +foo = 1 +''') + py_compile.compile(init_path) + synopsis = pydoc.synopsis(init_path, {}) + self.assertEqual(synopsis, 'my doc') + + def test_synopsis_sourceless_empty_doc(self): + with test.test_support.temp_cwd() as test_dir: + init_path = os.path.join(test_dir, 'foomod42.py') + cached_path = os.path.join(test_dir, 'foomod42.pyc') + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + py_compile.compile(init_path) + synopsis = pydoc.synopsis(init_path, {}) + self.assertIsNone(synopsis) + synopsis_cached = pydoc.synopsis(cached_path, {}) + self.assertIsNone(synopsis_cached) + class PydocImportTest(PydocBaseTest): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty + docstrings. Initial patch by Yuyang Guo. + - Issue #22885: Fixed arbitrary code execution vulnerability in the dumbdbm module. Original patch by Claudiu Popa. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 11:57:55 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 10:57:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Regenerated_Argument_Clini?= =?utf-8?q?c_checksums=2E?= Message-ID: <20150220105754.109567.63319@psf.io> https://hg.python.org/cpython/rev/da4eeba6ba20 changeset: 94698:da4eeba6ba20 parent: 94696:0ba4bcc0a7a6 user: Serhiy Storchaka date: Fri Feb 20 12:46:11 2015 +0200 summary: Regenerated Argument Clinic checksums. files: Modules/_lzmamodule.c | 2 +- Modules/clinic/_lzmamodule.c.h | 4 ++-- Modules/clinic/cmathmodule.c.h | 2 +- Modules/cmathmodule.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -1087,7 +1087,7 @@ static PyObject * _lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data, Py_ssize_t max_length) -/*[clinic end generated code: output=1532a5bb23629001 input=262e4e217f49039b]*/ +/*[clinic end generated code: output=1532a5bb23629001 input=f2bb902cc1caf203]*/ { PyObject *result = NULL; diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/clinic/_lzmamodule.c.h --- a/Modules/clinic/_lzmamodule.c.h +++ b/Modules/clinic/_lzmamodule.c.h @@ -65,7 +65,7 @@ "decompress($self, /, data, max_length=-1)\n" "--\n" "\n" -"Decompresses *data*, returning uncompressed data as bytes.\n" +"Decompress *data*, returning uncompressed data as bytes.\n" "\n" "If *max_length* is nonnegative, returns at most *max_length* bytes of\n" "decompressed data. If this limit is reached and further output can be\n" @@ -251,4 +251,4 @@ return return_value; } -/*[clinic end generated code: output=d17fac38b09626d8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=dc42b73890609369 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/cmathmodule.c.h b/Modules/clinic/cmathmodule.c.h --- a/Modules/clinic/cmathmodule.c.h +++ b/Modules/clinic/cmathmodule.c.h @@ -848,4 +848,4 @@ exit: return return_value; } -/*[clinic end generated code: output=4407f898ae07c83d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9b6d81711e4e3c4b input=a9049054013a1b77]*/ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -212,7 +212,7 @@ static Py_complex cmath_acosh_impl(PyModuleDef *module, Py_complex z) -/*[clinic end generated code: output=c23c776429def981 input=bc016412080bb3e9]*/ +/*[clinic end generated code: output=c23c776429def981 input=3f61bee7d703e53c]*/ { Py_complex s1, s2, r; @@ -267,7 +267,7 @@ static Py_complex cmath_asinh_impl(PyModuleDef *module, Py_complex z) -/*[clinic end generated code: output=0c6664823c7b1b35 input=5a21fa0242928c9b]*/ +/*[clinic end generated code: output=0c6664823c7b1b35 input=5c09448fcfc89a79]*/ { Py_complex s1, s2, r; @@ -358,7 +358,7 @@ static Py_complex cmath_atanh_impl(PyModuleDef *module, Py_complex z) -/*[clinic end generated code: output=279e0b9fefc8da7c input=df19cdc9f9d431c9]*/ +/*[clinic end generated code: output=279e0b9fefc8da7c input=2b3fdb82fb34487b]*/ { Py_complex r; double ay, h; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 13:56:34 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 20 Feb 2015 12:56:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323442=3A_Rename_t?= =?utf-8?q?wo_member_names_to_stay_backward_compatible?= Message-ID: <20150220125634.4018.59518@psf.io> https://hg.python.org/cpython/rev/52d37efaf939 changeset: 94699:52d37efaf939 user: Berker Peksag date: Fri Feb 20 14:57:31 2015 +0200 summary: Issue #23442: Rename two member names to stay backward compatible with the constants in http.client. Initial patch by Demian Brecht. files: Lib/http/__init__.py | 8 +- Lib/test/test_httplib.py | 61 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/Lib/http/__init__.py b/Lib/http/__init__.py --- a/Lib/http/__init__.py +++ b/Lib/http/__init__.py @@ -93,8 +93,8 @@ 'URI is too long') UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type', 'Entity body in unsupported format') - REQUEST_RANGE_NOT_SATISFIABLE = (416, - 'Request Range Not Satisfiable', + REQUESTED_RANGE_NOT_SATISFIABLE = (416, + 'Requested Range Not Satisfiable', 'Cannot satisfy request range') EXPECTATION_FAILED = (417, 'Expectation Failed', 'Expect condition could not be satisfied') @@ -107,8 +107,8 @@ TOO_MANY_REQUESTS = (429, 'Too Many Requests', 'The user has sent too many requests in ' 'a given amount of time ("rate limiting")') - REQUEST_HEADER_FIELD_TOO_LARGE = (431, - 'Request Header Field Too Large', + REQUEST_HEADER_FIELDS_TOO_LARGE = (431, + 'Request Header Fields Too Large', 'The server is unwilling to process the request because its header ' 'fields are too large') diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -939,6 +939,67 @@ def test_responses(self): self.assertEqual(client.responses[client.NOT_FOUND], "Not Found") + def test_client_constants(self): + # Make sure we don't break backward compatibility with 3.4 + expected = [ + 'CONTINUE', + 'SWITCHING_PROTOCOLS', + 'PROCESSING', + 'OK', + 'CREATED', + 'ACCEPTED', + 'NON_AUTHORITATIVE_INFORMATION', + 'NO_CONTENT', + 'RESET_CONTENT', + 'PARTIAL_CONTENT', + 'MULTI_STATUS', + 'IM_USED', + 'MULTIPLE_CHOICES', + 'MOVED_PERMANENTLY', + 'FOUND', + 'SEE_OTHER', + 'NOT_MODIFIED', + 'USE_PROXY', + 'TEMPORARY_REDIRECT', + 'BAD_REQUEST', + 'UNAUTHORIZED', + 'PAYMENT_REQUIRED', + 'FORBIDDEN', + 'NOT_FOUND', + 'METHOD_NOT_ALLOWED', + 'NOT_ACCEPTABLE', + 'PROXY_AUTHENTICATION_REQUIRED', + 'REQUEST_TIMEOUT', + 'CONFLICT', + 'GONE', + 'LENGTH_REQUIRED', + 'PRECONDITION_FAILED', + 'REQUEST_ENTITY_TOO_LARGE', + 'REQUEST_URI_TOO_LONG', + 'UNSUPPORTED_MEDIA_TYPE', + 'REQUESTED_RANGE_NOT_SATISFIABLE', + 'EXPECTATION_FAILED', + 'UNPROCESSABLE_ENTITY', + 'LOCKED', + 'FAILED_DEPENDENCY', + 'UPGRADE_REQUIRED', + 'PRECONDITION_REQUIRED', + 'TOO_MANY_REQUESTS', + 'REQUEST_HEADER_FIELDS_TOO_LARGE', + 'INTERNAL_SERVER_ERROR', + 'NOT_IMPLEMENTED', + 'BAD_GATEWAY', + 'SERVICE_UNAVAILABLE', + 'GATEWAY_TIMEOUT', + 'HTTP_VERSION_NOT_SUPPORTED', + 'INSUFFICIENT_STORAGE', + 'NOT_EXTENDED', + 'NETWORK_AUTHENTICATION_REQUIRED', + ] + for const in expected: + with self.subTest(constant=const): + self.assertTrue(hasattr(client, const)) + class SourceAddressTest(TestCase): def setUp(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 14:51:25 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 20 Feb 2015 13:51:25 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_441=3A_Updates_from_Paul_?= =?utf-8?q?Moore=2E?= Message-ID: <20150220135100.109577.35976@psf.io> https://hg.python.org/peps/rev/6dfeec7203f1 changeset: 5699:6dfeec7203f1 user: Berker Peksag date: Fri Feb 20 15:51:59 2015 +0200 summary: PEP 441: Updates from Paul Moore. files: pep-0441.txt | 265 ++++++++++++++++++++++++++++++-------- 1 files changed, 210 insertions(+), 55 deletions(-) diff --git a/pep-0441.txt b/pep-0441.txt --- a/pep-0441.txt +++ b/pep-0441.txt @@ -2,12 +2,14 @@ Title: Improving Python ZIP Application Support Version: $Revision$ Last-Modified: $Date$ -Author: Daniel Holth +Author: Daniel Holth , + Paul Moore +Discussions-To: https://mail.python.org/pipermail/python-dev/2015-February/138277.html Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 30 March 2013 -Post-History: 30 March 2013, 1 April 2013 +Post-History: 30 March 2013, 1 April 2013, 16 February 2015 Improving Python ZIP Application Support ======================================== @@ -15,116 +17,269 @@ Python has had the ability to execute directories or ZIP-format archives as scripts since version 2.6 [1]_. When invoked with a zip file or directory as its first argument the interpreter adds that -directory to sys.path and executes the __main__ module. These +directory to sys.path and executes the ``__main__`` module. These archives provide a great way to publish software that needs to be distributed as a single file script but is complex enough to need to be written as a collection of modules. -This feature is not as popular as it should be mainly because no one?s -heard of it as it wasn?t promoted as part of Python 2.6 [2]_, but also -because Windows users don?t have a file extension (other than .py) to -associate with the launcher. +This feature is not as popular as it should be mainly because it was +not promoted as part of Python 2.6 [2]_, so that it is relatively +unknown, but also because the Windows installer does not register a +file extension (other than ``.py``) for this format of file, to associate +with the launcher. This PEP proposes to fix these problems by re-publicising the feature, -defining the .pyz and .pyzw extensions as ?Python ZIP Applications? -and ?Windowed Python ZIP Applications?, and providing some simple +defining the ``.pyz`` and ``.pyzw`` extensions as "Python ZIP Applications" +and "Windowed Python ZIP Applications", and providing some simple tooling to manage the format. A New Python ZIP Application Extension ====================================== -The Python 3.4 installer will associate .pyz and .pyzw ?Python ZIP -Applications? with the platform launcher so they can be executed. A -.pyz archive is a console application and a .pyzw archive is a +The terminology "Python Zip Application" will be the formal term used +for a zip-format archive that contains Python code in a form that can +be directly executed by Python (specifically, it must have a +``__main__.py`` file in the root directory of the archive). The +extension ``.pyz`` will be formally associated with such files. + +The Python 3.5 installer will associate ``.pyz`` and ``.pyzw`` "Python +Zip Applications" with the platform launcher so they can be executed. +A ``.pyz`` archive is a console application and a ``.pyzw`` archive is a windowed application, indicating whether the console should appear when running the app. -Why not use .zip or .py? Users expect a .zip file would be opened with -an archive tool, and users expect .py to contain text. Both would be -confusing for this use case. +On Unix, it would be ideal if the ``.pyz`` extension and the name +"Python Zip Application" were registered (in the mime types database?). +However, such an association is out of scope for this PEP. -For UNIX users, .pyz applications should be prefixed with a #! line +Python Zip applications can be prefixed with a ``#!`` line pointing to the correct Python interpreter and an optional explanation:: #!/usr/bin/env python3 - # This is a Python application stored in a ZIP archive, created with - # pyzaa. + # Python application packed with zipapp module (binary contents of archive) +On Unix, this allows the OS to run the file with the correct +interpreter, via the standard "shebang" support. On Windows, the +Python launcher implements shebang support. + +However, it is always possible to execute a ``.pyz`` application by +supplying the filename to the Python interpreter directly. + As background, ZIP archives are defined with a footer containing relative offsets from the end of the file. They remain valid when concatenated to the end of any other file. This feature is completely standard and is how self-extracting ZIP archives and the bdist_wininst installer format work. -Minimal Tooling: The pyzaa Module -================================= +Minimal Tooling: The zipapp Module +================================== -This PEP also proposes including a simple application for working with -these archives: The Python Zip Application Archiver ?pyzaa? (rhymes -with ?huzzah? or ?pizza?). ?pyzaa? can archive these files, compile -bytecode, and can write the __main__ module if it is not present. +This PEP also proposes including a module for working with these +archives. The module will contain functions for working with Python +zip application archives, and a command line interface (via ``python +-m zipapp``) for their creation and manipulation. -Usage ------ +More complete tools for managing Python Zip Applications are +encouraged as 3rd party applications on PyPI. Currently, pyyzer [5]_ +and pex [6]_ are two tools known to exist. -``python -m pyzaa (pack | compile)`` +Module Interface +---------------- -``python -m pyzaa pack [-o path/name] [-m module.submodule:callable] [-c] [-w] -[-p interpreter] directory``:: +The zipapp module will provide the following functions:: - ZIP the contents of directory as directory.pyz or [-w] - directory.pyzw. Adds the executable flag to the archive. + pack(target, directory, interpreter=None, main=None) - ``-c`` compile .pyc files and add them to the archive +Writes an application archive called *target*, containing the +contents of *directory*. If *interpreter* is specified, it will +be written to the start of the archive as a shebang line and the file +will be made executable (if no interpreter is specified, the shebang +line will be omitted). If the directory contains no ``__main__.py`` +file, the function will construct a ``__main__.py`` which calls the +function specified in the *main* argument (which should be in the +form ``'pkg.mod:fn'``). - ``-p interpreter`` include #!interpreter as the first line of the archive +It is an error to specify *main* if the directory contains a +``__main__.py``, or to omit *main* when there is no ``__main__.py`` +(as that will result in an archive which has no main function and so +cannot be executed). - ``-o path/name`` archive is written to path/name.pyz[w] instead of - dirname. The extension is added if not specified. +``get_interpreter(archive)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``-m module.submodule:callable`` __main__.py is written as ?import - module.submodule; module.submodule.callable()? +Returns the interpreter specified in the shebang line of the *archive*. +If there is no shebang, the function returns ``None``. - pyzaa pack will warn if the directory contains C extensions or if - it doesn?t contain __main__.py. +``set_interpreter(archive, new_archive, interpreter=None)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``python -m pyzaa compile arcname.pyz[w]``:: +Modifies the *archive*'s shebang line to contain the specified +interpreter, and writes the updated archive to *new_archive*. If the +*interpreter* is ``None``, removes the shebang line. - The Python files in arcname.pyz[w] are compiled and appended to the - ZIP file. +Command Line Usage +------------------ -A standard ZIP utility or Python?s zipfile module can unpack the -archives. +The zipapp module can be run with the python ``-m`` flag. The command +line interface is as follows:: + + python -m zipapp [options] directory + + Create an archive from the contents of the given directory. By + default, an archive will be created with the same name as the + source directory, with a .pyz extension. + + The following options can be specified: + + -o archive / --output archive + + The destination archive will have the specified name. + + -p interpreter / --python interpreter + + The given interpreter will be written to the shebang line + of the archive. If this option is not given, the archive + will have no shebang line. + + -m pkg.mod:fn / --main pkg.mod:fn + + The source directory must not have a __main__.py file. The + archiver will write a __main__.py file into the target + which calls fn from the module pkg.mod. + +The behaviour of the command line interface matches that of +``zipapp.pack()``. + +As noted, the archives are standard zip files, and so can be unpacked +using any standard ZIP utility or Python's zipfile module. FAQ --- -Q. Are you sure a standard ZIP utility can handle #! at the beginning? +Are you sure a standard ZIP utility can handle ``#!`` at the beginning? + Absolutely. The zipfile specification allows for arbitrary data to + be prepended to a zipfile. This feature is commonly used by + "self-extracting zip" programs. If your archive program can't + handle this, it is a bug in your archive program. -A. Absolutely. If it doesn't, it is a bug in your archive program. +Isn't zipapp just a very thin wrapper over the zipfile module? + Yes. If you prefer to build your own Python zip application + archives using other tools, they will work just as well. The + zipapp module is a convenience, nothing more. -Q. Isn?t pyzaa just a very thin wrapper over zipfile and compileall? +Why not use just use a ``.zip`` or ``.py`` extension? + Users expect a ``.zip`` file to be opened with an archive tool, and + expect a ``.py`` file to contain readable text. Both would be + confusing for this use case. -A. Yes. +How does this compete with existing package formats? + The sdist, bdist and wheel formats are designed for packaging of + modules to be installed into an existing Python installation. + They are not intended to be used without installing. The + executable zip format is specifically designed for standalone use, + without needing to be installed. They are in effect a multi-file + version of a standalone Python script. -Q. How does this compete with existing sdist/bdist formats? +Rejected Proposals +================== -A. There is some overlap, but .pyz files are especially interesting -as a way to distribute an installer. They may also prove useful as a -way to deliver applications when users shouldn?t be asked to perform -virtualenv + ?pip install?. +Convenience Values for Shebang Lines +------------------------------------ + +Is it worth having "convenience" forms for any of the common +interpreter values? For example, ``-p 3`` meaning the same as ``-p +"/usr/bin/env python3"``. It would save a lot of typing for the +common cases, as well as giving cross-platform options for people who +don't want or need to understand the intricacies of shebang handling +on "other" platforms. + +Downsides are that it's not obvious how to translate the +abbreviations. For example, should "3" mean "/usr/bin/env python3", +"/usr/bin/python3", "python3", or something else? Also, there is no +obvious short form for the key case of "/usr/bin/env python" (any +available version of Python), which could easily result in scripts +being written with overly-restrictive shebang lines. + +Overall, this seems like there are more problems than benefits, and as +a result has been dropped from consideration. + +Registering ``.pyz`` as a Media Type +-------------------------------- + +It was suggested [3]_ that the ``.pyz`` extension should be registered +in the Unix database of extensions. While it makes sense to do this +as an equivalent of the Windows installer registering the extension, +the ``.py`` extension is not listed in the media types database [4]_. +It doesn't seem reasonable to register ``.pyz`` without ``.py``, so +this idea has been omitted from this PEP. An interested party could +arrange for *both* ``.py`` and ``.pyz`` to be registered at a future +date. + +Default Interpreter +------------------- + +The initial draft of this PEP proposed using ``/usr/bin/env python`` +as the default interpreter. Unix users have problems with this +behaviour, as the default for the python command on many distributions +is Python 2, and it is felt that this PEP should prefer Python 3 by +default. However, using a command of ``python3`` can result in +unexpected behaviour for Windows users, where the default behaviour of +the launcher for the command ``python`` is commonly customised by users, +but the behaviour of ``python3`` may not be modified to match. + +As a result, the principle "in the face of ambiguity, refuse to guess" +has been invoked, and archives have no shebang line unless explicitly +requested. On Windows, the archives will still be run (with the +default Python) by the launcher, and on Unix, the archives can be run +by explicitly invoking the desired Python interpreter. + +Command Line Tool to Manage Shebang Lines +----------------------------------------- + +It is conceivable that users would want to modify the shebang line for +an existing archive, or even just display the current shebang line. +This is tricky to do so with existing tools (zip programs typically +ignore prepended data totally, and text editors can have trouble +editing files containing binary data). + +The zipapp module provides functions to handle the shebang line, but +does not include a command line interface to that functionality. This +is because it is not clear how to provide one without the resulting +interface being over-complex and potentially confusing. Changing the +shebang line is expected to be an uncommon requirement. + +Reference Implementation +======================== + +A reference implementation is at http://bugs.python.org/issue23491. References ========== -.. [1] ?Allow interpreter to execute a zip file? +.. [1] Allow interpreter to execute a zip file (http://bugs.python.org/issue1739468) -.. [2] ?Feature is not documented? +.. [2] Feature is not documented (http://bugs.python.org/issue17359) +.. [3] Discussion of adding a .pyz mime type on python-dev + (https://mail.python.org/pipermail/python-dev/2015-February/138338.html) + +.. [4] Register of media types + (http://www.iana.org/assignments/media-types/media-types.xhtml) + +.. [5] pyzzer - A tool for creating Python-executable archives + (https://pypi.python.org/pypi/pyzzer) + +.. [6] pex - The PEX packaging toolchain + (https://pypi.python.org/pypi/pex) + +The discussion of this PEP took place on the python-dev mailing list, +in the thread starting at +https://mail.python.org/pipermail/python-dev/2015-February/138277.html + Copyright ========= -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Feb 20 15:09:45 2015 From: python-checkins at python.org (berker.peksag) Date: Fri, 20 Feb 2015 14:09:45 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_441=3A_Update_markup=2E?= Message-ID: <20150220140943.6734.98026@psf.io> https://hg.python.org/peps/rev/778905f87978 changeset: 5700:778905f87978 user: Berker Peksag date: Fri Feb 20 16:10:43 2015 +0200 summary: PEP 441: Update markup. files: pep-0441.txt | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pep-0441.txt b/pep-0441.txt --- a/pep-0441.txt +++ b/pep-0441.txt @@ -88,9 +88,10 @@ Module Interface ---------------- -The zipapp module will provide the following functions:: +The zipapp module will provide the following functions: - pack(target, directory, interpreter=None, main=None) +``pack(target, directory, interpreter=None, main=None)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Writes an application archive called *target*, containing the contents of *directory*. If *interpreter* is specified, it will -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Feb 20 15:48:29 2015 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Feb 2015 14:48:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322834=3A_Fix_a_fa?= =?utf-8?q?iling_test_under_Solaris_due_to_the_platform_not?= Message-ID: <20150220144827.3861.71424@psf.io> https://hg.python.org/cpython/rev/f4f2096ab6f8 changeset: 94700:f4f2096ab6f8 user: Brett Cannon date: Fri Feb 20 09:48:18 2015 -0500 summary: Issue #22834: Fix a failing test under Solaris due to the platform not allowing the deletion of the cwd. Thanks to Martin Panter for the initial fix. files: Lib/test/test_importlib/import_/test_path.py | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -163,8 +163,14 @@ def test_deleted_cwd(self): # Issue #22834 self.addCleanup(os.chdir, os.getcwd()) - with tempfile.TemporaryDirectory() as path: - os.chdir(path) + try: + with tempfile.TemporaryDirectory() as path: + os.chdir(path) + except OSError as exc: + if exc.errno == 22: + # issue #22834 + self.skipTest("platform does not allow the deletion of the cwd") + raise with util.import_state(path=['']): # Do not want FileNotFoundError raised. self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 16:34:30 2015 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Feb 2015 15:34:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323422=3A_Clarify_?= =?utf-8?q?some_things_around_importlib=2Eimport=5Fmodule=28=29?= Message-ID: <20150220153430.4026.15893@psf.io> https://hg.python.org/cpython/rev/46bfddb14cbe changeset: 94701:46bfddb14cbe user: Brett Cannon date: Fri Feb 20 10:34:20 2015 -0500 summary: Issue #23422: Clarify some things around importlib.import_module() files: Doc/library/importlib.rst | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -69,6 +69,10 @@ An implementation of the built-in :func:`__import__` function. + .. note:: + Programmatic importing of modules should use :func:`import_module` + instead of this function. + .. function:: import_module(name, package=None) Import a module. The *name* argument specifies what module to @@ -81,12 +85,15 @@ The :func:`import_module` function acts as a simplifying wrapper around :func:`importlib.__import__`. This means all semantics of the function are - derived from :func:`importlib.__import__`, including requiring the package - from which an import is occurring to have been previously imported - (i.e., *package* must already be imported). The most important difference - is that :func:`import_module` returns the specified package or module - (e.g. ``pkg.mod``), while :func:`__import__` returns the - top-level package or module (e.g. ``pkg``). + derived from :func:`importlib.__import__`. The most important difference + between these two functions is that :func:`import_module` returns the + specified package or module (e.g. ``pkg.mod``), while :func:`__import__` + returns the top-level package or module (e.g. ``pkg``). + + If you are dynamically importing a module that was created since the + interpreter began execution (e.g., created a Python source file), you may + need to call :func:`invalidate_caches` in order for the new module to be + noticed by the import system. .. versionchanged:: 3.3 Parent packages are automatically imported. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 18:13:34 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 20 Feb 2015 17:13:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2323018=3A_Replace?= =?utf-8?q?_copyright_symbol_with_escape=2E?= Message-ID: <20150220171333.116379.76863@psf.io> https://hg.python.org/cpython/rev/843a8ee94270 changeset: 94703:843a8ee94270 user: Steve Dower date: Fri Feb 20 09:08:48 2015 -0800 summary: Closes #23018: Replace copyright symbol with escape. files: PC/python_ver_rc.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/PC/python_ver_rc.h b/PC/python_ver_rc.h --- a/PC/python_ver_rc.h +++ b/PC/python_ver_rc.h @@ -4,7 +4,7 @@ #include "winver.h" #define PYTHON_COMPANY "Python Software Foundation" -#define PYTHON_COPYRIGHT "Copyright ? 2001-2015 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC." +#define PYTHON_COPYRIGHT "Copyright \xA9 2001-2015 Python Software Foundation. Copyright \xA9 2000 BeOpen.com. Copyright \xA9 1995-2001 CNRI. Copyright \xA9 1991-1995 SMC." #define MS_WINDOWS #include "modsupport.h" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 18:13:33 2015 From: python-checkins at python.org (steve.dower) Date: Fri, 20 Feb 2015 17:13:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Removes_unused_string_reso?= =?utf-8?q?urces_from_Windows_installer=2E?= Message-ID: <20150220171333.14025.30023@psf.io> https://hg.python.org/cpython/rev/042531828215 changeset: 94702:042531828215 user: Steve Dower date: Fri Feb 20 08:23:23 2015 -0800 summary: Removes unused string resources from Windows installer. files: Tools/msi/exe/exe_en-US.wxl_template | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Tools/msi/exe/exe_en-US.wxl_template b/Tools/msi/exe/exe_en-US.wxl_template --- a/Tools/msi/exe/exe_en-US.wxl_template +++ b/Tools/msi/exe/exe_en-US.wxl_template @@ -4,6 +4,4 @@ executable Python {{ShortVersion}} ({{Bitness}}) Launches the !(loc.ProductName) interpreter. - Add to PATH - Adds the install directory to PATH and .py to PATHEXT. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 20:35:22 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 19:35:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDkw?= =?utf-8?q?=3A_Fixed_possible_crashes_related_to_interoperability_between?= Message-ID: <20150220193522.6722.4305@psf.io> https://hg.python.org/cpython/rev/038297948389 changeset: 94704:038297948389 branch: 3.4 parent: 94694:21b31f5438ae user: Serhiy Storchaka date: Fri Feb 20 21:34:06 2015 +0200 summary: Issue #23490: Fixed possible crashes related to interoperability between old-style and new API for string with 2**30-1 characters. files: Objects/unicodeobject.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1535,6 +1535,10 @@ /* in case the native representation is 2-bytes, we need to allocate a new normalized 4-byte version. */ length_wo_surrogates = _PyUnicode_WSTR_LENGTH(unicode) - num_surrogates; + if (length_wo_surrogates > PY_SSIZE_T_MAX / 4 - 1) { + PyErr_NoMemory(); + return -1; + } _PyUnicode_DATA_ANY(unicode) = PyObject_MALLOC(4 * (length_wo_surrogates + 1)); if (!_PyUnicode_DATA_ANY(unicode)) { PyErr_NoMemory(); @@ -3846,6 +3850,11 @@ #endif } else { + if ((size_t)_PyUnicode_LENGTH(unicode) > + PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) { + PyErr_NoMemory(); + return NULL; + } _PyUnicode_WSTR(unicode) = (wchar_t *) PyObject_MALLOC(sizeof(wchar_t) * (_PyUnicode_LENGTH(unicode) + 1)); if (!_PyUnicode_WSTR(unicode)) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 20:35:23 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 19:35:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323490=3A_Fixed_possible_crashes_related_to_inte?= =?utf-8?q?roperability_between?= Message-ID: <20150220193522.3883.48@psf.io> https://hg.python.org/cpython/rev/56c6a4bce996 changeset: 94705:56c6a4bce996 parent: 94703:843a8ee94270 parent: 94704:038297948389 user: Serhiy Storchaka date: Fri Feb 20 21:34:39 2015 +0200 summary: Issue #23490: Fixed possible crashes related to interoperability between old-style and new API for string with 2**30-1 characters. files: Objects/unicodeobject.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1535,6 +1535,10 @@ /* in case the native representation is 2-bytes, we need to allocate a new normalized 4-byte version. */ length_wo_surrogates = _PyUnicode_WSTR_LENGTH(unicode) - num_surrogates; + if (length_wo_surrogates > PY_SSIZE_T_MAX / 4 - 1) { + PyErr_NoMemory(); + return -1; + } _PyUnicode_DATA_ANY(unicode) = PyObject_MALLOC(4 * (length_wo_surrogates + 1)); if (!_PyUnicode_DATA_ANY(unicode)) { PyErr_NoMemory(); @@ -3811,6 +3815,11 @@ #endif } else { + if ((size_t)_PyUnicode_LENGTH(unicode) > + PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) { + PyErr_NoMemory(); + return NULL; + } _PyUnicode_WSTR(unicode) = (wchar_t *) PyObject_MALLOC(sizeof(wchar_t) * (_PyUnicode_LENGTH(unicode) + 1)); if (!_PyUnicode_WSTR(unicode)) { -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 22:48:29 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 21:48:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323374=3A_Fixed_pydoc_failure_with_non-ASCII_fil?= =?utf-8?q?es_when_stdout_encoding?= Message-ID: <20150220214829.14027.92477@psf.io> https://hg.python.org/cpython/rev/affe167a45f3 changeset: 94707:affe167a45f3 parent: 94705:56c6a4bce996 parent: 94706:e7b6b1f57268 user: Serhiy Storchaka date: Fri Feb 20 23:47:09 2015 +0200 summary: Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding differs from file system encoding (e.g. on Mac OS). files: Lib/pydoc.py | 22 +++++++++++++--------- Lib/test/test_pydoc.py | 9 +++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1405,9 +1405,6 @@ def pager(text): """The first time this is called, determine what kind of pager to use.""" global pager - # Escape non-encodable characters to avoid encoding errors later - encoding = sys.getfilesystemencoding() - text = text.encode(encoding, 'backslashreplace').decode(encoding) pager = getpager() pager(text) @@ -1450,10 +1447,12 @@ def pipepager(text, cmd): """Page through text by feeding it to another program.""" - pipe = os.popen(cmd, 'w') + import subprocess + proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE) try: - pipe.write(text) - pipe.close() + with proc: + with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe: + pipe.write(text) except OSError: pass # Ignore broken pipes caused by quitting the pager program. @@ -1461,16 +1460,21 @@ """Page through text by invoking a program on a temporary file.""" import tempfile filename = tempfile.mktemp() - with open(filename, 'w') as file: + with open(filename, 'w', errors='backslashreplace') as file: file.write(text) try: os.system(cmd + ' "' + filename + '"') finally: os.unlink(filename) +def _escape_stdout(text): + # Escape non-encodable characters to avoid encoding errors later + encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8' + return text.encode(encoding, 'backslashreplace').decode(encoding) + def ttypager(text): """Page through text on a text terminal.""" - lines = plain(text).split('\n') + lines = plain(_escape_stdout(text)).split('\n') try: import tty fd = sys.stdin.fileno() @@ -1514,7 +1518,7 @@ def plainpager(text): """Simply print unformatted text. This is the ultimate fallback.""" - sys.stdout.write(plain(text)) + sys.stdout.write(plain(_escape_stdout(text))) def describe(thing): """Produce a short description of the given thing.""" diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -34,6 +34,10 @@ except ImportError: threading = None +class nonascii: + '?? ?? ????????' + pass + if test.support.HAVE_DOCSTRINGS: expected_data_docstrings = ( 'dictionary for instance variables (if defined)', @@ -460,6 +464,11 @@ self.assertEqual(expected, result, "documentation for missing module found") + def test_not_ascii(self): + result = run_pydoc('test.test_pydoc.nonascii', PYTHONIOENCODING='ascii') + encoded = nonascii.__doc__.encode('ascii', 'backslashreplace') + self.assertIn(encoded, result) + def test_input_strip(self): missing_module = " test.i_am_not_here " result = str(run_pydoc(missing_module), 'ascii') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding + differs from file system encoding (e.g. on Mac OS). + - Issue #23481: Remove RC4 from the SSL module's default cipher list. - Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 22:48:30 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 21:48:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMzc0?= =?utf-8?q?=3A_Fixed_pydoc_failure_with_non-ASCII_files_when_stdout_encodi?= =?utf-8?q?ng?= Message-ID: <20150220214829.109583.69432@psf.io> https://hg.python.org/cpython/rev/e7b6b1f57268 changeset: 94706:e7b6b1f57268 branch: 3.4 parent: 94704:038297948389 user: Serhiy Storchaka date: Fri Feb 20 23:46:06 2015 +0200 summary: Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding differs from file system encoding (e.g. on Mac OS). files: Lib/pydoc.py | 22 +++++++++++++--------- Lib/test/test_pydoc.py | 9 +++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1407,9 +1407,6 @@ def pager(text): """The first time this is called, determine what kind of pager to use.""" global pager - # Escape non-encodable characters to avoid encoding errors later - encoding = sys.getfilesystemencoding() - text = text.encode(encoding, 'backslashreplace').decode(encoding) pager = getpager() pager(text) @@ -1452,10 +1449,12 @@ def pipepager(text, cmd): """Page through text by feeding it to another program.""" - pipe = os.popen(cmd, 'w') + import subprocess + proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE) try: - pipe.write(text) - pipe.close() + with proc: + with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe: + pipe.write(text) except OSError: pass # Ignore broken pipes caused by quitting the pager program. @@ -1463,16 +1462,21 @@ """Page through text by invoking a program on a temporary file.""" import tempfile filename = tempfile.mktemp() - with open(filename, 'w') as file: + with open(filename, 'w', errors='backslashreplace') as file: file.write(text) try: os.system(cmd + ' "' + filename + '"') finally: os.unlink(filename) +def _escape_stdout(text): + # Escape non-encodable characters to avoid encoding errors later + encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8' + return text.encode(encoding, 'backslashreplace').decode(encoding) + def ttypager(text): """Page through text on a text terminal.""" - lines = plain(text).split('\n') + lines = plain(_escape_stdout(text)).split('\n') try: import tty fd = sys.stdin.fileno() @@ -1516,7 +1520,7 @@ def plainpager(text): """Simply print unformatted text. This is the ultimate fallback.""" - sys.stdout.write(plain(text)) + sys.stdout.write(plain(_escape_stdout(text))) def describe(thing): """Produce a short description of the given thing.""" diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -35,6 +35,10 @@ except ImportError: threading = None +class nonascii: + '?? ?? ????????' + pass + if test.support.HAVE_DOCSTRINGS: expected_data_docstrings = ( 'dictionary for instance variables (if defined)', @@ -474,6 +478,11 @@ self.assertEqual(expected, result, "documentation for missing module found") + def test_not_ascii(self): + result = run_pydoc('test.test_pydoc.nonascii', PYTHONIOENCODING='ascii') + encoded = nonascii.__doc__.encode('ascii', 'backslashreplace') + self.assertIn(encoded, result) + def test_input_strip(self): missing_module = " test.i_am_not_here " result = str(run_pydoc(missing_module), 'ascii') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding + differs from file system encoding (e.g. on Mac OS). + - Issue #23481: Remove RC4 from the SSL module's default cipher list. - Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 23:37:11 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 22:37:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzU3MDA6?= =?utf-8?q?_io=2EFileIO=28=29_called_flush=28=29_after_closing_the_file=2E?= Message-ID: <20150220223710.99290.91007@psf.io> https://hg.python.org/cpython/rev/36f5c36b7704 changeset: 94709:36f5c36b7704 branch: 3.4 parent: 94706:e7b6b1f57268 user: Serhiy Storchaka date: Sat Feb 21 00:35:09 2015 +0200 summary: Issue #5700: io.FileIO() called flush() after closing the file. flush() was not called in close() if closefd=False. files: Lib/test/test_io.py | 50 ++++++++++++++++++++++++++++++- Misc/NEWS | 3 + Modules/_io/fileio.c | 21 ++++++++---- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -593,13 +593,43 @@ with self.open(zero, "r") as f: self.assertRaises(OverflowError, f.read) - def test_flush_error_on_close(self): - f = self.open(support.TESTFN, "wb", buffering=0) + def check_flush_error_on_close(self, *args, **kwargs): + # Test that the file is closed despite failed flush + # and that flush() is called before file closed. + f = self.open(*args, **kwargs) + closed = [] def bad_flush(): + closed[:] = [f.closed] raise OSError() f.flush = bad_flush self.assertRaises(OSError, f.close) # exception not swallowed self.assertTrue(f.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + + def test_flush_error_on_close(self): + # raw file + # Issue #5700: io.FileIO calls flush() after file closed + self.check_flush_error_on_close(support.TESTFN, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0, closefd=False) + os.close(fd) + # buffered io + self.check_flush_error_on_close(support.TESTFN, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', closefd=False) + os.close(fd) + # text io + self.check_flush_error_on_close(support.TESTFN, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w', closefd=False) + os.close(fd) def test_multi_close(self): f = self.open(support.TESTFN, "wb", buffering=0) @@ -788,13 +818,21 @@ self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname) def test_flush_error_on_close(self): + # Test that buffered file is closed despite failed flush + # and that flush() is called before file closed. raw = self.MockRawIO() + closed = [] def bad_flush(): + closed[:] = [b.closed, raw.closed] raise OSError() raw.flush = bad_flush b = self.tp(raw) self.assertRaises(OSError, b.close) # exception not swallowed self.assertTrue(b.closed) + self.assertTrue(raw.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2618,12 +2656,20 @@ self.assertEqual(content.count("Thread%03d\n" % n), 1) def test_flush_error_on_close(self): + # Test that text file is closed despite failed flush + # and that flush() is called before file closed. txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + closed = [] def bad_flush(): + closed[:] = [txt.closed, txt.buffer.closed] raise OSError() txt.flush = bad_flush self.assertRaises(OSError, txt.close) # exception not swallowed self.assertTrue(txt.closed) + self.assertTrue(txt.buffer.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_close_error_on_close(self): buffer = self.BytesIO(self.testdata) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #5700: io.FileIO() called flush() after closing the file. + flush() was not called in close() if closefd=False. + - Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding differs from file system encoding (e.g. on Mac OS). diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -126,11 +126,18 @@ static PyObject * fileio_close(fileio *self) { + PyObject *res; + PyObject *exc, *val, *tb; + int rc; _Py_IDENTIFIER(close); + res = _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_close, "O", self); if (!self->closefd) { self->fd = -1; - Py_RETURN_NONE; + return res; } + if (res == NULL) + PyErr_Fetch(&exc, &val, &tb); if (self->finalizing) { PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); if (r) @@ -138,12 +145,12 @@ else PyErr_Clear(); } - errno = internal_close(self); - if (errno < 0) - return NULL; - - return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, - &PyId_close, "O", self); + rc = internal_close(self); + if (res == NULL) + _PyErr_ChainExceptions(exc, val, tb); + if (rc < 0) + Py_CLEAR(res); + return res; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 23:37:11 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 22:37:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogSXNzdWUgIzU3MDA6IGlvLkZpbGVJTygpIGNhbGxlZCBmbHVzaCgpIGFm?= =?utf-8?q?ter_closing_the_file=2E?= Message-ID: <20150220223710.3859.50106@psf.io> https://hg.python.org/cpython/rev/e1f08f5b6b62 changeset: 94710:e1f08f5b6b62 parent: 94707:affe167a45f3 parent: 94709:36f5c36b7704 user: Serhiy Storchaka date: Sat Feb 21 00:35:53 2015 +0200 summary: Issue #5700: io.FileIO() called flush() after closing the file. flush() was not called in close() if closefd=False. files: Lib/test/test_io.py | 50 ++++++++++++++++++++++++++++++- Misc/NEWS | 3 + Modules/_io/fileio.c | 21 ++++++++---- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -589,13 +589,43 @@ with self.open(zero, "r") as f: self.assertRaises(OverflowError, f.read) - def test_flush_error_on_close(self): - f = self.open(support.TESTFN, "wb", buffering=0) + def check_flush_error_on_close(self, *args, **kwargs): + # Test that the file is closed despite failed flush + # and that flush() is called before file closed. + f = self.open(*args, **kwargs) + closed = [] def bad_flush(): + closed[:] = [f.closed] raise OSError() f.flush = bad_flush self.assertRaises(OSError, f.close) # exception not swallowed self.assertTrue(f.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + + def test_flush_error_on_close(self): + # raw file + # Issue #5700: io.FileIO calls flush() after file closed + self.check_flush_error_on_close(support.TESTFN, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0, closefd=False) + os.close(fd) + # buffered io + self.check_flush_error_on_close(support.TESTFN, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', closefd=False) + os.close(fd) + # text io + self.check_flush_error_on_close(support.TESTFN, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w', closefd=False) + os.close(fd) def test_multi_close(self): f = self.open(support.TESTFN, "wb", buffering=0) @@ -784,13 +814,21 @@ self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname) def test_flush_error_on_close(self): + # Test that buffered file is closed despite failed flush + # and that flush() is called before file closed. raw = self.MockRawIO() + closed = [] def bad_flush(): + closed[:] = [b.closed, raw.closed] raise OSError() raw.flush = bad_flush b = self.tp(raw) self.assertRaises(OSError, b.close) # exception not swallowed self.assertTrue(b.closed) + self.assertTrue(raw.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2679,12 +2717,20 @@ self.assertEqual(content.count("Thread%03d\n" % n), 1) def test_flush_error_on_close(self): + # Test that text file is closed despite failed flush + # and that flush() is called before file closed. txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + closed = [] def bad_flush(): + closed[:] = [txt.closed, txt.buffer.closed] raise OSError() txt.flush = bad_flush self.assertRaises(OSError, txt.close) # exception not swallowed self.assertTrue(txt.closed) + self.assertTrue(txt.buffer.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_close_error_on_close(self): buffer = self.BytesIO(self.testdata) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #5700: io.FileIO() called flush() after closing the file. + flush() was not called in close() if closefd=False. + - Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding differs from file system encoding (e.g. on Mac OS). diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -127,11 +127,18 @@ static PyObject * fileio_close(fileio *self) { + PyObject *res; + PyObject *exc, *val, *tb; + int rc; _Py_IDENTIFIER(close); + res = _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_close, "O", self); if (!self->closefd) { self->fd = -1; - Py_RETURN_NONE; + return res; } + if (res == NULL) + PyErr_Fetch(&exc, &val, &tb); if (self->finalizing) { PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); if (r) @@ -139,12 +146,12 @@ else PyErr_Clear(); } - errno = internal_close(self); - if (errno < 0) - return NULL; - - return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, - &PyId_close, "O", self); + rc = internal_close(self); + if (res == NULL) + _PyErr_ChainExceptions(exc, val, tb); + if (rc < 0) + Py_CLEAR(res); + return res; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 20 23:37:11 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 22:37:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzU3MDA6?= =?utf-8?q?_io=2EFileIO=28=29_called_flush=28=29_after_closing_the_file=2E?= Message-ID: <20150220223710.109571.32765@psf.io> https://hg.python.org/cpython/rev/7052206ad381 changeset: 94708:7052206ad381 branch: 2.7 parent: 94697:43641e03692a user: Serhiy Storchaka date: Sat Feb 21 00:34:20 2015 +0200 summary: Issue #5700: io.FileIO() called flush() after closing the file. flush() was not called in close() if closefd=False. files: Lib/test/test_io.py | 50 ++++++++++++++++++++++++++++++- Misc/NEWS | 3 + Modules/_io/fileio.c | 14 ++++---- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -564,13 +564,43 @@ with self.open(zero, "r") as f: self.assertRaises(OverflowError, f.read) - def test_flush_error_on_close(self): - f = self.open(support.TESTFN, "wb", buffering=0) + def check_flush_error_on_close(self, *args, **kwargs): + # Test that the file is closed despite failed flush + # and that flush() is called before file closed. + f = self.open(*args, **kwargs) + closed = [] def bad_flush(): + closed[:] = [f.closed] raise IOError() f.flush = bad_flush self.assertRaises(IOError, f.close) # exception not swallowed self.assertTrue(f.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + + def test_flush_error_on_close(self): + # raw file + # Issue #5700: io.FileIO calls flush() after file closed + self.check_flush_error_on_close(support.TESTFN, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0, closefd=False) + os.close(fd) + # buffered io + self.check_flush_error_on_close(support.TESTFN, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', closefd=False) + os.close(fd) + # text io + self.check_flush_error_on_close(support.TESTFN, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w', closefd=False) + os.close(fd) def test_multi_close(self): f = self.open(support.TESTFN, "wb", buffering=0) @@ -741,13 +771,21 @@ self.assertEqual(repr(b), "<%s name='dummy'>" % clsname) def test_flush_error_on_close(self): + # Test that buffered file is closed despite failed flush + # and that flush() is called before file closed. raw = self.MockRawIO() + closed = [] def bad_flush(): + closed[:] = [b.closed, raw.closed] raise IOError() raw.flush = bad_flush b = self.tp(raw) self.assertRaises(IOError, b.close) # exception not swallowed self.assertTrue(b.closed) + self.assertTrue(raw.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2484,12 +2522,20 @@ self.assertEqual(content.count("Thread%03d\n" % n), 1) def test_flush_error_on_close(self): + # Test that text file is closed despite failed flush + # and that flush() is called before file closed. txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + closed = [] def bad_flush(): + closed[:] = [txt.closed, txt.buffer.closed] raise IOError() txt.flush = bad_flush self.assertRaises(IOError, txt.close) # exception not swallowed self.assertTrue(txt.closed) + self.assertTrue(txt.buffer.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_multi_close(self): txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #5700: io.FileIO() called flush() after closing the file. + flush() was not called in close() if closefd=False. + - Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty docstrings. Initial patch by Yuyang Guo. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -101,16 +101,16 @@ static PyObject * fileio_close(fileio *self) { + PyObject *res; + res = PyObject_CallMethod((PyObject*)&PyRawIOBase_Type, + "close", "O", self); if (!self->closefd) { self->fd = -1; - Py_RETURN_NONE; + return res; } - errno = internal_close(self); - if (errno < 0) - return NULL; - - return PyObject_CallMethod((PyObject*)&PyRawIOBase_Type, - "close", "O", self); + if (internal_close(self) < 0) + Py_CLEAR(res); + return res; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 00:23:32 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 23:23:32 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323215=3A_Multibyte_codecs_with_custom_error_han?= =?utf-8?q?dlers_that_ignores_errors?= Message-ID: <20150220232326.116385.31798@psf.io> https://hg.python.org/cpython/rev/5620691ce26b changeset: 94713:5620691ce26b parent: 94710:e1f08f5b6b62 parent: 94712:4dc8b7ed8973 user: Serhiy Storchaka date: Sat Feb 21 01:21:08 2015 +0200 summary: Issue #23215: Multibyte codecs with custom error handlers that ignores errors consumed too much memory and raised SystemError or MemoryError. Original patch by Aleksi Torhamo. files: Lib/test/test_multibytecodec.py | 7 ++++++ Misc/NEWS | 4 +++ Modules/cjkcodecs/multibytecodec.c | 19 ++++++++++------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -44,6 +44,13 @@ self.assertRaises(IndexError, dec, b'apple\x92ham\x93spam', 'test.cjktest') + def test_errorcallback_custom_ignore(self): + # Issue #23215: MemoryError with custom error handlers and multibyte codecs + data = 100 * "\udc00" + codecs.register_error("test.ignore", codecs.ignore_errors) + for enc in ALL_CJKENCODINGS: + self.assertEqual(data.encode(enc, "test.ignore"), b'') + def test_codingspec(self): try: for enc in ALL_CJKENCODINGS: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Library ------- +- Issue #23215: Multibyte codecs with custom error handlers that ignores errors + consumed too much memory and raised SystemError or MemoryError. + Original patch by Aleksi Torhamo. + - Issue #5700: io.FileIO() called flush() after closing the file. flush() was not called in close() if closefd=False. diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -174,8 +174,10 @@ orgsize = PyBytes_GET_SIZE(buf->outobj); incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize); - if (orgsize > PY_SSIZE_T_MAX - incsize) + if (orgsize > PY_SSIZE_T_MAX - incsize) { + PyErr_NoMemory(); return -1; + } if (_PyBytes_Resize(&buf->outobj, orgsize + incsize) == -1) return -1; @@ -186,11 +188,11 @@ return 0; } -#define REQUIRE_ENCODEBUFFER(buf, s) { \ - if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ +#define REQUIRE_ENCODEBUFFER(buf, s) do { \ + if ((s) < 0 || (s) > (buf)->outbuf_end - (buf)->outbuf) \ if (expand_encodebuffer(buf, s) == -1) \ goto errorexit; \ -} +} while(0) /** @@ -324,10 +326,11 @@ assert(PyBytes_Check(retstr)); retstrsize = PyBytes_GET_SIZE(retstr); - REQUIRE_ENCODEBUFFER(buf, retstrsize); - - memcpy(buf->outbuf, PyBytes_AS_STRING(retstr), retstrsize); - buf->outbuf += retstrsize; + if (retstrsize > 0) { + REQUIRE_ENCODEBUFFER(buf, retstrsize); + memcpy(buf->outbuf, PyBytes_AS_STRING(retstr), retstrsize); + buf->outbuf += retstrsize; + } newpos = PyLong_AsSsize_t(PyTuple_GET_ITEM(retobj, 1)); if (newpos < 0 && !PyErr_Occurred()) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 00:23:26 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 23:23:26 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzMjE1?= =?utf-8?q?=3A_Multibyte_codecs_with_custom_error_handlers_that_ignores_er?= =?utf-8?q?rors?= Message-ID: <20150220232325.10184.6148@psf.io> https://hg.python.org/cpython/rev/4dc8b7ed8973 changeset: 94712:4dc8b7ed8973 branch: 3.4 parent: 94709:36f5c36b7704 user: Serhiy Storchaka date: Sat Feb 21 01:19:58 2015 +0200 summary: Issue #23215: Multibyte codecs with custom error handlers that ignores errors consumed too much memory and raised SystemError or MemoryError. Original patch by Aleksi Torhamo. files: Lib/test/test_multibytecodec.py | 7 ++++++ Misc/NEWS | 4 +++ Modules/cjkcodecs/multibytecodec.c | 19 ++++++++++------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -44,6 +44,13 @@ self.assertRaises(IndexError, dec, b'apple\x92ham\x93spam', 'test.cjktest') + def test_errorcallback_custom_ignore(self): + # Issue #23215: MemoryError with custom error handlers and multibyte codecs + data = 100 * "\udc00" + codecs.register_error("test.ignore", codecs.ignore_errors) + for enc in ALL_CJKENCODINGS: + self.assertEqual(data.encode(enc, "test.ignore"), b'') + def test_codingspec(self): try: for enc in ALL_CJKENCODINGS: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Library ------- +- Issue #23215: Multibyte codecs with custom error handlers that ignores errors + consumed too much memory and raised SystemError or MemoryError. + Original patch by Aleksi Torhamo. + - Issue #5700: io.FileIO() called flush() after closing the file. flush() was not called in close() if closefd=False. diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -182,8 +182,10 @@ orgsize = PyBytes_GET_SIZE(buf->outobj); incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize); - if (orgsize > PY_SSIZE_T_MAX - incsize) + if (orgsize > PY_SSIZE_T_MAX - incsize) { + PyErr_NoMemory(); return -1; + } if (_PyBytes_Resize(&buf->outobj, orgsize + incsize) == -1) return -1; @@ -194,11 +196,11 @@ return 0; } -#define REQUIRE_ENCODEBUFFER(buf, s) { \ - if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ +#define REQUIRE_ENCODEBUFFER(buf, s) do { \ + if ((s) < 0 || (s) > (buf)->outbuf_end - (buf)->outbuf) \ if (expand_encodebuffer(buf, s) == -1) \ goto errorexit; \ -} +} while(0) /** @@ -332,10 +334,11 @@ assert(PyBytes_Check(retstr)); retstrsize = PyBytes_GET_SIZE(retstr); - REQUIRE_ENCODEBUFFER(buf, retstrsize); - - memcpy(buf->outbuf, PyBytes_AS_STRING(retstr), retstrsize); - buf->outbuf += retstrsize; + if (retstrsize > 0) { + REQUIRE_ENCODEBUFFER(buf, retstrsize); + memcpy(buf->outbuf, PyBytes_AS_STRING(retstr), retstrsize); + buf->outbuf += retstrsize; + } newpos = PyLong_AsSsize_t(PyTuple_GET_ITEM(retobj, 1)); if (newpos < 0 && !PyErr_Occurred()) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 00:23:32 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 20 Feb 2015 23:23:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzMjE1?= =?utf-8?q?=3A_Multibyte_codecs_with_custom_error_handlers_that_ignores_er?= =?utf-8?q?rors?= Message-ID: <20150220232325.3873.91459@psf.io> https://hg.python.org/cpython/rev/af8089217cc6 changeset: 94711:af8089217cc6 branch: 2.7 parent: 94708:7052206ad381 user: Serhiy Storchaka date: Sat Feb 21 01:19:17 2015 +0200 summary: Issue #23215: Multibyte codecs with custom error handlers that ignores errors consumed too much memory and raised SystemError or MemoryError. Original patch by Aleksi Torhamo. files: Lib/test/test_multibytecodec.py | 7 +++++ Misc/NEWS | 4 ++ Modules/cjkcodecs/multibytecodec.c | 25 ++++++++++------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -43,6 +43,13 @@ self.assertRaises(IndexError, dec, 'apple\x92ham\x93spam', 'test.cjktest') + def test_errorcallback_custom_ignore(self): + # Issue #23215: MemoryError with custom error handlers and multibyte codecs + data = 100 * unichr(0xdc00) + codecs.register_error("test.ignore", codecs.ignore_errors) + for enc in ALL_CJKENCODINGS: + self.assertEqual(data.encode(enc, "test.ignore"), b'') + def test_codingspec(self): for enc in ALL_CJKENCODINGS: code = '# coding: {}\n'.format(enc) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,10 @@ Library ------- +- Issue #23215: Multibyte codecs with custom error handlers that ignores errors + consumed too much memory and raised SystemError or MemoryError. + Original patch by Aleksi Torhamo. + - Issue #5700: io.FileIO() called flush() after closing the file. flush() was not called in close() if closefd=False. diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -170,8 +170,10 @@ orgsize = PyString_GET_SIZE(buf->outobj); incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize); - if (orgsize > PY_SSIZE_T_MAX - incsize) + if (orgsize > PY_SSIZE_T_MAX - incsize) { + PyErr_NoMemory(); return -1; + } if (_PyString_Resize(&buf->outobj, orgsize + incsize) == -1) return -1; @@ -182,11 +184,11 @@ return 0; } -#define REQUIRE_ENCODEBUFFER(buf, s) { \ - if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ +#define REQUIRE_ENCODEBUFFER(buf, s) do { \ + if ((s) < 0 || (s) > (buf)->outbuf_end - (buf)->outbuf) \ if (expand_encodebuffer(buf, s) == -1) \ goto errorexit; \ -} +} while(0) static int expand_decodebuffer(MultibyteDecodeBuffer *buf, Py_ssize_t esize) @@ -205,11 +207,11 @@ return 0; } -#define REQUIRE_DECODEBUFFER(buf, s) { \ - if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ +#define REQUIRE_DECODEBUFFER(buf, s) do { \ + if ((s) < 0 || (s) > (buf)->outbuf_end - (buf)->outbuf) \ if (expand_decodebuffer(buf, s) == -1) \ goto errorexit; \ -} +} while(0) /** @@ -327,10 +329,11 @@ } retstrsize = PyString_GET_SIZE(retstr); - REQUIRE_ENCODEBUFFER(buf, retstrsize); - - memcpy(buf->outbuf, PyString_AS_STRING(retstr), retstrsize); - buf->outbuf += retstrsize; + if (retstrsize > 0) { + REQUIRE_ENCODEBUFFER(buf, retstrsize); + memcpy(buf->outbuf, PyString_AS_STRING(retstr), retstrsize); + buf->outbuf += retstrsize; + } newpos = PyInt_AsSsize_t(PyTuple_GET_ITEM(retobj, 1)); if (newpos < 0 && !PyErr_Occurred()) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 11:12:01 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 21 Feb 2015 10:12:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20150221101201.116383.63275@psf.io> https://hg.python.org/cpython/rev/a291916333ee changeset: 94717:a291916333ee parent: 94714:b78195af96f5 parent: 94716:e295ad9be16d user: Serhiy Storchaka date: Sat Feb 21 12:10:59 2015 +0200 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 11:12:01 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 21 Feb 2015 10:12:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWVzICM4MTQy?= =?utf-8?q?53=2C_=239179=3A_Warnings_now_are_raised_when_group_references_?= =?utf-8?q?and?= Message-ID: <20150221101201.3861.14107@psf.io> https://hg.python.org/cpython/rev/5387095b8675 changeset: 94715:5387095b8675 branch: 2.7 parent: 94711:af8089217cc6 user: Serhiy Storchaka date: Sat Feb 21 12:08:36 2015 +0200 summary: Issues #814253, #9179: Warnings now are raised when group references and conditional group references are used in lookbehind assertions in regular expressions. files: Doc/library/re.rst | 7 +++- Lib/sre_parse.py | 20 ++++++++++++++ Lib/test/test_re.py | 45 ++++++++++++++++++++++++++++++-- Misc/NEWS | 4 ++ 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -276,7 +276,9 @@ assertion`. ``(?<=abc)def`` will find a match in ``abcdef``, since the lookbehind will back up 3 characters and check if the contained pattern matches. The contained pattern must only match strings of some fixed length, meaning that - ``abc`` or ``a|b`` are allowed, but ``a*`` and ``a{3,4}`` are not. Note that + ``abc`` or ``a|b`` are allowed, but ``a*`` and ``a{3,4}`` are not. Group + references are not supported even if they match strings of some fixed length. + Note that patterns which start with positive lookbehind assertions will not match at the beginning of the string being searched; you will most likely want to use the :func:`search` function rather than the :func:`match` function: @@ -296,7 +298,8 @@ Matches if the current position in the string is not preceded by a match for ``...``. This is called a :dfn:`negative lookbehind assertion`. Similar to positive lookbehind assertions, the contained pattern must only match strings of - some fixed length. Patterns which start with negative lookbehind assertions may + some fixed length and shouldn't contain group references. + Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched. ``(?(id/name)yes-pattern|no-pattern)`` diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -69,6 +69,8 @@ self.open = [] self.groups = 1 self.groupdict = {} + self.lookbehind = 0 + def opengroup(self, name=None): gid = self.groups self.groups = gid + 1 @@ -299,6 +301,11 @@ if group < state.groups: if not state.checkgroup(group): raise error, "cannot refer to open group" + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) return GROUPREF, group raise ValueError if len(escape) == 2: @@ -578,6 +585,11 @@ if gid is None: msg = "unknown group name: {0!r}".format(name) raise error(msg) + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) subpatternappend((GROUPREF, gid)) continue else: @@ -606,7 +618,10 @@ raise error, "syntax error" dir = -1 # lookbehind char = sourceget() + state.lookbehind += 1 p = _parse_sub(source, state) + if dir < 0: + state.lookbehind -= 1 if not sourcematch(")"): raise error, "unbalanced parenthesis" if char == "=": @@ -637,6 +652,11 @@ condgroup = int(condname) except ValueError: raise error, "bad character in group name" + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) else: # flags if not source.next in FLAGS: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- -from test.test_support import verbose, run_unittest, import_module -from test.test_support import precisionbigmemtest, _2G, cpython_only -from test.test_support import captured_stdout, have_unicode, requires_unicode, u +from test.test_support import ( + verbose, run_unittest, import_module, + precisionbigmemtest, _2G, cpython_only, + captured_stdout, have_unicode, requires_unicode, u, + check_warnings) import locale import re from re import Scanner @@ -449,7 +451,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_non_consuming(self): + def test_lookahead(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -463,6 +465,41 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") + # Group reference. + self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) + self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) + # Named group reference. + self.assertTrue(re.match(r'(?Pa)b(?=(?P=g))a', 'aba')) + self.assertIsNone(re.match(r'(?Pa)b(?=(?P=g))c', 'abac')) + # Conditional group reference. + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) + # Group used before defined. + self.assertTrue(re.match(r'(a)b(?=(?(2)x|c))(c)', 'abc')) + self.assertIsNone(re.match(r'(a)b(?=(?(2)b|x))(c)', 'abc')) + self.assertTrue(re.match(r'(a)b(?=(?(1)c|x))(c)', 'abc')) + + def test_lookbehind(self): + self.assertTrue(re.match(r'ab(?<=b)c', 'abc')) + self.assertIsNone(re.match(r'ab(?<=c)c', 'abc')) + self.assertIsNone(re.match(r'ab(?a)a(?<=(?P=g))c') + # Conditional group reference. + with check_warnings(('', RuntimeWarning)): + re.compile(r'(a)b(?<=(?(1)b|x))c') + # Group used before defined. + with check_warnings(('', RuntimeWarning)): + re.compile(r'(a)b(?<=(?(2)b|x))(c)') + def test_ignore_case(self): self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC") self.assertEqual(re.match("abc", u"ABC", re.I).group(0), "ABC") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,10 @@ Library ------- +- Issues #814253, #9179: Warnings now are raised when group references and + conditional group references are used in lookbehind assertions in regular + expressions. + - Issue #23215: Multibyte codecs with custom error handlers that ignores errors consumed too much memory and raised SystemError or MemoryError. Original patch by Aleksi Torhamo. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 11:12:01 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 21 Feb 2015 10:12:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWVzICM4MTQy?= =?utf-8?q?53=2C_=239179=3A_Warnings_now_are_raised_when_group_references_?= =?utf-8?q?and?= Message-ID: <20150221101201.109544.85878@psf.io> https://hg.python.org/cpython/rev/e295ad9be16d changeset: 94716:e295ad9be16d branch: 3.4 parent: 94712:4dc8b7ed8973 user: Serhiy Storchaka date: Sat Feb 21 12:08:52 2015 +0200 summary: Issues #814253, #9179: Warnings now are raised when group references and conditional group references are used in lookbehind assertions in regular expressions. files: Doc/library/re.rst | 7 +++++-- Lib/sre_parse.py | 20 ++++++++++++++++++++ Lib/test/test_re.py | 33 ++++++++++++++++++++++++++++++++- Misc/NEWS | 4 ++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -281,7 +281,9 @@ assertion`. ``(?<=abc)def`` will find a match in ``abcdef``, since the lookbehind will back up 3 characters and check if the contained pattern matches. The contained pattern must only match strings of some fixed length, meaning that - ``abc`` or ``a|b`` are allowed, but ``a*`` and ``a{3,4}`` are not. Note that + ``abc`` or ``a|b`` are allowed, but ``a*`` and ``a{3,4}`` are not. Group + references are not supported even if they match strings of some fixed length. + Note that patterns which start with positive lookbehind assertions will not match at the beginning of the string being searched; you will most likely want to use the :func:`search` function rather than the :func:`match` function: @@ -301,7 +303,8 @@ Matches if the current position in the string is not preceded by a match for ``...``. This is called a :dfn:`negative lookbehind assertion`. Similar to positive lookbehind assertions, the contained pattern must only match strings of - some fixed length. Patterns which start with negative lookbehind assertions may + some fixed length and shouldn't contain group references. + Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched. ``(?(id/name)yes-pattern|no-pattern)`` diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -69,6 +69,8 @@ self.open = [] self.groups = 1 self.groupdict = {} + self.lookbehind = 0 + def opengroup(self, name=None): gid = self.groups self.groups = gid + 1 @@ -352,6 +354,11 @@ if group < state.groups: if not state.checkgroup(group): raise error("cannot refer to open group") + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) return GROUPREF, group raise ValueError if len(escape) == 2: @@ -630,6 +637,11 @@ if gid is None: msg = "unknown group name: {0!r}".format(name) raise error(msg) + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) subpatternappend((GROUPREF, gid)) continue else: @@ -658,7 +670,10 @@ raise error("syntax error") dir = -1 # lookbehind char = sourceget() + state.lookbehind += 1 p = _parse_sub(source, state) + if dir < 0: + state.lookbehind -= 1 if not sourcematch(")"): raise error("unbalanced parenthesis") if char == "=": @@ -689,6 +704,11 @@ condgroup = int(condname) except ValueError: raise error("bad character in group name") + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) else: # flags if not source.next in FLAGS: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -557,7 +557,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_non_consuming(self): + def test_lookahead(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -571,6 +571,37 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") + # Group reference. + self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) + self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) + # Named group reference. + self.assertTrue(re.match(r'(?Pa)b(?=(?P=g))a', 'aba')) + self.assertIsNone(re.match(r'(?Pa)b(?=(?P=g))c', 'abac')) + # Conditional group reference. + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) + # Group used before defined. + self.assertTrue(re.match(r'(a)b(?=(?(2)x|c))(c)', 'abc')) + self.assertIsNone(re.match(r'(a)b(?=(?(2)b|x))(c)', 'abc')) + self.assertTrue(re.match(r'(a)b(?=(?(1)c|x))(c)', 'abc')) + + def test_lookbehind(self): + self.assertTrue(re.match(r'ab(?<=b)c', 'abc')) + self.assertIsNone(re.match(r'ab(?<=c)c', 'abc')) + self.assertIsNone(re.match(r'ab(?a)a(?<=(?P=g))c') + # Conditional group reference. + self.assertWarns(RuntimeWarning, re.compile, r'(a)b(?<=(?(1)b|x))c') + # Group used before defined. + self.assertWarns(RuntimeWarning, re.compile, r'(a)b(?<=(?(2)b|x))(c)') + def test_ignore_case(self): self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC") self.assertEqual(re.match(b"abc", b"ABC", re.I).group(0), b"ABC") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Library ------- +- Issues #814253, #9179: Warnings now are raised when group references and + conditional group references are used in lookbehind assertions in regular + expressions. + - Issue #23215: Multibyte codecs with custom error handlers that ignores errors consumed too much memory and raised SystemError or MemoryError. Original patch by Aleksi Torhamo. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 11:12:01 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 21 Feb 2015 10:12:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issues_=23814253=2C_=23917?= =?utf-8?q?9=3A_Group_references_and_conditional_group_references_now?= Message-ID: <20150221101201.14031.10554@psf.io> https://hg.python.org/cpython/rev/b78195af96f5 changeset: 94714:b78195af96f5 user: Serhiy Storchaka date: Sat Feb 21 10:07:35 2015 +0200 summary: Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. files: Doc/library/re.rst | 3 + Lib/re.py | 5 +- Lib/sre_parse.py | 51 +++++++++++++++++++++++++++----- Lib/test/test_re.py | 42 ++++++++++++++++++++++++++- Misc/NEWS | 3 + 5 files changed, 92 insertions(+), 12 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -297,6 +297,9 @@ >>> m.group(0) 'egg' + .. versionchanged: 3.5 + Added support for group references of fixed length. + ``(? MAXGROUPS: raise error("groups number is too large") if name is not None: @@ -82,12 +85,19 @@ raise error("redefinition of group name %r as group %d; " "was group %d" % (name, gid, ogid)) self.groupdict[name] = gid - self.open.append(gid) return gid - def closegroup(self, gid): - self.open.remove(gid) + def closegroup(self, gid, p): + self.subpatterns[gid] = p def checkgroup(self, gid): - return gid < self.groups and gid not in self.open + return gid < self.groups and self.subpatterns[gid] is not None + + def checklookbehindgroup(self, gid, source): + if self.lookbehindgroups is not None: + if not self.checkgroup(gid): + raise source.error('cannot refer to an open group') + if gid >= self.lookbehindgroups: + raise source.error('cannot refer to group defined in the same ' + 'lookbehind subpattern') class SubPattern: # a subpattern, in intermediate form @@ -183,7 +193,21 @@ elif op in _UNITCODES: lo = lo + 1 hi = hi + 1 - elif op == SUCCESS: + elif op is GROUPREF: + i, j = self.pattern.subpatterns[av].getwidth() + lo = lo + i + hi = hi + j + elif op is GROUPREF_EXISTS: + i, j = av[1].getwidth() + if av[2] is not None: + l, h = av[2].getwidth() + i = min(i, l) + j = max(j, h) + else: + i = 0 + lo = lo + i + hi = hi + j + elif op is SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -379,6 +403,7 @@ if not state.checkgroup(group): raise source.error("cannot refer to open group", len(escape)) + state.checklookbehindgroup(group, source) return GROUPREF, group raise ValueError if len(escape) == 2: @@ -641,6 +666,7 @@ if gid is None: msg = "unknown group name: {0!r}".format(name) raise source.error(msg, len(name) + 1) + state.checklookbehindgroup(gid, source) subpatternappend((GROUPREF, gid)) continue else: @@ -668,7 +694,13 @@ if char is None or char not in "=!": raise source.error("syntax error") dir = -1 # lookbehind + lookbehindgroups = state.lookbehindgroups + if lookbehindgroups is None: + state.lookbehindgroups = state.groups p = _parse_sub(source, state) + if dir < 0: + if lookbehindgroups is None: + state.lookbehindgroups = None if not sourcematch(")"): raise source.error("unbalanced parenthesis") if char == "=": @@ -701,6 +733,7 @@ if condgroup >= MAXGROUPS: raise source.error("the group number is too large", len(condname) + 1) + state.checklookbehindgroup(condgroup, source) elif char in FLAGS: # flags state.flags |= FLAGS[char] @@ -726,7 +759,7 @@ if not sourcematch(")"): raise source.error("unbalanced parenthesis") if group is not None: - state.closegroup(group) + state.closegroup(group, p) subpatternappend((SUBPATTERN, (group, p))) else: while True: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -604,7 +604,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_non_consuming(self): + def test_lookahead(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -618,6 +618,46 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") + # Group reference. + self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) + self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) + # Conditional group reference. + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) + # Group used before defined. + self.assertTrue(re.match(r'(a)b(?=(?(2)x|c))(c)', 'abc')) + self.assertIsNone(re.match(r'(a)b(?=(?(2)b|x))(c)', 'abc')) + self.assertTrue(re.match(r'(a)b(?=(?(1)c|x))(c)', 'abc')) + + def test_lookbehind(self): + self.assertTrue(re.match(r'ab(?<=b)c', 'abc')) + self.assertIsNone(re.match(r'ab(?<=c)c', 'abc')) + self.assertIsNone(re.match(r'ab(?.)(?P=a))(c)') + self.assertRaises(re.error, re.compile, r'(a)b(?<=(a)(?(2)b|x))(c)') + self.assertRaises(re.error, re.compile, r'(a)b(?<=(.)(?<=\2))(c)') + def test_ignore_case(self): self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC") self.assertEqual(re.match(b"abc", b"ABC", re.I).group(0), b"ABC") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issues #814253, #9179: Group references and conditional group references now + work in lookbehind assertions in regular expressions. + - Issue #23215: Multibyte codecs with custom error handlers that ignores errors consumed too much memory and raised SystemError or MemoryError. Original patch by Aleksi Torhamo. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 17:50:43 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 21 Feb 2015 16:50:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323152=3A_Implemen?= =?utf-8?q?t_=5FPy=5Ffstat=28=29_to_support_files_larger_than_2_GB_on?= Message-ID: <20150221165042.3869.45515@psf.io> https://hg.python.org/cpython/rev/4f6f4aa0d80f changeset: 94718:4f6f4aa0d80f user: Steve Dower date: Sat Feb 21 08:44:05 2015 -0800 summary: Issue #23152: Implement _Py_fstat() to support files larger than 2 GB on Windows. fstat() may fail with EOVERFLOW on files larger than 2 GB because the file size type is an signed 32-bit integer. files: Include/fileutils.h | 31 ++++- Modules/_io/fileio.c | 46 +++--- Modules/main.c | 5 +- Modules/mmapmodule.c | 8 +- Modules/posixmodule.c | 151 +++------------------- Modules/signalmodule.c | 7 +- Programs/_freeze_importlib.c | 4 +- Python/dynload_shlib.c | 4 +- Python/fileutils.c | 142 +++++++++++++++++++++- Python/marshal.c | 16 +- Python/random.c | 6 +- Python/sysmodule.c | 4 +- 12 files changed, 243 insertions(+), 181 deletions(-) diff --git a/Include/fileutils.h b/Include/fileutils.h --- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -21,11 +21,40 @@ struct stat *buf); #endif +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + +#ifdef MS_WINDOWS +struct _Py_stat_struct { + unsigned long st_dev; + __int64 st_ino; + unsigned short st_mode; + int st_nlink; + int st_uid; + int st_gid; + unsigned long st_rdev; + __int64 st_size; + time_t st_atime; + int st_atime_nsec; + time_t st_mtime; + int st_mtime_nsec; + time_t st_ctime; + int st_ctime_nsec; + unsigned long st_file_attributes; +}; +#else +# define _Py_stat_struct stat +#endif + +PyAPI_FUNC(int) _Py_fstat( + int fd, + struct _Py_stat_struct *stat); +#endif /* HAVE_FSTAT || MS_WINDOWS */ + #ifdef HAVE_STAT PyAPI_FUNC(int) _Py_stat( PyObject *path, struct stat *statbuf); -#endif +#endif /* HAVE_STAT */ #ifndef Py_LIMITED_API PyAPI_FUNC(int) _Py_open( diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -180,9 +180,9 @@ static int check_fd(int fd) { -#if defined(HAVE_FSTAT) - struct stat buf; - if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + struct _Py_stat_struct buf; + if (!_PyVerify_fd(fd) || (_Py_fstat(fd, &buf) < 0 && errno == EBADF)) { PyObject *exc; char *msg = strerror(EBADF); exc = PyObject_CallFunction(PyExc_OSError, "(is)", @@ -222,8 +222,8 @@ #elif !defined(MS_WINDOWS) int *atomic_flag_works = NULL; #endif -#ifdef HAVE_FSTAT - struct stat fdfstat; +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + struct _Py_stat_struct fdfstat; #endif int async_err = 0; @@ -420,9 +420,11 @@ } self->blksize = DEFAULT_BUFFER_SIZE; -#ifdef HAVE_FSTAT - if (fstat(self->fd, &fdfstat) < 0) +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + if (_Py_fstat(self->fd, &fdfstat) < 0) { + PyErr_SetFromErrno(PyExc_OSError); goto error; + } #if defined(S_ISDIR) && defined(EISDIR) /* On Unix, open will succeed for directories. In Python, there should be no file objects referring to @@ -437,7 +439,7 @@ if (fdfstat.st_blksize > 1) self->blksize = fdfstat.st_blksize; #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ -#endif /* HAVE_FSTAT */ +#endif /* HAVE_FSTAT || MS_WINDOWS */ #if defined(MS_WINDOWS) || defined(__CYGWIN__) /* don't translate newlines (\r\n <=> \n) */ @@ -603,17 +605,7 @@ return PyLong_FromSsize_t(n); } -#ifndef HAVE_FSTAT - -static PyObject * -fileio_readall(fileio *self) -{ - _Py_IDENTIFIER(readall); - return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, - &PyId_readall, "O", self); -} - -#else +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) static size_t new_buffersize(fileio *self, size_t currentsize) @@ -637,7 +629,7 @@ static PyObject * fileio_readall(fileio *self) { - struct stat st; + struct _Py_stat_struct st; Py_off_t pos, end; PyObject *result; Py_ssize_t bytes_read = 0; @@ -655,7 +647,7 @@ #else pos = lseek(self->fd, 0L, SEEK_CUR); #endif - if (fstat(self->fd, &st) == 0) + if (_Py_fstat(self->fd, &st) == 0) end = st.st_size; else end = (Py_off_t)-1; @@ -729,7 +721,17 @@ return result; } -#endif /* HAVE_FSTAT */ +#else + +static PyObject * +fileio_readall(fileio *self) +{ + _Py_IDENTIFIER(readall); + return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_readall, "O", self); +} + +#endif /* HAVE_FSTAT || MS_WINDOWS */ static PyObject * fileio_read(fileio *self, PyObject *args) diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -752,9 +752,8 @@ } } { - /* XXX: does this work on Win/Win64? (see posix_fstat) */ - struct stat sb; - if (fstat(fileno(fp), &sb) == 0 && + struct _Py_stat_struct sb; + if (_Py_fstat(fileno(fp), &sb) == 0 && S_ISDIR(sb.st_mode)) { fprintf(stderr, "%ls: '%ls' is a directory, cannot continue\n", argv[0], filename); fclose(fp); diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -459,8 +459,8 @@ #ifdef UNIX { - struct stat buf; - if (-1 == fstat(self->fd, &buf)) { + struct _Py_stat_struct buf; + if (-1 == _Py_fstat(self->fd, &buf)) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -1107,7 +1107,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) { #ifdef HAVE_FSTAT - struct stat st; + struct _Py_stat_struct st; #endif mmap_object *m_obj; PyObject *map_size_obj = NULL; @@ -1174,7 +1174,7 @@ (void)fcntl(fd, F_FULLFSYNC); #endif #ifdef HAVE_FSTAT - if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { + if (fd != -1 && _Py_fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { if (map_size == 0) { if (st.st_size == 0) { PyErr_SetString(PyExc_ValueError, diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -350,8 +350,8 @@ #ifdef MS_WINDOWS # define STAT win32_stat # define LSTAT win32_lstat -# define FSTAT win32_fstat -# define STRUCT_STAT struct win32_stat +# define FSTAT _Py_fstat +# define STRUCT_STAT struct _Py_stat_struct #else # define STAT stat # define LSTAT lstat @@ -1469,73 +1469,6 @@ unsigned long st_file_attributes; }; -static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ - -static void -FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) -{ - /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ - /* Cannot simply cast and dereference in_ptr, - since it might not be aligned properly */ - __int64 in; - memcpy(&in, in_ptr, sizeof(in)); - *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ - *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); -} - -static void -time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) -{ - /* XXX endianness */ - __int64 out; - out = time_in + secs_between_epochs; - out = out * 10000000 + nsec_in / 100; - memcpy(out_ptr, &out, sizeof(out)); -} - -/* Below, we *know* that ugo+r is 0444 */ -#if _S_IREAD != 0400 -#error Unsupported C library -#endif -static int -attributes_to_mode(DWORD attr) -{ - int m = 0; - if (attr & FILE_ATTRIBUTE_DIRECTORY) - m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */ - else - m |= _S_IFREG; - if (attr & FILE_ATTRIBUTE_READONLY) - m |= 0444; - else - m |= 0666; - return m; -} - -static int -attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct win32_stat *result) -{ - memset(result, 0, sizeof(*result)); - result->st_mode = attributes_to_mode(info->dwFileAttributes); - result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; - result->st_dev = info->dwVolumeSerialNumber; - result->st_rdev = result->st_dev; - FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); - result->st_nlink = info->nNumberOfLinks; - result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow; - if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { - /* first clear the S_IFMT bits */ - result->st_mode ^= (result->st_mode & S_IFMT); - /* now set the bits that make this a symlink */ - result->st_mode |= S_IFLNK; - } - result->st_file_attributes = info->dwFileAttributes; - - return 0; -} - static BOOL attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) { @@ -1645,11 +1578,15 @@ return TRUE; } -static int -win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, +/* defined in fileutils.c */ +int +attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result); + +static int +win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse); static int -win32_xstat_impl(const char *path, struct win32_stat *result, +win32_xstat_impl(const char *path, struct _Py_stat_struct *result, BOOL traverse) { int code; @@ -1745,7 +1682,7 @@ } static int -win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, +win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) { int code; @@ -1841,7 +1778,7 @@ } static int -win32_xstat(const char *path, struct win32_stat *result, BOOL traverse) +win32_xstat(const char *path, struct _Py_stat_struct *result, BOOL traverse) { /* Protocol violation: we explicitly clear errno, instead of setting it to a POSIX error. Callers should use GetLastError. */ @@ -1851,7 +1788,7 @@ } static int -win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse) +win32_xstat_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) { /* Protocol violation: we explicitly clear errno, instead of setting it to a POSIX error. Callers should use GetLastError. */ @@ -1873,80 +1810,29 @@ The _w represent Unicode equivalents of the aforementioned ANSI functions. */ static int -win32_lstat(const char* path, struct win32_stat *result) +win32_lstat(const char* path, struct _Py_stat_struct *result) { return win32_xstat(path, result, FALSE); } static int -win32_lstat_w(const wchar_t* path, struct win32_stat *result) +win32_lstat_w(const wchar_t* path, struct _Py_stat_struct *result) { return win32_xstat_w(path, result, FALSE); } static int -win32_stat(const char* path, struct win32_stat *result) +win32_stat(const char* path, struct _Py_stat_struct *result) { return win32_xstat(path, result, TRUE); } static int -win32_stat_w(const wchar_t* path, struct win32_stat *result) +win32_stat_w(const wchar_t* path, struct _Py_stat_struct *result) { return win32_xstat_w(path, result, TRUE); } -static int -win32_fstat(int file_number, struct win32_stat *result) -{ - BY_HANDLE_FILE_INFORMATION info; - HANDLE h; - int type; - - if (!_PyVerify_fd(file_number)) - h = INVALID_HANDLE_VALUE; - else - h = (HANDLE)_get_osfhandle(file_number); - - /* Protocol violation: we explicitly clear errno, instead of - setting it to a POSIX error. Callers should use GetLastError. */ - errno = 0; - - if (h == INVALID_HANDLE_VALUE) { - /* This is really a C library error (invalid file handle). - We set the Win32 error to the closes one matching. */ - SetLastError(ERROR_INVALID_HANDLE); - return -1; - } - memset(result, 0, sizeof(*result)); - - type = GetFileType(h); - if (type == FILE_TYPE_UNKNOWN) { - DWORD error = GetLastError(); - if (error != 0) { - return -1; - } - /* else: valid but unknown file */ - } - - if (type != FILE_TYPE_DISK) { - if (type == FILE_TYPE_CHAR) - result->st_mode = _S_IFCHR; - else if (type == FILE_TYPE_PIPE) - result->st_mode = _S_IFIFO; - return 0; - } - - if (!GetFileInformationByHandle(h, &info)) { - return -1; - } - - attribute_data_to_stat(&info, 0, result); - /* specific to fstat() */ - result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; - return 0; -} - #endif /* MS_WINDOWS */ PyDoc_STRVAR(stat_result__doc__, @@ -6333,6 +6219,11 @@ return return_value; } +#ifdef MS_WINDOWS +void +time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr); +#endif + static PyObject * os_utime_impl(PyModuleDef *module, path_t *path, PyObject *times, PyObject *ns, int dir_fd, int follow_symlinks) /*[clinic end generated code: output=891489c35cc68c5d input=1f18c17d5941aa82]*/ diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -503,13 +503,13 @@ static PyObject * signal_set_wakeup_fd(PyObject *self, PyObject *args) { + struct _Py_stat_struct st; #ifdef MS_WINDOWS PyObject *fdobj; SOCKET_T sockfd, old_sockfd; int res; int res_size = sizeof res; PyObject *mod; - struct stat st; int is_socket; if (!PyArg_ParseTuple(args, "O:set_wakeup_fd", &fdobj)) @@ -520,7 +520,6 @@ return NULL; #else int fd, old_fd; - struct stat st; if (!PyArg_ParseTuple(args, "i:set_wakeup_fd", &fd)) return NULL; @@ -560,7 +559,7 @@ return NULL; } - if (fstat(fd, &st) != 0) { + if (_Py_fstat(fd, &st) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -592,7 +591,7 @@ return NULL; } - if (fstat(fd, &st) != 0) { + if (_Py_fstat(fd, &st) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c --- a/Programs/_freeze_importlib.c +++ b/Programs/_freeze_importlib.c @@ -35,7 +35,7 @@ { char *inpath, *outpath; FILE *infile = NULL, *outfile = NULL; - struct stat st; + struct _Py_stat_struct st; size_t text_size, data_size, n; char *text = NULL; unsigned char *data; @@ -54,7 +54,7 @@ fprintf(stderr, "cannot open '%s' for reading\n", inpath); goto error; } - if (fstat(fileno(infile), &st)) { + if (_Py_fstat(fileno(infile), &st)) { fprintf(stderr, "cannot fstat '%s'\n", inpath); goto error; } diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -71,8 +71,8 @@ if (fp != NULL) { int i; - struct stat statb; - if (fstat(fileno(fp), &statb) == -1) { + struct _Py_stat_struct statb; + if (_Py_fstat(fileno(fp), &statb) == -1) { PyErr_SetFromErrno(PyExc_IOError); return NULL; } diff --git a/Python/fileutils.c b/Python/fileutils.c --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -544,8 +544,145 @@ } #endif + +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + +#ifdef MS_WINDOWS +static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ + +static void +FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) +{ + /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ + /* Cannot simply cast and dereference in_ptr, + since it might not be aligned properly */ + __int64 in; + memcpy(&in, in_ptr, sizeof(in)); + *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ + *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); +} + +void +time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) +{ + /* XXX endianness */ + __int64 out; + out = time_in + secs_between_epochs; + out = out * 10000000 + nsec_in / 100; + memcpy(out_ptr, &out, sizeof(out)); +} + +/* Below, we *know* that ugo+r is 0444 */ +#if _S_IREAD != 0400 +#error Unsupported C library +#endif +static int +attributes_to_mode(DWORD attr) +{ + int m = 0; + if (attr & FILE_ATTRIBUTE_DIRECTORY) + m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */ + else + m |= _S_IFREG; + if (attr & FILE_ATTRIBUTE_READONLY) + m |= 0444; + else + m |= 0666; + return m; +} + +int +attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result) +{ + memset(result, 0, sizeof(*result)); + result->st_mode = attributes_to_mode(info->dwFileAttributes); + result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; + result->st_dev = info->dwVolumeSerialNumber; + result->st_rdev = result->st_dev; + FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_nlink = info->nNumberOfLinks; + result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow; + if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { + /* first clear the S_IFMT bits */ + result->st_mode ^= (result->st_mode & S_IFMT); + /* now set the bits that make this a symlink */ + result->st_mode |= S_IFLNK; + } + result->st_file_attributes = info->dwFileAttributes; + + return 0; +} +#endif + +/* Return information about a file. + + On POSIX, use fstat(). + + On Windows, use GetFileType() and GetFileInformationByHandle() which support + files larger than 2 GB. fstat() may fail with EOVERFLOW on files larger + than 2 GB because the file size type is an signed 32-bit integer: see issue + #23152. + */ +int +_Py_fstat(int fd, struct _Py_stat_struct *result) +{ +#ifdef MS_WINDOWS + BY_HANDLE_FILE_INFORMATION info; + HANDLE h; + int type; + + if (!_PyVerify_fd(fd)) + h = INVALID_HANDLE_VALUE; + else + h = (HANDLE)_get_osfhandle(fd); + + /* Protocol violation: we explicitly clear errno, instead of + setting it to a POSIX error. Callers should use GetLastError. */ + errno = 0; + + if (h == INVALID_HANDLE_VALUE) { + /* This is really a C library error (invalid file handle). + We set the Win32 error to the closes one matching. */ + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + memset(result, 0, sizeof(*result)); + + type = GetFileType(h); + if (type == FILE_TYPE_UNKNOWN) { + DWORD error = GetLastError(); + if (error != 0) { + return -1; + } + /* else: valid but unknown file */ + } + + if (type != FILE_TYPE_DISK) { + if (type == FILE_TYPE_CHAR) + result->st_mode = _S_IFCHR; + else if (type == FILE_TYPE_PIPE) + result->st_mode = _S_IFIFO; + return 0; + } + + if (!GetFileInformationByHandle(h, &info)) { + return -1; + } + + attribute_data_to_stat(&info, 0, result); + /* specific to fstat() */ + result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; + return 0; +#else + return fstat(fd, result); +#endif +} +#endif /* HAVE_FSTAT || MS_WINDOWS */ + + #ifdef HAVE_STAT - /* Call _wstat() on Windows, or encode the path to the filesystem encoding and call stat() otherwise. Only fill st_mode attribute on Windows. @@ -578,7 +715,8 @@ #endif } -#endif +#endif /* HAVE_STAT */ + static int get_inheritable(int fd, int raise) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1481,16 +1481,20 @@ return res; } -#ifdef HAVE_FSTAT -/* Return size of file in bytes; < 0 if unknown. */ +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) +/* Return size of file in bytes; < 0 if unknown or INT_MAX if too big */ static off_t getfilesize(FILE *fp) { - struct stat st; - if (fstat(fileno(fp), &st) != 0) + struct _Py_stat_struct st; + if (_Py_fstat(fileno(fp), &st) != 0) return -1; +#if SIZEOF_OFF_T == 4 + else if (st.st_size >= INT_MAX) + return (off_t)INT_MAX; +#endif else - return st.st_size; + return (off_t)st.st_size; } #endif @@ -1505,7 +1509,7 @@ { /* REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. */ #define REASONABLE_FILE_LIMIT (1L << 18) -#ifdef HAVE_FSTAT +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) off_t filesize; filesize = getfilesize(fp); if (filesize > 0 && filesize <= REASONABLE_FILE_LIMIT) { diff --git a/Python/random.c b/Python/random.c --- a/Python/random.c +++ b/Python/random.c @@ -139,14 +139,14 @@ { int fd; Py_ssize_t n; - struct stat st; + struct _Py_stat_struct st; if (size <= 0) return 0; if (urandom_cache.fd >= 0) { /* Does the fd point to the same thing as before? (issue #21207) */ - if (fstat(urandom_cache.fd, &st) + if (_Py_fstat(urandom_cache.fd, &st) || st.st_dev != urandom_cache.st_dev || st.st_ino != urandom_cache.st_ino) { /* Something changed: forget the cached fd (but don't close it, @@ -178,7 +178,7 @@ fd = urandom_cache.fd; } else { - if (fstat(fd, &st)) { + if (_Py_fstat(fd, &st)) { PyErr_SetFromErrno(PyExc_OSError); close(fd); return -1; diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1681,8 +1681,8 @@ the shell already prevents that. */ #if !defined(MS_WINDOWS) { - struct stat sb; - if (fstat(fileno(stdin), &sb) == 0 && + struct _Py_stat_struct sb; + if (_Py_fstat(fileno(stdin), &sb) == 0 && S_ISDIR(sb.st_mode)) { /* There's nothing more we can do. */ /* Py_FatalError() will core dump, so just exit. */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 18:57:14 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 21 Feb 2015 17:57:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyMTEz?= =?utf-8?q?=3A_struct=2Epack=5Finto=28=29_now_supports_new_buffer_protocol?= =?utf-8?q?_=28in?= Message-ID: <20150221175714.99237.84339@psf.io> https://hg.python.org/cpython/rev/4d8e37e54a7d changeset: 94719:4d8e37e54a7d branch: 2.7 parent: 94715:5387095b8675 user: Serhiy Storchaka date: Sat Feb 21 19:51:17 2015 +0200 summary: Issue #22113: struct.pack_into() now supports new buffer protocol (in particular accepts writable memoryview). files: Lib/test/test_struct.py | 19 ++++++++++++++----- Misc/NEWS | 3 +++ Modules/_struct.c | 22 ++++++++++++---------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -433,24 +433,24 @@ self.assertRaises(struct.error, s.unpack_from, data, i) self.assertRaises(struct.error, struct.unpack_from, fmt, data, i) - def test_pack_into(self): + def test_pack_into(self, cls=bytearray, tobytes=str): test_string = 'Reykjavik rocks, eow!' - writable_buf = array.array('c', ' '*100) + writable_buf = cls(' '*100) fmt = '21s' s = struct.Struct(fmt) # Test without offset s.pack_into(writable_buf, 0, test_string) - from_buf = writable_buf.tostring()[:len(test_string)] + from_buf = tobytes(writable_buf)[:len(test_string)] self.assertEqual(from_buf, test_string) # Test with offset. s.pack_into(writable_buf, 10, test_string) - from_buf = writable_buf.tostring()[:len(test_string)+10] + from_buf = tobytes(writable_buf)[:len(test_string)+10] self.assertEqual(from_buf, test_string[:10] + test_string) # Go beyond boundaries. - small_buf = array.array('c', ' '*10) + small_buf = cls(' '*10) self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0, test_string) self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2, @@ -461,6 +461,15 @@ self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb, None) + def test_pack_into_array(self): + self.test_pack_into(cls=lambda b: array.array('c', b), + tobytes=array.array.tostring) + + def test_pack_into_memoryview(self): + # Issue #22113 + self.test_pack_into(cls=lambda b: memoryview(bytearray(b)), + tobytes=memoryview.tobytes) + def test_pack_into_fn(self): test_string = 'Reykjavik rocks, eow!' writable_buf = array.array('c', ' '*100) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #22113: struct.pack_into() now supports new buffer protocol (in + particular accepts writable memoryview). + - Issues #814253, #9179: Warnings now are raised when group references and conditional group references are used in lookbehind assertions in regular expressions. diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1657,8 +1657,8 @@ s_pack_into(PyObject *self, PyObject *args) { PyStructObject *soself; - char *buffer; - Py_ssize_t buffer_len, offset; + Py_buffer buf; + Py_ssize_t offset; /* Validate arguments. +1 is for the first arg as buffer. */ soself = (PyStructObject *)self; @@ -1683,33 +1683,35 @@ } /* Extract a writable memory buffer from the first argument */ - if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0), - (void**)&buffer, &buffer_len) == -1 ) { + if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buf)) return NULL; - } - assert( buffer_len >= 0 ); /* Extract the offset from the first argument */ offset = PyInt_AsSsize_t(PyTuple_GET_ITEM(args, 1)); - if (offset == -1 && PyErr_Occurred()) + if (offset == -1 && PyErr_Occurred()) { + PyBuffer_Release(&buf); return NULL; + } /* Support negative offsets. */ if (offset < 0) - offset += buffer_len; + offset += buf.len; /* Check boundaries */ - if (offset < 0 || (buffer_len - offset) < soself->s_size) { + if (offset < 0 || (buf.len - offset) < soself->s_size) { PyErr_Format(StructError, "pack_into requires a buffer of at least %zd bytes", soself->s_size); + PyBuffer_Release(&buf); return NULL; } /* Call the guts */ - if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) { + if (s_pack_internal(soself, args, 2, (char *)buf.buf + offset) != 0) { + PyBuffer_Release(&buf); return NULL; } + PyBuffer_Release(&buf); Py_RETURN_NONE; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 21 19:04:24 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 21 Feb 2015 18:04:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323152=3A_Renames_?= =?utf-8?q?attribute=5Fdata=5Fto=5Fstat_to_=5FPy=5Fattribute=5Fdata=5Fto?= =?utf-8?q?=5Fstat?= Message-ID: <20150221180424.3865.41447@psf.io> https://hg.python.org/cpython/rev/307713759a62 changeset: 94720:307713759a62 parent: 94718:4f6f4aa0d80f user: Steve Dower date: Sat Feb 21 10:04:10 2015 -0800 summary: Issue #23152: Renames attribute_data_to_stat to _Py_attribute_data_to_stat files: Modules/posixmodule.c | 6 +++--- Python/fileutils.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1580,7 +1580,7 @@ /* defined in fileutils.c */ int -attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result); +_Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result); static int win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, @@ -1669,7 +1669,7 @@ } else CloseHandle(hFile); } - attribute_data_to_stat(&info, reparse_tag, result); + _Py_attribute_data_to_stat(&info, reparse_tag, result); /* Set S_IEXEC if it is an .exe, .bat, ... */ dot = strrchr(path, '.'); @@ -1765,7 +1765,7 @@ } else CloseHandle(hFile); } - attribute_data_to_stat(&info, reparse_tag, result); + _Py_attribute_data_to_stat(&info, reparse_tag, result); /* Set S_IEXEC if it is an .exe, .bat, ... */ dot = wcsrchr(path, '.'); diff --git a/Python/fileutils.c b/Python/fileutils.c --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -592,7 +592,7 @@ } int -attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result) +_Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result) { memset(result, 0, sizeof(*result)); result->st_mode = attributes_to_mode(info->dwFileAttributes); @@ -671,7 +671,7 @@ return -1; } - attribute_data_to_stat(&info, 0, result); + _Py_attribute_data_to_stat(&info, 0, result); /* specific to fstat() */ result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; return 0; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 00:30:38 2015 From: python-checkins at python.org (steve.dower) Date: Sat, 21 Feb 2015 23:30:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323152=3A_Renames_?= =?utf-8?b?dGltZV90X3RvX0ZJTEVfVElNRSB0byBfUHlfdGltZV90X3RvX0ZJTEVfVElN?= =?utf-8?q?E=2C_removes?= Message-ID: <20150221233038.109528.8737@psf.io> https://hg.python.org/cpython/rev/a824c40e8fc0 changeset: 94721:a824c40e8fc0 user: Steve Dower date: Sat Feb 21 15:26:02 2015 -0800 summary: Issue #23152: Renames time_t_to_FILE_TIME to _Py_time_t_to_FILE_TIME, removes unused struct win32_stat and return value files: Modules/posixmodule.c | 26 ++++---------------------- Python/fileutils.c | 6 ++---- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1451,24 +1451,6 @@ #define HAVE_STAT_NSEC 1 #define HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES 1 -struct win32_stat{ - unsigned long st_dev; - __int64 st_ino; - unsigned short st_mode; - int st_nlink; - int st_uid; - int st_gid; - unsigned long st_rdev; - __int64 st_size; - time_t st_atime; - int st_atime_nsec; - time_t st_mtime; - int st_mtime_nsec; - time_t st_ctime; - int st_ctime_nsec; - unsigned long st_file_attributes; -}; - static BOOL attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) { @@ -1579,7 +1561,7 @@ } /* defined in fileutils.c */ -int +void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result); static int @@ -6221,7 +6203,7 @@ #ifdef MS_WINDOWS void -time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr); +_Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr); #endif static PyObject * @@ -6327,8 +6309,8 @@ atime = mtime; } else { - time_t_to_FILE_TIME(utime.atime_s, utime.atime_ns, &atime); - time_t_to_FILE_TIME(utime.mtime_s, utime.mtime_ns, &mtime); + _Py_time_t_to_FILE_TIME(utime.atime_s, utime.atime_ns, &atime); + _Py_time_t_to_FILE_TIME(utime.mtime_s, utime.mtime_ns, &mtime); } if (!SetFileTime(hFile, NULL, &atime, &mtime)) { /* Avoid putting the file name into the error here, diff --git a/Python/fileutils.c b/Python/fileutils.c --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -563,7 +563,7 @@ } void -time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) +_Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { /* XXX endianness */ __int64 out; @@ -591,7 +591,7 @@ return m; } -int +void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result) { memset(result, 0, sizeof(*result)); @@ -611,8 +611,6 @@ result->st_mode |= S_IFLNK; } result->st_file_attributes = info->dwFileAttributes; - - return 0; } #endif -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Feb 22 13:27:29 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 22 Feb 2015 13:27:29 +0100 Subject: [Python-checkins] Daily reference leaks (a824c40e8fc0): sum=3 Message-ID: results for a824c40e8fc0 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog23GgK0', '-x'] From solipsis at pitrou.net Sun Feb 22 13:29:01 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 22 Feb 2015 13:29:01 +0100 Subject: [Python-checkins] Daily reference leaks (5620691ce26b): sum=0 Message-ID: results for 5620691ce26b on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog9EsCAO', '-x'] From python-checkins at python.org Sun Feb 22 15:47:20 2015 From: python-checkins at python.org (nick.coghlan) Date: Sun, 22 Feb 2015 14:47:20 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_422=3A_Rename_init=5Fclas?= =?utf-8?q?s_as_autodecorate?= Message-ID: <20150222144719.14035.4734@psf.io> https://hg.python.org/peps/rev/0ca7ce244d19 changeset: 5701:0ca7ce244d19 user: Nick Coghlan date: Mon Feb 23 00:47:12 2015 +1000 summary: PEP 422: Rename init_class as autodecorate files: pep-0422.txt | 88 +++++++++++++++++++++++++++++---------- 1 files changed, 64 insertions(+), 24 deletions(-) diff --git a/pep-0422.txt b/pep-0422.txt --- a/pep-0422.txt +++ b/pep-0422.txt @@ -21,9 +21,9 @@ This PEP proposes to instead support a wide range of customisation scenarios through a new ``namespace`` parameter in the class header, and -a new ``__init_class__`` hook in the class body. +a new ``__autodecorate__`` hook in the class body. -The new mechanism is also much easier to understand and use than +The new mechanism should be easier to understand and use than implementing a custom metaclass, and thus should provide a gentler introduction to the full power Python's metaclass machinery. @@ -109,16 +109,16 @@ but potentially without the full flexibility of the Python 2 style ``__metaclass__`` hook -One mechanism that can achieve this goal is to add a new class -initialisation hook, modelled directly on the existing instance -initialisation hook, but with the signature constrained to match that -of an ordinary class decorator. +One mechanism that can achieve this goal is to add a new implicit class +decoration hook, modelled directly on the existing explicit class +decorators, but defined in the class body or in a parent class, rather than +being part of the class definition header. Specifically, it is proposed that class definitions be able to provide a class initialisation hook as follows:: class Example: - def __init_class__(cls): + def __autodecorate__(cls): # This is invoked after the class is created, but before any # explicit decorators are called # The usual super() mechanisms are used to correctly support @@ -128,14 +128,14 @@ If present on the created object, this new hook will be called by the class creation machinery *after* the ``__class__`` reference has been initialised. For ``types.new_class()``, it will be called as the last step before -returning the created class object. ``__init_class__`` is implicitly +returning the created class object. ``__autodecorate__`` is implicitly converted to a class method when the class is created (prior to the hook being invoked). -If a metaclass wishes to block class initialisation for some reason, it -must arrange for ``cls.__init_class__`` to trigger ``AttributeError``. +If a metaclass wishes to block implicit class decoration for some reason, it +must arrange for ``cls.__autodecorate__`` to trigger ``AttributeError``. -Note, that when ``__init_class__`` is called, the name of the class is not +Note, that when ``__autodecorate__`` is called, the name of the class is not yet bound to the new class object. As a consequence, the two argument form of ``super()`` cannot be used to call methods (e.g., ``super(Example, cls)`` wouldn't work in the example above). However, the zero argument form of @@ -158,7 +158,7 @@ an ordered dictionary as the class namespace:: class OrderedExample(namespace=collections.OrderedDict): - def __init_class__(cls): + def __autodecorate__(cls): # cls.__dict__ is still a read-only proxy to the class namespace, # but the underlying storage is an OrderedDict instance @@ -220,12 +220,12 @@ parents of a class definition. This risk also makes it very difficult to *add* a metaclass to a class that has previously been published without one. -By contrast, adding an ``__init_class__`` method to an existing type poses +By contrast, adding an ``__autodecorate__`` method to an existing type poses a similar level of risk to adding an ``__init__`` method: technically, there is a risk of breaking poorly implemented subclasses, but when that occurs, it is recognised as a bug in the subclass rather than the library author breaching backwards compatibility guarantees. In fact, due to the constrained -signature of ``__init_class__``, the risk in this case is actually even +signature of ``__autodecorate__``, the risk in this case is actually even lower than in the case of ``__init__``. @@ -243,11 +243,33 @@ For use cases that don't involve completely replacing the defined class, Python 2 code that dynamically set ``__metaclass__`` can now dynamically -set ``__init_class__`` instead. For more advanced use cases, introduction of +set ``__autodecorate__`` instead. For more advanced use cases, introduction of an explicit metaclass (possibly made available as a required base class) will still be necessary in order to support Python 3. +Design Notes +============ + + +Determining if the class being decorated is the base class +---------------------------------------------------------- + +In the body of an ``__autodecorate__`` method, as in any other class method, +``__class__`` will be bound to the class declaring the method, while the +value passed in may be a subclass. + +This makes it relatively straightforward to skip processing the base class +if necessary:: + + class Example: + def __autodecorate__(cls): + # Don't process the base class + if cls is __class__: + return + # Process subclasses here + + New Ways of Using Classes ========================= @@ -354,21 +376,39 @@ ======================= -Calling ``__init_class__`` from ``type.__init__`` -------------------------------------------------- +Calling ``__autodecorate__`` from ``type.__init__`` +--------------------------------------------------- Calling the new hook automatically from ``type.__init__``, would achieve most of the goals of this PEP. However, using that approach would mean that -``__init_class__`` implementations would be unable to call any methods that +``__autodecorate__`` implementations would be unable to call any methods that relied on the ``__class__`` reference (or used the zero-argument form of ``super()``), and could not make use of those features themselves. -Requiring an explict decorator on ``__init_class__`` ----------------------------------------------------- +Calling the automatic decoration hook ``__init_class__`` +-------------------------------------------------------- + +Earlier versions of the PEP used the name ``__init_class__`` for the name +of the new hook. There were three significant problems with this name: + +* it was hard to remember if the correct spelling was ``__init_class__`` or + ``__class_init__`` +* the use of "init" in the name suggested the signature should match that + of ``type.__init__``, which is not the case +* the use of "init" in the name suggested the method would be run as part + of class construction, which is not the case + +The new name ``__autodecorate__`` was chosen to make it clear that the new +initialisation hook is most usefully thought of as an implicitly invoked +class decorator, rather than as being like an ``__init__`` method. + + +Requiring an explicit decorator on ``__autodecorate__`` +------------------------------------------------------- Originally, this PEP required the explicit use of ``@classmethod`` on the -``__init_class__`` decorator. It was made implicit since there's no +``__autodecorate__`` decorator. It was made implicit since there's no sensible interpretation for leaving it out, and that case would need to be detected anyway in order to give a useful error message. @@ -393,9 +433,9 @@ Reference Implementation ======================== -A reference implementation for __init_class__ has been posted to the -`issue tracker`_. It does not yet include the new ``namespace`` parameter -for ``type.__prepare__``. +A reference implementation for ``__autodecorate__`` has been posted to the +`issue tracker`_. It uses the original ``__init_class__`` naming and does +not yet include the new ``namespace`` parameter for ``type.__prepare__``. TODO ==== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Feb 22 16:15:06 2015 From: python-checkins at python.org (nick.coghlan) Date: Sun, 22 Feb 2015 15:15:06 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_422=3A_Update_Deferral_no?= =?utf-8?q?te_=26_other_tweaks?= Message-ID: <20150222151505.109528.37899@psf.io> https://hg.python.org/peps/rev/ef12b7584922 changeset: 5702:ef12b7584922 user: Nick Coghlan date: Mon Feb 23 01:14:58 2015 +1000 summary: PEP 422: Update Deferral note & other tweaks files: pep-0422.txt | 21 +++++++++++++++------ 1 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pep-0422.txt b/pep-0422.txt --- a/pep-0422.txt +++ b/pep-0422.txt @@ -27,12 +27,17 @@ implementing a custom metaclass, and thus should provide a gentler introduction to the full power Python's metaclass machinery. + PEP Deferral ============ -Deferred until 3.5 at the earliest. The last review raised a few interesting -points that I (Nick) need to consider further before proposing it for -inclusion, and that's not going to happen in the 3.4 timeframe. +Currently deferred pending updates to address feedback received prior to the +Python 3.4 release (see TODO note below). + +Note that I'd be open to relinquishing the PEP to a new champion if anyone +would like to propose it for Python 3.5 (while I've made a few updates to +the design recently it doesn't currently look like I will be in a position +to push it forward myself in the 3.5 time frame). Background @@ -204,7 +209,7 @@ stated "subclass of type" for a constraint that is actually "instance of type". -Understanding the proposed class initialisation hook only requires +Understanding the proposed implicit class decoration hook only requires understanding decorators and ordinary method inheritance, which isn't quite as daunting a task. The new hook provides a more gradual path towards understanding all of the phases involved in the class definition @@ -268,6 +273,7 @@ if cls is __class__: return # Process subclasses here + ... New Ways of Using Classes @@ -330,7 +336,7 @@ Extending a class ----------------- -.. note:: Just because the PEP makes it *possible* to do this relatively, +.. note:: Just because the PEP makes it *possible* to do this relatively cleanly doesn't mean anyone *should* do this! :: @@ -385,6 +391,9 @@ relied on the ``__class__`` reference (or used the zero-argument form of ``super()``), and could not make use of those features themselves. +The current design instead ensures that the implicit decorator hook is able +to do anything an explicit decorator can do by running it after the initial +class creation is already complete. Calling the automatic decoration hook ``__init_class__`` -------------------------------------------------------- @@ -397,7 +406,7 @@ * the use of "init" in the name suggested the signature should match that of ``type.__init__``, which is not the case * the use of "init" in the name suggested the method would be run as part - of class construction, which is not the case + of initial class object creation, which is not the case The new name ``__autodecorate__`` was chosen to make it clear that the new initialisation hook is most usefully thought of as an implicitly invoked -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Feb 22 16:28:05 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 15:28:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzY2Mzk6?= =?utf-8?q?_Module-level_turtle_functions_no_longer_raise_TclError_after?= Message-ID: <20150222152805.6722.40400@psf.io> https://hg.python.org/cpython/rev/1628484c9408 changeset: 94723:1628484c9408 branch: 3.4 parent: 94716:e295ad9be16d user: Serhiy Storchaka date: Sun Feb 22 17:25:33 2015 +0200 summary: Issue #6639: Module-level turtle functions no longer raise TclError after closing the window. files: Lib/turtle.py | 69 ++++++++++++------------- Lib/turtledemo/__main__.py | 4 + Misc/NEWS | 3 + 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/Lib/turtle.py b/Lib/turtle.py --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -1288,7 +1288,7 @@ def _incrementudc(self): """Increment update counter.""" if not TurtleScreen._RUNNING: - TurtleScreen._RUNNNING = True + TurtleScreen._RUNNING = True raise Terminator if self._tracing > 0: self._updatecounter += 1 @@ -3754,7 +3754,7 @@ Turtle._screen = None _Screen._root = None _Screen._canvas = None - TurtleScreen._RUNNING = True + TurtleScreen._RUNNING = False root.destroy() def bye(self): @@ -3795,7 +3795,6 @@ except AttributeError: exit(0) - class Turtle(RawTurtle): """RawTurtle auto-creating (scrolled) canvas. @@ -3818,18 +3817,6 @@ Pen = Turtle -def _getpen(): - """Create the 'anonymous' turtle if not already present.""" - if Turtle._pen is None: - Turtle._pen = Turtle() - return Turtle._pen - -def _getscreen(): - """Create a TurtleScreen if not already present.""" - if Turtle._screen is None: - Turtle._screen = Screen() - return Turtle._screen - def write_docstringdict(filename="turtle_docstringdict"): """Create and write docstring-dictionary to file. @@ -3952,26 +3939,38 @@ ## as functions. So we can enhance, change, add, delete methods to these ## classes and do not need to change anything here. - -for methodname in _tg_screen_functions: - pl1, pl2 = getmethparlist(eval('_Screen.' + methodname)) - if pl1 == "": - print(">>>>>>", pl1, pl2) - continue - defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec(defstr) - eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__) - -for methodname in _tg_turtle_functions: - pl1, pl2 = getmethparlist(eval('Turtle.' + methodname)) - if pl1 == "": - print(">>>>>>", pl1, pl2) - continue - defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec(defstr) - eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__) +__func_body = """\ +def {name}{paramslist}: + if {obj} is None: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + {obj} = {init} + try: + return {obj}.{name}{argslist} + except TK.TclError: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + raise +""" + +def _make_global_funcs(functions, cls, obj, init, docrevise): + for methodname in functions: + method = getattr(cls, methodname) + pl1, pl2 = getmethparlist(method) + if pl1 == "": + print(">>>>>>", pl1, pl2) + continue + defstr = __func_body.format(obj=obj, init=init, name=methodname, + paramslist=pl1, argslist=pl2) + exec(defstr, globals()) + globals()[methodname].__doc__ = docrevise(method.__doc__) + +_make_global_funcs(_tg_screen_functions, _Screen, + 'Turtle._screen', 'Screen()', _screen_docrevise) +_make_global_funcs(_tg_turtle_functions, Turtle, + 'Turtle._pen', 'Turtle()', _turtle_docrevise) done = mainloop diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -344,6 +344,8 @@ else: self.state = DONE except turtle.Terminator: + if self.root is None: + return self.state = DONE result = "stopped!" if self.state == DONE: @@ -369,7 +371,9 @@ turtle.TurtleScreen._RUNNING = False def _destroy(self): + turtle.TurtleScreen._RUNNING = False self.root.destroy() + self.root = None def main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #6639: Module-level turtle functions no longer raise TclError after + closing the window. + - Issues #814253, #9179: Warnings now are raised when group references and conditional group references are used in lookbehind assertions in regular expressions. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 16:28:06 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 15:28:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=236639=3A_Module-level_turtle_functions_no_longer?= =?utf-8?q?_raise_TclError_after?= Message-ID: <20150222152805.99402.20387@psf.io> https://hg.python.org/cpython/rev/d8e494986caf changeset: 94724:d8e494986caf parent: 94721:a824c40e8fc0 parent: 94723:1628484c9408 user: Serhiy Storchaka date: Sun Feb 22 17:26:35 2015 +0200 summary: Issue #6639: Module-level turtle functions no longer raise TclError after closing the window. files: Lib/turtle.py | 69 ++++++++++++------------- Lib/turtledemo/__main__.py | 4 + Misc/NEWS | 3 + 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/Lib/turtle.py b/Lib/turtle.py --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -1288,7 +1288,7 @@ def _incrementudc(self): """Increment update counter.""" if not TurtleScreen._RUNNING: - TurtleScreen._RUNNNING = True + TurtleScreen._RUNNING = True raise Terminator if self._tracing > 0: self._updatecounter += 1 @@ -3754,7 +3754,7 @@ Turtle._screen = None _Screen._root = None _Screen._canvas = None - TurtleScreen._RUNNING = True + TurtleScreen._RUNNING = False root.destroy() def bye(self): @@ -3795,7 +3795,6 @@ except AttributeError: exit(0) - class Turtle(RawTurtle): """RawTurtle auto-creating (scrolled) canvas. @@ -3818,18 +3817,6 @@ Pen = Turtle -def _getpen(): - """Create the 'anonymous' turtle if not already present.""" - if Turtle._pen is None: - Turtle._pen = Turtle() - return Turtle._pen - -def _getscreen(): - """Create a TurtleScreen if not already present.""" - if Turtle._screen is None: - Turtle._screen = Screen() - return Turtle._screen - def write_docstringdict(filename="turtle_docstringdict"): """Create and write docstring-dictionary to file. @@ -3952,26 +3939,38 @@ ## as functions. So we can enhance, change, add, delete methods to these ## classes and do not need to change anything here. - -for methodname in _tg_screen_functions: - pl1, pl2 = getmethparlist(eval('_Screen.' + methodname)) - if pl1 == "": - print(">>>>>>", pl1, pl2) - continue - defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec(defstr) - eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__) - -for methodname in _tg_turtle_functions: - pl1, pl2 = getmethparlist(eval('Turtle.' + methodname)) - if pl1 == "": - print(">>>>>>", pl1, pl2) - continue - defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec(defstr) - eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__) +__func_body = """\ +def {name}{paramslist}: + if {obj} is None: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + {obj} = {init} + try: + return {obj}.{name}{argslist} + except TK.TclError: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + raise +""" + +def _make_global_funcs(functions, cls, obj, init, docrevise): + for methodname in functions: + method = getattr(cls, methodname) + pl1, pl2 = getmethparlist(method) + if pl1 == "": + print(">>>>>>", pl1, pl2) + continue + defstr = __func_body.format(obj=obj, init=init, name=methodname, + paramslist=pl1, argslist=pl2) + exec(defstr, globals()) + globals()[methodname].__doc__ = docrevise(method.__doc__) + +_make_global_funcs(_tg_screen_functions, _Screen, + 'Turtle._screen', 'Screen()', _screen_docrevise) +_make_global_funcs(_tg_turtle_functions, Turtle, + 'Turtle._pen', 'Turtle()', _turtle_docrevise) done = mainloop diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py old mode 100755 new mode 100644 --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -344,6 +344,8 @@ else: self.state = DONE except turtle.Terminator: + if self.root is None: + return self.state = DONE result = "stopped!" if self.state == DONE: @@ -369,7 +371,9 @@ turtle.TurtleScreen._RUNNING = False def _destroy(self): + turtle.TurtleScreen._RUNNING = False self.root.destroy() + self.root = None def main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #6639: Module-level turtle functions no longer raise TclError after + closing the window. + - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 16:28:06 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 15:28:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzY2Mzk6?= =?utf-8?q?_Module-level_turtle_functions_no_longer_raise_TclError_after?= Message-ID: <20150222152805.109561.1755@psf.io> https://hg.python.org/cpython/rev/15dd9d6cc632 changeset: 94722:15dd9d6cc632 branch: 2.7 parent: 94719:4d8e37e54a7d user: Serhiy Storchaka date: Sun Feb 22 17:22:53 2015 +0200 summary: Issue #6639: Module-level turtle functions no longer raise TclError after closing the window. files: Demo/turtle/turtleDemo.py | 4 + Lib/lib-tk/turtle.py | 70 +++++++++++++------------- Misc/NEWS | 3 + 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/Demo/turtle/turtleDemo.py b/Demo/turtle/turtleDemo.py --- a/Demo/turtle/turtleDemo.py +++ b/Demo/turtle/turtleDemo.py @@ -231,6 +231,8 @@ else: self.state = DONE except turtle.Terminator: + if self.root is None: + return self.state = DONE result = "stopped!" if self.state == DONE: @@ -257,7 +259,9 @@ turtle.TurtleScreen._RUNNING = False def _destroy(self): + turtle.TurtleScreen._RUNNING = False self.root.destroy() + self.root = None #sys.exit() def main(): diff --git a/Lib/lib-tk/turtle.py b/Lib/lib-tk/turtle.py --- a/Lib/lib-tk/turtle.py +++ b/Lib/lib-tk/turtle.py @@ -1235,7 +1235,7 @@ def _incrementudc(self): """Increment update counter.""" if not TurtleScreen._RUNNING: - TurtleScreen._RUNNNING = True + TurtleScreen._RUNNING = True raise Terminator if self._tracing > 0: self._updatecounter += 1 @@ -3644,7 +3644,7 @@ Turtle._screen = None _Screen._root = None _Screen._canvas = None - TurtleScreen._RUNNING = True + TurtleScreen._RUNNING = False root.destroy() def bye(self): @@ -3685,7 +3685,6 @@ except AttributeError: exit(0) - class Turtle(RawTurtle): """RawTurtle auto-creating (scrolled) canvas. @@ -3708,18 +3707,6 @@ Pen = Turtle -def _getpen(): - """Create the 'anonymous' turtle if not already present.""" - if Turtle._pen is None: - Turtle._pen = Turtle() - return Turtle._pen - -def _getscreen(): - """Create a TurtleScreen if not already present.""" - if Turtle._screen is None: - Turtle._screen = Screen() - return Turtle._screen - def write_docstringdict(filename="turtle_docstringdict"): """Create and write docstring-dictionary to file. @@ -3847,30 +3834,41 @@ ## as functions. So we can enhance, change, add, delete methods to these ## classes and do not need to change anything here. - -for methodname in _tg_screen_functions: - pl1, pl2 = getmethparlist(eval('_Screen.' + methodname)) - if pl1 == "": - print ">>>>>>", pl1, pl2 - continue - defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec defstr - eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__) - -for methodname in _tg_turtle_functions: - pl1, pl2 = getmethparlist(eval('Turtle.' + methodname)) - if pl1 == "": - print ">>>>>>", pl1, pl2 - continue - defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec defstr - eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__) +__func_body = """\ +def {name}{paramslist}: + if {obj} is None: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + {obj} = {init} + try: + return {obj}.{name}{argslist} + except TK.TclError: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + raise +""" + +def _make_global_funcs(functions, cls, obj, init, docrevise): + for methodname in functions: + method = getattr(cls, methodname) + pl1, pl2 = getmethparlist(method) + if pl1 == "": + print ">>>>>>", pl1, pl2 + continue + defstr = __func_body.format(obj=obj, init=init, name=methodname, + paramslist=pl1, argslist=pl2) + exec defstr in globals() + globals()[methodname].__doc__ = docrevise(method.__doc__) + +_make_global_funcs(_tg_screen_functions, _Screen, + 'Turtle._screen', 'Screen()', _screen_docrevise) +_make_global_funcs(_tg_turtle_functions, Turtle, + 'Turtle._pen', 'Turtle()', _turtle_docrevise) done = mainloop = TK.mainloop -del pl1, pl2, defstr if __name__ == "__main__": def switchpen(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -116,6 +116,9 @@ Tools/Demos ----------- +- Issue #6639: Module-level turtle functions no longer raise TclError after + closing the window. + - Issue #22314: pydoc now works when the LINES environment variable is set. - Issue #18905: "pydoc -p 0" now outputs actually used port. Based on patch by -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 18:40:21 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 17:40:21 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323152=3A_Move_dec?= =?utf-8?q?laration_into_a_header_and_exclude_from_stable_API=2E?= Message-ID: <20150222174021.4032.11694@psf.io> https://hg.python.org/cpython/rev/b4f9e787b857 changeset: 94725:b4f9e787b857 user: Serhiy Storchaka date: Sun Feb 22 19:39:36 2015 +0200 summary: Issue #23152: Move declaration into a header and exclude from stable API. files: Include/fileutils.h | 6 ++++++ Modules/posixmodule.c | 9 --------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Include/fileutils.h b/Include/fileutils.h --- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -21,6 +21,7 @@ struct stat *buf); #endif +#ifndef Py_LIMITED_API #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) #ifdef MS_WINDOWS @@ -41,6 +42,10 @@ int st_ctime_nsec; unsigned long st_file_attributes; }; + +PyAPI_FUNC(void) _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); +PyAPI_FUNC(void) _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, + ULONG, struct _Py_stat_struct *); #else # define _Py_stat_struct stat #endif @@ -49,6 +54,7 @@ int fd, struct _Py_stat_struct *stat); #endif /* HAVE_FSTAT || MS_WINDOWS */ +#endif /* Py_LIMITED_API */ #ifdef HAVE_STAT PyAPI_FUNC(int) _Py_stat( diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1560,10 +1560,6 @@ return TRUE; } -/* defined in fileutils.c */ -void -_Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct _Py_stat_struct *result); - static int win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse); @@ -6201,11 +6197,6 @@ return return_value; } -#ifdef MS_WINDOWS -void -_Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr); -#endif - static PyObject * os_utime_impl(PyModuleDef *module, path_t *path, PyObject *times, PyObject *ns, int dir_fd, int follow_symlinks) /*[clinic end generated code: output=891489c35cc68c5d input=1f18c17d5941aa82]*/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 20:35:39 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 19:35:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323152=3A_Move_dec?= =?utf-8?q?larations_back_to_posixmodule=2Ec=2E?= Message-ID: <20150222193539.116391.46220@psf.io> https://hg.python.org/cpython/rev/72cf174cc0eb changeset: 94726:72cf174cc0eb user: Serhiy Storchaka date: Sun Feb 22 21:34:54 2015 +0200 summary: Issue #23152: Move declarations back to posixmodule.c. Declarations of Windows-specific auxilary functions need Windows types from windows.h. Instead of including windows.h in Python.h and making it available to all Windows users, it is simpler and safer just move declarations to the single file that needs them. files: Include/fileutils.h | 4 ---- Modules/posixmodule.c | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Include/fileutils.h b/Include/fileutils.h --- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -42,10 +42,6 @@ int st_ctime_nsec; unsigned long st_file_attributes; }; - -PyAPI_FUNC(void) _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); -PyAPI_FUNC(void) _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, - ULONG, struct _Py_stat_struct *); #else # define _Py_stat_struct stat #endif diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -372,6 +372,12 @@ #define DWORD_MAX 4294967295U +#ifdef MS_WINDOWS +/* defined in fileutils.c */ +PyAPI_FUNC(void) _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); +PyAPI_FUNC(void) _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, + ULONG, struct _Py_stat_struct *); +#endif #ifdef MS_WINDOWS static int -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 23:33:58 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 22:33:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Broke_referenc?= =?utf-8?q?e_loops_in_tests_added_in_issue_=235700=2E?= Message-ID: <20150222223358.3859.66025@psf.io> https://hg.python.org/cpython/rev/00bde0743690 changeset: 94728:00bde0743690 branch: 3.4 parent: 94723:1628484c9408 user: Serhiy Storchaka date: Mon Feb 23 00:28:38 2015 +0200 summary: Broke reference loops in tests added in issue #5700. files: Lib/test/test_io.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -606,6 +606,7 @@ self.assertTrue(f.closed) self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed + f.flush = lambda: None # break reference loop def test_flush_error_on_close(self): # raw file @@ -833,6 +834,7 @@ self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed self.assertFalse(closed[1]) + raw.flush = lambda: None # break reference loop def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2670,6 +2672,7 @@ self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed self.assertFalse(closed[1]) + txt.flush = lambda: None # break reference loop def test_close_error_on_close(self): buffer = self.BytesIO(self.testdata) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 23:33:58 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 22:33:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Broke_referenc?= =?utf-8?q?e_loops_in_tests_added_in_issue_=235700=2E?= Message-ID: <20150222223358.116385.46280@psf.io> https://hg.python.org/cpython/rev/bf52f69d6948 changeset: 94727:bf52f69d6948 branch: 2.7 parent: 94722:15dd9d6cc632 user: Serhiy Storchaka date: Mon Feb 23 00:28:38 2015 +0200 summary: Broke reference loops in tests added in issue #5700. files: Lib/test/test_io.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -577,6 +577,7 @@ self.assertTrue(f.closed) self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed + f.flush = lambda: None # break reference loop def test_flush_error_on_close(self): # raw file @@ -786,6 +787,7 @@ self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed self.assertFalse(closed[1]) + raw.flush = lambda: None # break reference loop def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2536,6 +2538,7 @@ self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed self.assertFalse(closed[1]) + txt.flush = lambda: None # break reference loop def test_multi_close(self): txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 23:33:58 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 22 Feb 2015 22:33:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Broke_reference_loops_in_tests_added_in_issue_=235700=2E?= Message-ID: <20150222223358.29678.98404@psf.io> https://hg.python.org/cpython/rev/a8df1ca60452 changeset: 94729:a8df1ca60452 parent: 94726:72cf174cc0eb parent: 94728:00bde0743690 user: Serhiy Storchaka date: Mon Feb 23 00:31:33 2015 +0200 summary: Broke reference loops in tests added in issue #5700. files: Lib/test/test_io.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -602,6 +602,7 @@ self.assertTrue(f.closed) self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed + f.flush = lambda: None # break reference loop def test_flush_error_on_close(self): # raw file @@ -829,6 +830,7 @@ self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed self.assertFalse(closed[1]) + raw.flush = lambda: None # break reference loop def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2731,6 +2733,7 @@ self.assertTrue(closed) # flush() called self.assertFalse(closed[0]) # flush() called before file closed self.assertFalse(closed[1]) + txt.flush = lambda: None # break reference loop def test_close_error_on_close(self): buffer = self.BytesIO(self.testdata) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Feb 22 23:49:24 2015 From: python-checkins at python.org (victor.stinner) Date: Sun, 22 Feb 2015 22:49:24 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_446=3A_Fix_typo_reported_?= =?utf-8?q?by_Zhou_Keyang?= Message-ID: <20150222224924.6734.52379@psf.io> https://hg.python.org/peps/rev/421f9453e07a changeset: 5703:421f9453e07a user: Victor Stinner date: Sun Feb 22 23:49:15 2015 +0100 summary: PEP 446: Fix typo reported by Zhou Keyang files: pep-0446.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0446.txt b/pep-0446.txt --- a/pep-0446.txt +++ b/pep-0446.txt @@ -533,7 +533,7 @@ ``os.dup2()`` behaves differently than ``os.dup()`` because the most common use case of ``os.dup2()`` is to replace the file descriptors of the standard streams: ``stdin`` (``0``), ``stdout`` (``1``) and -``stdout`` (``2``). Standard streams are expected to be inherited by +``stderr`` (``2``). Standard streams are expected to be inherited by child processes. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Feb 23 01:15:41 2015 From: python-checkins at python.org (ned.deily) Date: Mon, 23 Feb 2015 00:15:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNDk5?= =?utf-8?q?=3A_Fix_grammar_error_noticed_by_SilentGhost?= Message-ID: <20150223001541.4036.86208@psf.io> https://hg.python.org/cpython/rev/5dfdaec85345 changeset: 94731:5dfdaec85345 branch: 3.4 parent: 94728:00bde0743690 user: Ned Deily date: Sun Feb 22 16:14:32 2015 -0800 summary: Issue #23499: Fix grammar error noticed by SilentGhost files: Doc/library/mimetypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -106,8 +106,8 @@ extension is already known, the new type will replace the old one. When the type is already known the extension will be added to the list of known extensions. - When *strict* is ``True`` (the default), the mapping will added to the official MIME - types, otherwise to the non-standard ones. + When *strict* is ``True`` (the default), the mapping will be added to the + official MIME types, otherwise to the non-standard ones. .. data:: inited -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 23 01:15:41 2015 From: python-checkins at python.org (ned.deily) Date: Mon, 23 Feb 2015 00:15:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323499=3A_Fix_grammar_error_noticed_by_SilentGho?= =?utf-8?q?st?= Message-ID: <20150223001541.10184.38758@psf.io> https://hg.python.org/cpython/rev/49130b06e3ac changeset: 94732:49130b06e3ac parent: 94729:a8df1ca60452 parent: 94731:5dfdaec85345 user: Ned Deily date: Sun Feb 22 16:15:14 2015 -0800 summary: Issue #23499: Fix grammar error noticed by SilentGhost files: Doc/library/mimetypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -106,8 +106,8 @@ extension is already known, the new type will replace the old one. When the type is already known the extension will be added to the list of known extensions. - When *strict* is ``True`` (the default), the mapping will added to the official MIME - types, otherwise to the non-standard ones. + When *strict* is ``True`` (the default), the mapping will be added to the + official MIME types, otherwise to the non-standard ones. .. data:: inited -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 23 01:15:44 2015 From: python-checkins at python.org (ned.deily) Date: Mon, 23 Feb 2015 00:15:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzNDk5?= =?utf-8?q?=3A_Fix_grammar_error_noticed_by_SilentGhost?= Message-ID: <20150223001541.99276.64721@psf.io> https://hg.python.org/cpython/rev/2b8c5ed7b38b changeset: 94730:2b8c5ed7b38b branch: 2.7 parent: 94727:bf52f69d6948 user: Ned Deily date: Sun Feb 22 16:08:23 2015 -0800 summary: Issue #23499: Fix grammar error noticed by SilentGhost files: Doc/library/mimetypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -106,8 +106,8 @@ extension is already known, the new type will replace the old one. When the type is already known the extension will be added to the list of known extensions. - When *strict* is ``True`` (the default), the mapping will added to the official MIME - types, otherwise to the non-standard ones. + When *strict* is ``True`` (the default), the mapping will be added to the + official MIME types, otherwise to the non-standard ones. .. data:: inited -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Feb 23 09:44:36 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 23 Feb 2015 09:44:36 +0100 Subject: [Python-checkins] Daily reference leaks (a8df1ca60452): sum=3 Message-ID: results for a8df1ca60452 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogno7N9j', '-x'] From python-checkins at python.org Mon Feb 23 11:42:38 2015 From: python-checkins at python.org (victor.stinner) Date: Mon, 23 Feb 2015 10:42:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_close_explicitly_event_loops?= Message-ID: <20150223104230.109579.98868@psf.io> https://hg.python.org/cpython/rev/05bd5ec8365e changeset: 94733:05bd5ec8365e branch: 3.4 parent: 94731:5dfdaec85345 user: Victor Stinner date: Mon Feb 23 11:41:56 2015 +0100 summary: asyncio doc: close explicitly event loops files: Doc/library/asyncio-dev.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -212,6 +212,7 @@ loop = asyncio.get_event_loop() asyncio.async(bug()) loop.run_forever() + loop.close() Output:: @@ -258,6 +259,7 @@ loop = asyncio.get_event_loop() asyncio.async(handle_exception()) loop.run_forever() + loop.close() Another option is to use the :meth:`BaseEventLoop.run_until_complete` function:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 23 11:42:38 2015 From: python-checkins at python.org (victor.stinner) Date: Mon, 23 Feb 2015 10:42:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio_doc=29?= Message-ID: <20150223104230.109540.82180@psf.io> https://hg.python.org/cpython/rev/516d3773ecb2 changeset: 94734:516d3773ecb2 parent: 94732:49130b06e3ac parent: 94733:05bd5ec8365e user: Victor Stinner date: Mon Feb 23 11:42:22 2015 +0100 summary: Merge 3.4 (asyncio doc) files: Doc/library/asyncio-dev.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -212,6 +212,7 @@ loop = asyncio.get_event_loop() asyncio.async(bug()) loop.run_forever() + loop.close() Output:: @@ -258,6 +259,7 @@ loop = asyncio.get_event_loop() asyncio.async(handle_exception()) loop.run_forever() + loop.close() Another option is to use the :meth:`BaseEventLoop.run_until_complete` function:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Feb 23 12:34:46 2015 From: python-checkins at python.org (nick.coghlan) Date: Mon, 23 Feb 2015 11:34:46 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_422=3A_Make_=5F=5Fautodec?= =?utf-8?q?orate=5F=5F_a_true_decorator?= Message-ID: <20150223113446.14047.34497@psf.io> https://hg.python.org/peps/rev/922b91d5b23d changeset: 5704:922b91d5b23d user: Nick Coghlan date: Mon Feb 23 21:34:36 2015 +1000 summary: PEP 422: Make __autodecorate__ a true decorator * __autodecorate__ is now defined as a true decorator that can replace the class object entirely * question whether the namespace parameter is sufficiently valuable to be worth the extra complexity, or if Eric Snow's idea of using an ordered dict by default would suffice files: pep-0422.txt | 96 +++++++++++++++++++++++++++++++++++++-- 1 files changed, 90 insertions(+), 6 deletions(-) diff --git a/pep-0422.txt b/pep-0422.txt --- a/pep-0422.txt +++ b/pep-0422.txt @@ -129,6 +129,18 @@ # The usual super() mechanisms are used to correctly support # multiple inheritance. The class decorator style signature helps # ensure that invoking the parent class is as simple as possible. + cls = super().__autodecorate__() + return cls + +To simplify the cooperative multiple inheritance case, ``object`` will gain +a default implementation of the hook that returns the class unmodified: + + class object: + def __autodecorate__(cls): + return cls + +If a metaclass wishes to block implicit class decoration for some reason, it +must arrange for ``cls.__autodecorate__`` to trigger ``AttributeError``. If present on the created object, this new hook will be called by the class creation machinery *after* the ``__class__`` reference has been initialised. @@ -137,9 +149,6 @@ converted to a class method when the class is created (prior to the hook being invoked). -If a metaclass wishes to block implicit class decoration for some reason, it -must arrange for ``cls.__autodecorate__`` to trigger ``AttributeError``. - Note, that when ``__autodecorate__`` is called, the name of the class is not yet bound to the new class object. As a consequence, the two argument form of ``super()`` cannot be used to call methods (e.g., ``super(Example, cls)`` @@ -151,7 +160,7 @@ inclusion in the language definition `more than 10 years ago`_, and a similar mechanism has long been supported by `Zope's ExtensionClass`_), but the situation has changed sufficiently in recent years that -the idea is worth reconsidering. +the idea is worth reconsidering for inclusion as a native language feature. In addition, the introduction of the metaclass ``__prepare__`` method in PEP 3115 allows a further enhancement that was not possible in Python 2: this @@ -269,6 +278,7 @@ class Example: def __autodecorate__(cls): + cls = super().__autodecorate__() # Don't process the base class if cls is __class__: return @@ -276,6 +286,58 @@ ... +Replacing a class with a different kind of object +------------------------------------------------- + +As an implicit decorator, ``__autodecorate__`` is able to relatively easily +replace the defined class with a different kind of object. Technically +custom metaclasses and even ``__new__`` methods can already do this +implicitly, but the decorator model makes such code much easier to understand +and implement. + + class BuildDict: + def __autodecorate__(cls): + cls = super().__autodecorate__() + # Don't process the base class + if cls is __class__: + return + # Convert subclasses to ordinary dictionaries + return cls.__dict__.copy() + +It's not clear why anyone would ever do this implicitly based on inheritance +rather than just using an explicit decorator, but the possibility seems worth +noting. + + +Open Questions +============== + +Is the ``namespace`` concept worth the extra complexity? +-------------------------------------------------------- + +Unlike the new ``__autodecorate__`` hook the proposed ``namespace`` keyword +argument is not automatically inherited by subclasses. Given the way this +proposal is currently written , the only way to get a special namespace used +consistently in subclasses is still to write a custom metaclass with a +suitable ``__prepare__`` implementation. + +Changing the custom namespace factory to also be inherited would +significantly increase the complexity of this proposal, and introduce a +number of the same potential base class conflict issues as arise with the +use of custom metaclasses. + +Eric Snow has put forward a +`separate proposal `__ +to instead make the execution namespace for class bodies an ordered dictionary +by default, and capture the class attribute definition order for future +reference as an attribute (e.g. ``__definition_order__``) on the class object. + +Eric's suggested approach may be a better choice for a new default behaviour +for type that combines well with the proposed ``__autodecorate__`` hook, +leaving the more complex configurable namespace factory idea to a custom +metaclass like the one shown below. + + New Ways of Using Classes ========================= @@ -428,6 +490,26 @@ explicitly say anything one way or the other). +Making ``__autodecorate__`` implicitly static, like ``__new__`` +--------------------------------------------------------------- + +While it accepts the class to be instantiated as the first argument, +``__new__`` is actually implicitly treated as a static method rather than +as a class method. This allows it to be readily extracted from its +defining class and called directly on a subclass, rather than being +coupled to the class object it is retrieved from. + +Such behaviour initially appears to be potentially useful for the +new ``__autodecorate__`` hook, as it would allow ``__autodecorate__`` +methods to readily be used as explicit decorators on other classes. + +However, that apparent support would be an illusion as it would only work +correctly if invoked on a subclass, in which case the method can just as +readily be retrieved from the subclass and called that way. Unlike +``__new__``, there's no issue with potentially changing method signatures at +different points in the inheritance chain. + + Passing in the namespace directly rather than a factory function ---------------------------------------------------------------- @@ -443,8 +525,10 @@ ======================== A reference implementation for ``__autodecorate__`` has been posted to the -`issue tracker`_. It uses the original ``__init_class__`` naming and does -not yet include the new ``namespace`` parameter for ``type.__prepare__``. +`issue tracker`_. It uses the original ``__init_class__`` naming. does not yet +allow the implicit decorator to replace the class with a different object and +does not implement the suggested ``namespace`` parameter for +``type.__prepare__``. TODO ==== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Feb 23 20:45:25 2015 From: python-checkins at python.org (steve.dower) Date: Mon, 23 Feb 2015 19:45:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_23314=3A_SuppressCra?= =?utf-8?q?shReports_now_disables_CRT_assertions?= Message-ID: <20150223194525.14025.98809@psf.io> https://hg.python.org/cpython/rev/bb67b810aac1 changeset: 94735:bb67b810aac1 user: Steve Dower date: Mon Feb 23 07:56:13 2015 -0800 summary: Issue 23314: SuppressCrashReports now disables CRT assertions SuppressCrashReports should be used in test subprocesses that test invalid conditions. files: Lib/test/support/__init__.py | 27 ++++++++++++++++++++ Lib/test/tf_inherit_check.py | 32 ++++++++++++----------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2151,6 +2151,7 @@ disable the creation of coredump file. """ old_value = None + old_modes = None def __enter__(self): """On Windows, disable Windows Error Reporting dialogs using @@ -2168,6 +2169,26 @@ SEM_NOGPFAULTERRORBOX = 0x02 self.old_value = self._k32.SetErrorMode(SEM_NOGPFAULTERRORBOX) self._k32.SetErrorMode(self.old_value | SEM_NOGPFAULTERRORBOX) + + # Suppress assert dialogs in debug builds + # (see http://bugs.python.org/issue23314) + try: + import msvcrt + msvcrt.CrtSetReportMode + except (AttributeError, ImportError): + # no msvcrt or a release build + pass + else: + self.old_modes = {} + for report_type in [msvcrt.CRT_WARN, + msvcrt.CRT_ERROR, + msvcrt.CRT_ASSERT]: + old_mode = msvcrt.CrtSetReportMode(report_type, + msvcrt.CRTDBG_MODE_FILE) + old_file = msvcrt.CrtSetReportFile(report_type, + msvcrt.CRTDBG_FILE_STDERR) + self.old_modes[report_type] = old_mode, old_file + else: if resource is not None: try: @@ -2199,6 +2220,12 @@ if sys.platform.startswith('win'): self._k32.SetErrorMode(self.old_value) + + if self.old_modes: + import msvcrt + for report_type, (old_mode, old_file) in self.old_modes.items(): + msvcrt.CrtSetReportMode(report_type, old_mode) + msvcrt.CrtSetReportFile(report_type, old_file) else: if resource is not None: try: diff --git a/Lib/test/tf_inherit_check.py b/Lib/test/tf_inherit_check.py --- a/Lib/test/tf_inherit_check.py +++ b/Lib/test/tf_inherit_check.py @@ -4,22 +4,24 @@ import sys import os +from test.support import SuppressCrashReport -verbose = (sys.argv[1] == 'v') -try: - fd = int(sys.argv[2]) +with SuppressCrashReport(): + verbose = (sys.argv[1] == 'v') + try: + fd = int(sys.argv[2]) - try: - os.write(fd, b"blat") - except OSError: - # Success -- could not write to fd. - sys.exit(0) - else: + try: + os.write(fd, b"blat") + except OSError: + # Success -- could not write to fd. + sys.exit(0) + else: + if verbose: + sys.stderr.write("fd %d is open in child" % fd) + sys.exit(1) + + except Exception: if verbose: - sys.stderr.write("fd %d is open in child" % fd) + raise sys.exit(1) - -except Exception: - if verbose: - raise - sys.exit(1) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 24 14:32:46 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 24 Feb 2015 13:32:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzNDU4?= =?utf-8?q?=3A_On_POSIX=2C_the_file_descriptor_kept_open_by_os=2Eurandom?= =?utf-8?b?KCkgaXMgbm93?= Message-ID: <20150224133058.116387.30101@psf.io> https://hg.python.org/cpython/rev/88a99ea8a4cf changeset: 94736:88a99ea8a4cf branch: 2.7 parent: 94730:2b8c5ed7b38b user: Victor Stinner date: Tue Feb 24 14:30:43 2015 +0100 summary: Issue #23458: On POSIX, the file descriptor kept open by os.urandom() is now set to non inheritable files: Lib/test/subprocessdata/fd_status.py | 32 ++++++++++++++++ Lib/test/test_os.py | 28 ++++++++++++++ Misc/NEWS | 3 + Python/random.c | 9 ++++ 4 files changed, 72 insertions(+), 0 deletions(-) diff --git a/Lib/test/subprocessdata/fd_status.py b/Lib/test/subprocessdata/fd_status.py new file mode 100644 --- /dev/null +++ b/Lib/test/subprocessdata/fd_status.py @@ -0,0 +1,32 @@ +"""When called as a script, print a comma-separated list of the open +file descriptors on stdout. + +Usage: +fd_stats.py: check all file descriptors +fd_status.py fd1 fd2 ...: check only specified file descriptors +""" + +import errno +import os +import stat +import sys + +if __name__ == "__main__": + fds = [] + if len(sys.argv) == 1: + try: + _MAXFD = os.sysconf("SC_OPEN_MAX") + except: + _MAXFD = 256 + test_fds = range(0, _MAXFD) + else: + test_fds = map(int, sys.argv[1:]) + for fd in test_fds: + try: + st = os.fstat(fd) + except OSError as e: + if e.errno == errno.EBADF: + continue + raise + fds.append(fd) + print(','.join(map(str, fds))) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -10,6 +10,7 @@ import signal import subprocess import sysconfig +import textwrap import time try: import resource @@ -568,6 +569,33 @@ data2 = self.get_urandom_subprocess(16) self.assertNotEqual(data1, data2) + def test_urandom_fd_non_inheritable(self): + # Issue #23458: os.urandom() keeps a file descriptor open, but it + # must be non inheritable + fd_status = test_support.findfile("fd_status.py", subdir="subprocessdata") + + # Need a two subprocesses because the Python test suite opens other + # inheritable file descriptors, whereas the test is specific to + # os.urandom() file descriptor + code = textwrap.dedent(""" + import os + import subprocess + import sys + + # Ensure that the /dev/urandom file descriptor is open + os.urandom(1) + + exitcode = subprocess.call([sys.executable, %r], + close_fds=False) + sys.exit(exitcode) + """ % fd_status) + + proc = subprocess.Popen([sys.executable, "-c", code], + stdout=subprocess.PIPE, close_fds=True) + output, error = proc.communicate() + open_fds = set(map(int, output.rstrip().split(','))) + self.assertEqual(open_fds - set(range(3)), set()) + HAVE_GETENTROPY = (sysconfig.get_config_var('HAVE_GETENTROPY') == 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #23458: On POSIX, the file descriptor kept open by os.urandom() is now + set to non inheritable + - Issue #22113: struct.pack_into() now supports new buffer protocol (in particular accepts writable memoryview). diff --git a/Python/random.c b/Python/random.c --- a/Python/random.c +++ b/Python/random.c @@ -188,6 +188,7 @@ int fd; Py_ssize_t n; struct stat st; + int attr; if (size <= 0) return 0; @@ -219,6 +220,14 @@ PyErr_SetFromErrno(PyExc_OSError); return -1; } + + /* try to make the file descriptor non-inheritable, ignore errors */ + attr = fcntl(fd, F_GETFD); + if (attr >= 0) { + attr |= FD_CLOEXEC; + (void)fcntl(fd, F_SETFD, attr); + } + if (urandom_cache.fd >= 0) { /* urandom_fd was initialized by another thread while we were not holding the GIL, keep it. */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 24 15:13:30 2015 From: python-checkins at python.org (victor.stinner) Date: Tue, 24 Feb 2015 14:13:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIzNDU4?= =?utf-8?q?=3A_skip_test=5Fos=2Etest=5Furandom=5Ffd=5Fnon=5Finheritable=28?= =?utf-8?q?=29_on_Windows?= Message-ID: <20150224141322.29696.50067@psf.io> https://hg.python.org/cpython/rev/8969c7f44d9e changeset: 94737:8969c7f44d9e branch: 2.7 user: Victor Stinner date: Tue Feb 24 15:12:57 2015 +0100 summary: Issue #23458: skip test_os.test_urandom_fd_non_inheritable() on Windows files: Lib/test/test_os.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -569,6 +569,8 @@ data2 = self.get_urandom_subprocess(16) self.assertNotEqual(data1, data2) + # os.urandom() doesn't use a file descriptor on Windows + @unittest.skipIf(sys.platform == "win32", "POSIX specific tests") def test_urandom_fd_non_inheritable(self): # Issue #23458: os.urandom() keeps a file descriptor open, but it # must be non inheritable -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Feb 24 19:34:39 2015 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 24 Feb 2015 18:34:39 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_to_PEP_441_from_Paul_M?= =?utf-8?q?ore=3A_swap_pack=28=29_args=2C_default_archive_name=2C?= Message-ID: <20150224183439.10168.49710@psf.io> https://hg.python.org/peps/rev/4eba4dcec2c7 changeset: 5705:4eba4dcec2c7 user: Guido van Rossum date: Tue Feb 24 10:34:33 2015 -0800 summary: Update to PEP 441 from Paul More: swap pack() args, default archive name, support open streams. files: pep-0441.txt | 26 +++++++++++++++----------- 1 files changed, 15 insertions(+), 11 deletions(-) diff --git a/pep-0441.txt b/pep-0441.txt --- a/pep-0441.txt +++ b/pep-0441.txt @@ -90,17 +90,19 @@ The zipapp module will provide the following functions: -``pack(target, directory, interpreter=None, main=None)`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``pack(directory, target=None, interpreter=None, main=None)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Writes an application archive called *target*, containing the -contents of *directory*. If *interpreter* is specified, it will -be written to the start of the archive as a shebang line and the file -will be made executable (if no interpreter is specified, the shebang -line will be omitted). If the directory contains no ``__main__.py`` -file, the function will construct a ``__main__.py`` which calls the -function specified in the *main* argument (which should be in the -form ``'pkg.mod:fn'``). +Writes an application archive called *target*, containing the contents +of *directory*. The *target* can be a filename, or a file-like object +(which must be open for writing in bytes mode), or None (which means +use the name of *directory* with ``.pyz`` appended). If *interpreter* +is specified, it will be written to the start of the archive as a +shebang line and the file will be made executable (if no interpreter +is specified, the shebang line will be omitted). If the directory +contains no ``__main__.py`` file, the function will construct a +``__main__.py`` which calls the function specified in the *main* +argument (which should be in the form ``'pkg.mod:fn'``). It is an error to specify *main* if the directory contains a ``__main__.py``, or to omit *main* when there is no ``__main__.py`` @@ -118,7 +120,9 @@ Modifies the *archive*'s shebang line to contain the specified interpreter, and writes the updated archive to *new_archive*. If the -*interpreter* is ``None``, removes the shebang line. +*interpreter* is ``None``, removes the shebang line. The +*new_archive* argument can be a filename, or a file-like object open +for writing in byte mode. Command Line Usage ------------------ -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Tue Feb 24 19:36:22 2015 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 24 Feb 2015 18:36:22 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Make_a_line_of_dashes_longer?= =?utf-8?q?=2C_to_satisfy_pep2html=2E?= Message-ID: <20150224183619.109569.959@psf.io> https://hg.python.org/peps/rev/25fdc87ba644 changeset: 5706:25fdc87ba644 user: Guido van Rossum date: Tue Feb 24 10:36:15 2015 -0800 summary: Make a line of dashes longer, to satisfy pep2html. files: pep-0441.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0441.txt b/pep-0441.txt --- a/pep-0441.txt +++ b/pep-0441.txt @@ -211,7 +211,7 @@ a result has been dropped from consideration. Registering ``.pyz`` as a Media Type --------------------------------- +------------------------------------ It was suggested [3]_ that the ``.pyz`` extension should be registered in the Unix database of extensions. While it makes sense to do this -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Feb 25 02:01:19 2015 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 25 Feb 2015 01:01:19 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Small_wording_change_to_PEP_4?= =?utf-8?q?48_=28replace_=22currently=22_with_=22continue_to=22=29=2E?= Message-ID: <20150225010114.116399.75024@psf.io> https://hg.python.org/peps/rev/2193d9680c70 changeset: 5707:2193d9680c70 user: Guido van Rossum date: Tue Feb 24 16:44:25 2015 -0800 summary: Small wording change to PEP 448 (replace "currently" with "continue to"). files: pep-0448.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0448.txt b/pep-0448.txt --- a/pep-0448.txt +++ b/pep-0448.txt @@ -137,7 +137,7 @@ arguments with relation to ``*`` unpackings nor any restriction of the order of keyword arguments with relation to ``**`` unpackings. -Function calls currently have the restriction that keyword arguments +Function calls continue to have the restriction that keyword arguments must follow positional arguments and ``**`` unpackings must additionally follow ``*`` unpackings. -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Wed Feb 25 12:41:14 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 25 Feb 2015 12:41:14 +0100 Subject: [Python-checkins] Daily reference leaks (bb67b810aac1): sum=7 Message-ID: results for bb67b810aac1 on branch "default" -------------------------------------------- test_asyncio leaked [0, 3, 0] memory blocks, sum=3 test_functools leaked [0, 0, 3] memory blocks, sum=3 test_smtplib leaked [0, 0, 1] references, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogJYEkzi', '-x'] From solipsis at pitrou.net Wed Feb 25 12:42:40 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 25 Feb 2015 12:42:40 +0100 Subject: [Python-checkins] Daily reference leaks (bb67b810aac1): sum=0 Message-ID: results for bb67b810aac1 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogTrpVNr', '-x'] From python-checkins at python.org Wed Feb 25 13:07:53 2015 From: python-checkins at python.org (georg.brandl) Date: Wed, 25 Feb 2015 12:07:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4?= Message-ID: <20150225120742.109544.37723@psf.io> https://hg.python.org/cpython/rev/3673cc0c1b8f changeset: 94739:3673cc0c1b8f parent: 94735:bb67b810aac1 parent: 94738:c113cdfef1e1 user: Georg Brandl date: Wed Feb 25 13:07:03 2015 +0100 summary: Merge with 3.4 files: Doc/library/codecs.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -403,7 +403,7 @@ Implements the ``'replace'`` error handling (for :term:`text encodings ` only): substitutes ``'?'`` for encoding errors (to be encoded by the codec), and ``'\ufffd'`` (the Unicode replacement - character, ``'?'``) for decoding errors. + character) for decoding errors. .. function:: ignore_errors(exception) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 13:07:53 2015 From: python-checkins at python.org (georg.brandl) Date: Wed, 25 Feb 2015 12:07:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Remove_unsuppo?= =?utf-8?q?rted_=28in_latex=29_character_from_the_source=2E?= Message-ID: <20150225120742.3887.44874@psf.io> https://hg.python.org/cpython/rev/c113cdfef1e1 changeset: 94738:c113cdfef1e1 branch: 3.4 parent: 94733:05bd5ec8365e user: Georg Brandl date: Wed Feb 25 13:05:53 2015 +0100 summary: Remove unsupported (in latex) character from the source. files: Doc/library/codecs.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -393,7 +393,7 @@ Implements the ``'replace'`` error handling (for :term:`text encodings ` only): substitutes ``'?'`` for encoding errors (to be encoded by the codec), and ``'\ufffd'`` (the Unicode replacement - character, ``'?'``) for decoding errors. + character) for decoding errors. .. function:: ignore_errors(exception) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 14:25:40 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 25 Feb 2015 13:25:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio_doc=29?= Message-ID: <20150225132455.4034.14964@psf.io> https://hg.python.org/cpython/rev/a727eed3a811 changeset: 94743:a727eed3a811 parent: 94739:3673cc0c1b8f parent: 94742:14e7a28235c6 user: Victor Stinner date: Wed Feb 25 14:24:47 2015 +0100 summary: Merge 3.4 (asyncio doc) files: Doc/library/asyncio-eventloop.rst | 5 + Doc/library/asyncio-protocol.rst | 2 + Doc/library/asyncio-sync.rst | 297 +---------------- Doc/library/asyncio-stream.rst | 4 + Doc/library/asyncio-subprocess.rst | 5 + Doc/library/asyncio-sync.rst | 172 +--------- Doc/library/asyncio-task.rst | 4 + Doc/library/asyncio.rst | 6 + 8 files changed, 42 insertions(+), 453 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -22,6 +22,8 @@ Base class of event loops. + This class is :ref:`not thread safe `. + Run an event loop ----------------- @@ -104,6 +106,9 @@ Like :meth:`call_soon`, but thread safe. + See the :ref:`concurrency and multithreading ` + section of the documentation. + .. _asyncio-delayed-calls: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -23,6 +23,8 @@ subprocess pipes. The methods available on a transport depend on the transport's kind. +The transport classes are :ref:`not thread safe `. + BaseTransport ------------- diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-queue.rst copy from Doc/library/asyncio-sync.rst copy to Doc/library/asyncio-queue.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-queue.rst @@ -1,16 +1,7 @@ .. currentmodule:: asyncio -.. _asyncio-sync: -Synchronization primitives -========================== - -Locks: - -* :class:`Lock` -* :class:`Event` -* :class:`Condition` -* :class:`Semaphore` -* :class:`BoundedSemaphore` +Queues +====== Queues: @@ -19,284 +10,14 @@ * :class:`LifoQueue` * :class:`JoinableQueue` -asyncio locks and queues API were designed to be close to classes of the -:mod:`threading` module (:class:`~threading.Lock`, :class:`~threading.Event`, -:class:`~threading.Condition`, :class:`~threading.Semaphore`, -:class:`~threading.BoundedSemaphore`) and the :mod:`queue` module -(:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, -:class:`~queue.LifoQueue`), but they have no *timeout* parameter. The +asyncio queue API was designed to be close to classes of the :mod:`queue` +module (:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, +:class:`~queue.LifoQueue`), but it has no *timeout* parameter. The :func:`asyncio.wait_for` function can be used to cancel a task after a timeout. -Locks +Queue ----- -Lock -^^^^ - -.. class:: Lock(\*, loop=None) - - Primitive lock objects. - - A primitive lock is a synchronization primitive that is not owned by a - particular coroutine when locked. A primitive lock is in one of two states, - 'locked' or 'unlocked'. - - It is created in the unlocked state. It has two basic methods, :meth:`acquire` - and :meth:`release`. When the state is unlocked, acquire() changes the state to - locked and returns immediately. When the state is locked, acquire() blocks - until a call to release() in another coroutine changes it to unlocked, then - the acquire() call resets it to locked and returns. The release() method - should only be called in the locked state; it changes the state to unlocked - and returns immediately. If an attempt is made to release an unlocked lock, - a :exc:`RuntimeError` will be raised. - - When more than one coroutine is blocked in acquire() waiting for the state - to turn to unlocked, only one coroutine proceeds when a release() call - resets the state to unlocked; first coroutine which is blocked in acquire() - is being processed. - - :meth:`acquire` is a coroutine and should be called with ``yield from``. - - Locks also support the context management protocol. ``(yield from lock)`` - should be used as context manager expression. - - Usage:: - - lock = Lock() - ... - yield from lock - try: - ... - finally: - lock.release() - - Context manager usage:: - - lock = Lock() - ... - with (yield from lock): - ... - - Lock objects can be tested for locking state:: - - if not lock.locked(): - yield from lock - else: - # lock is acquired - ... - - .. method:: locked() - - Return ``True`` if the lock is acquired. - - .. coroutinemethod:: acquire() - - Acquire a lock. - - This method blocks until the lock is unlocked, then sets it to locked and - returns ``True``. - - This method is a :ref:`coroutine `. - - .. method:: release() - - Release a lock. - - When the lock is locked, reset it to unlocked, and return. If any other - coroutines are blocked waiting for the lock to become unlocked, allow - exactly one of them to proceed. - - When invoked on an unlocked lock, a :exc:`RuntimeError` is raised. - - There is no return value. - - -Event -^^^^^ - -.. class:: Event(\*, loop=None) - - An Event implementation, asynchronous equivalent to :class:`threading.Event`. - - Class implementing event objects. An event manages a flag that can be set to - true with the :meth:`set` method and reset to false with the :meth:`clear` - method. The :meth:`wait` method blocks until the flag is true. The flag is - initially false. - - .. method:: clear() - - Reset the internal flag to false. Subsequently, coroutines calling - :meth:`wait` will block until :meth:`set` is called to set the internal - flag to true again. - - .. method:: is_set() - - Return ``True`` if and only if the internal flag is true. - - .. method:: set() - - Set the internal flag to true. All coroutines waiting for it to become - true are awakened. Coroutine that call :meth:`wait` once the flag is true - will not block at all. - - .. coroutinemethod:: wait() - - Block until the internal flag is true. - - If the internal flag is true on entry, return ``True`` immediately. - Otherwise, block until another coroutine calls :meth:`set` to set the - flag to true, then return ``True``. - - This method is a :ref:`coroutine `. - - -Condition -^^^^^^^^^ - -.. class:: Condition(lock=None, \*, loop=None) - - A Condition implementation, asynchronous equivalent to - :class:`threading.Condition`. - - This class implements condition variable objects. A condition variable - allows one or more coroutines to wait until they are notified by another - coroutine. - - If the *lock* argument is given and not ``None``, it must be a :class:`Lock` - object, and it is used as the underlying lock. Otherwise, - a new :class:`Lock` object is created and used as the underlying lock. - - .. coroutinemethod:: acquire() - - Acquire the underlying lock. - - This method blocks until the lock is unlocked, then sets it to locked and - returns ``True``. - - This method is a :ref:`coroutine `. - - .. method:: notify(n=1) - - By default, wake up one coroutine waiting on this condition, if any. - If the calling coroutine has not acquired the lock when this method is - called, a :exc:`RuntimeError` is raised. - - This method wakes up at most *n* of the coroutines waiting for the - condition variable; it is a no-op if no coroutines are waiting. - - .. note:: - - An awakened coroutine does not actually return from its :meth:`wait` - call until it can reacquire the lock. Since :meth:`notify` does not - release the lock, its caller should. - - .. method:: locked() - - Return ``True`` if the underlying lock is acquired. - - .. method:: notify_all() - - Wake up all threads waiting on this condition. This method acts like - :meth:`notify`, but wakes up all waiting threads instead of one. If the - calling thread has not acquired the lock when this method is called, a - :exc:`RuntimeError` is raised. - - .. method:: release() - - Release the underlying lock. - - When the lock is locked, reset it to unlocked, and return. If any other - coroutines are blocked waiting for the lock to become unlocked, allow - exactly one of them to proceed. - - When invoked on an unlocked lock, a :exc:`RuntimeError` is raised. - - There is no return value. - - .. coroutinemethod:: wait() - - Wait until notified. - - If the calling coroutine has not acquired the lock when this method is - called, a :exc:`RuntimeError` is raised. - - This method releases the underlying lock, and then blocks until it is - awakened by a :meth:`notify` or :meth:`notify_all` call for the same - condition variable in another coroutine. Once awakened, it re-acquires - the lock and returns ``True``. - - This method is a :ref:`coroutine `. - - .. coroutinemethod:: wait_for(predicate) - - Wait until a predicate becomes true. - - The predicate should be a callable which result will be interpreted as a - boolean value. The final predicate value is the return value. - - This method is a :ref:`coroutine `. - - -Semaphores ----------- - -Semaphore -^^^^^^^^^ - -.. class:: Semaphore(value=1, \*, loop=None) - - A Semaphore implementation. - - A semaphore manages an internal counter which is decremented by each - :meth:`acquire` call and incremented by each :meth:`release` call. The - counter can never go below zero; when :meth:`acquire` finds that it is zero, - it blocks, waiting until some other thread calls :meth:`release`. - - Semaphores also support the context management protocol. - - The optional argument gives the initial value for the internal counter; it - defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` - is raised. - - .. coroutinemethod:: acquire() - - Acquire a semaphore. - - If the internal counter is larger than zero on entry, decrement it by one - and return ``True`` immediately. If it is zero on entry, block, waiting - until some other coroutine has called :meth:`release` to make it larger - than ``0``, and then return ``True``. - - This method is a :ref:`coroutine `. - - .. method:: locked() - - Returns ``True`` if semaphore can not be acquired immediately. - - .. coroutinemethod:: release() - - Release a semaphore, incrementing the internal counter by one. When it - was zero on entry and another coroutine is waiting for it to become - larger than zero again, wake up that coroutine. - - -BoundedSemaphore -^^^^^^^^^^^^^^^^ - -.. class:: BoundedSemaphore(value=1, \*, loop=None) - - A bounded semaphore implementation. Inherit from :class:`Semaphore`. - - This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would - increase the value above the initial value. - - -Queues ------- - -Queue -^^^^^ - .. class:: Queue(maxsize=0, \*, loop=None) A queue, useful for coordinating producer and consumer coroutines. @@ -310,6 +31,8 @@ be interrupted between calling :meth:`qsize` and doing an operation on the Queue. + This class is :ref:`not thread safe `. + .. versionchanged:: 3.4.3 New :meth:`join` and :meth:`task_done` methods. @@ -402,7 +125,7 @@ PriorityQueue -^^^^^^^^^^^^^ +------------- .. class:: PriorityQueue @@ -413,7 +136,7 @@ LifoQueue -^^^^^^^^^ +--------- .. class:: LifoQueue diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -85,6 +85,8 @@ .. class:: StreamReader(limit=None, loop=None) + This class is :ref:`not thread safe `. + .. method:: exception() Get the exception. @@ -155,6 +157,8 @@ wait for flow control. It also adds a transport attribute which references the :class:`Transport` directly. + This class is :ref:`not thread safe `. + .. attribute:: transport Transport. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -193,6 +193,9 @@ :meth:`~subprocess.Popen.wait` method of the :class:`~subprocess.Popen` class is implemented as a busy loop. + This class is :ref:`not thread safe `. See also the + :ref:`Subprocess and threads ` section. + .. coroutinemethod:: wait() Wait for child process to terminate. Set and return :attr:`returncode` @@ -310,6 +313,8 @@ subprocesses from other threads. Call the :func:`get_child_watcher` function in the main thread to instantiate the child watcher. +The :class:`asyncio.subprocess.Process` class is not thread safe. + .. seealso:: The :ref:`Concurrency and multithreading in asyncio diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -9,22 +9,16 @@ * :class:`Lock` * :class:`Event` * :class:`Condition` + +Semaphores: + * :class:`Semaphore` * :class:`BoundedSemaphore` -Queues: - -* :class:`Queue` -* :class:`PriorityQueue` -* :class:`LifoQueue` -* :class:`JoinableQueue` - -asyncio locks and queues API were designed to be close to classes of the -:mod:`threading` module (:class:`~threading.Lock`, :class:`~threading.Event`, +asyncio lock API was designed to be close to classes of the :mod:`threading` +module (:class:`~threading.Lock`, :class:`~threading.Event`, :class:`~threading.Condition`, :class:`~threading.Semaphore`, -:class:`~threading.BoundedSemaphore`) and the :mod:`queue` module -(:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, -:class:`~queue.LifoQueue`), but they have no *timeout* parameter. The +:class:`~threading.BoundedSemaphore`), but it has no *timeout* parameter. The :func:`asyncio.wait_for` function can be used to cancel a task after a timeout. Locks @@ -290,157 +284,3 @@ This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would increase the value above the initial value. - -Queues ------- - -Queue -^^^^^ - -.. class:: Queue(maxsize=0, \*, loop=None) - - A queue, useful for coordinating producer and consumer coroutines. - - If *maxsize* is less than or equal to zero, the queue size is infinite. If - it is an integer greater than ``0``, then ``yield from put()`` will block - when the queue reaches *maxsize*, until an item is removed by :meth:`get`. - - Unlike the standard library :mod:`queue`, you can reliably know this Queue's - size with :meth:`qsize`, since your single-threaded asyncio application won't - be interrupted between calling :meth:`qsize` and doing an operation on the - Queue. - - .. versionchanged:: 3.4.3 - New :meth:`join` and :meth:`task_done` methods. - - .. method:: empty() - - Return ``True`` if the queue is empty, ``False`` otherwise. - - .. method:: full() - - Return ``True`` if there are :attr:`maxsize` items in the queue. - - .. note:: - - If the Queue was initialized with ``maxsize=0`` (the default), then - :meth:`full()` is never ``True``. - - .. coroutinemethod:: get() - - Remove and return an item from the queue. If queue is empty, wait until - an item is available. - - This method is a :ref:`coroutine `. - - .. seealso:: - - The :meth:`empty` method. - - .. method:: get_nowait() - - Remove and return an item from the queue. - - Return an item if one is immediately available, else raise - :exc:`QueueEmpty`. - - .. coroutinemethod:: join() - - Block until all items in the queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls - :meth:`task_done` to indicate that the item was retrieved and all work on - it is complete. When the count of unfinished tasks drops to zero, - :meth:`join` unblocks. - - This method is a :ref:`coroutine `. - - .. versionadded:: 3.4.3 - - .. coroutinemethod:: put(item) - - Put an item into the queue. If the queue is full, wait until a free slot - is available before adding item. - - This method is a :ref:`coroutine `. - - .. seealso:: - - The :meth:`full` method. - - .. method:: put_nowait(item) - - Put an item into the queue without blocking. - - If no free slot is immediately available, raise :exc:`QueueFull`. - - .. method:: qsize() - - Number of items in the queue. - - .. method:: task_done() - - Indicate that a formerly enqueued task is complete. - - Used by queue consumers. For each :meth:`~Queue.get` used to fetch a task, a - subsequent call to :meth:`task_done` tells the queue that the processing - on the task is complete. - - If a :meth:`join` is currently blocking, it will resume when all items - have been processed (meaning that a :meth:`task_done` call was received - for every item that had been :meth:`~Queue.put` into the queue). - - Raises :exc:`ValueError` if called more times than there were items - placed in the queue. - - .. versionadded:: 3.4.3 - - .. attribute:: maxsize - - Number of items allowed in the queue. - - -PriorityQueue -^^^^^^^^^^^^^ - -.. class:: PriorityQueue - - A subclass of :class:`Queue`; retrieves entries in priority order (lowest - first). - - Entries are typically tuples of the form: (priority number, data). - - -LifoQueue -^^^^^^^^^ - -.. class:: LifoQueue - - A subclass of :class:`Queue` that retrieves most recently added entries - first. - - -JoinableQueue -^^^^^^^^^^^^^ - -.. class:: JoinableQueue - - Deprecated alias for :class:`Queue`. - - .. deprecated:: 3.4.3 - - -Exceptions -^^^^^^^^^^ - -.. exception:: QueueEmpty - - Exception raised when the :meth:`~Queue.get_nowait` method is called on a - :class:`Queue` object which is empty. - - -.. exception:: QueueFull - - Exception raised when the :meth:`~Queue.put_nowait` method is called on a - :class:`Queue` object which is full. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -209,6 +209,8 @@ :func:`~concurrent.futures.as_completed` functions in the :mod:`concurrent.futures` package. + This class is :ref:`not thread safe `. + .. method:: cancel() Cancel the future and schedule callbacks. @@ -375,6 +377,8 @@ Don't directly create :class:`Task` instances: use the :func:`async` function or the :meth:`BaseEventLoop.create_task` method. + This class is :ref:`not thread safe `. + .. classmethod:: all_tasks(loop=None) Return a set of all tasks for an event loop. diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -46,6 +46,11 @@ you absolutely, positively have to use a library that makes blocking I/O calls. +Asynchronous programming is more complex than classical "sequential" +programming: see the :ref:`Develop with asyncio ` page which lists +common traps and explains how to avoid them. :ref:`Enable the debug mode +` during development to detect common issues. + Table of contents: .. toctree:: @@ -58,6 +63,7 @@ asyncio-stream.rst asyncio-subprocess.rst asyncio-sync.rst + asyncio-queue.rst asyncio-dev.rst .. seealso:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 14:26:16 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 25 Feb 2015 13:26:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_begin_with_warnings_on_asyncio_traps?= Message-ID: <20150225132454.3857.71875@psf.io> https://hg.python.org/cpython/rev/909849f11fe9 changeset: 94741:909849f11fe9 branch: 3.4 user: Victor Stinner date: Wed Feb 25 14:23:51 2015 +0100 summary: asyncio doc: begin with warnings on asyncio traps files: Doc/library/asyncio.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -46,6 +46,11 @@ you absolutely, positively have to use a library that makes blocking I/O calls. +Asynchronous programming is more complex than classical "sequential" +programming: see the :ref:`Develop with asyncio ` page which lists +common traps and explains how to avoid them. :ref:`Enable the debug mode +` during development to detect common issues. + Table of contents: .. toctree:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 14:26:16 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 25 Feb 2015 13:26:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogYWRk?= =?utf-8?q?_a_note_about_=28non=29_thread_safety_in_each_class?= Message-ID: <20150225132454.109544.29017@psf.io> https://hg.python.org/cpython/rev/14e7a28235c6 changeset: 94742:14e7a28235c6 branch: 3.4 user: Victor Stinner date: Wed Feb 25 14:24:15 2015 +0100 summary: asyncio: add a note about (non) thread safety in each class files: Doc/library/asyncio-eventloop.rst | 5 +++++ Doc/library/asyncio-protocol.rst | 2 ++ Doc/library/asyncio-queue.rst | 2 ++ Doc/library/asyncio-stream.rst | 4 ++++ Doc/library/asyncio-subprocess.rst | 5 +++++ Doc/library/asyncio-task.rst | 4 ++++ 6 files changed, 22 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -22,6 +22,8 @@ Base class of event loops. + This class is :ref:`not thread safe `. + Run an event loop ----------------- @@ -104,6 +106,9 @@ Like :meth:`call_soon`, but thread safe. + See the :ref:`concurrency and multithreading ` + section of the documentation. + .. _asyncio-delayed-calls: diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -23,6 +23,8 @@ subprocess pipes. The methods available on a transport depend on the transport's kind. +The transport classes are :ref:`not thread safe `. + BaseTransport ------------- diff --git a/Doc/library/asyncio-queue.rst b/Doc/library/asyncio-queue.rst --- a/Doc/library/asyncio-queue.rst +++ b/Doc/library/asyncio-queue.rst @@ -31,6 +31,8 @@ be interrupted between calling :meth:`qsize` and doing an operation on the Queue. + This class is :ref:`not thread safe `. + .. versionchanged:: 3.4.3 New :meth:`join` and :meth:`task_done` methods. diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -85,6 +85,8 @@ .. class:: StreamReader(limit=None, loop=None) + This class is :ref:`not thread safe `. + .. method:: exception() Get the exception. @@ -155,6 +157,8 @@ wait for flow control. It also adds a transport attribute which references the :class:`Transport` directly. + This class is :ref:`not thread safe `. + .. attribute:: transport Transport. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -193,6 +193,9 @@ :meth:`~subprocess.Popen.wait` method of the :class:`~subprocess.Popen` class is implemented as a busy loop. + This class is :ref:`not thread safe `. See also the + :ref:`Subprocess and threads ` section. + .. coroutinemethod:: wait() Wait for child process to terminate. Set and return :attr:`returncode` @@ -310,6 +313,8 @@ subprocesses from other threads. Call the :func:`get_child_watcher` function in the main thread to instantiate the child watcher. +The :class:`asyncio.subprocess.Process` class is not thread safe. + .. seealso:: The :ref:`Concurrency and multithreading in asyncio diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -209,6 +209,8 @@ :func:`~concurrent.futures.as_completed` functions in the :mod:`concurrent.futures` package. + This class is :ref:`not thread safe `. + .. method:: cancel() Cancel the future and schedule callbacks. @@ -375,6 +377,8 @@ Don't directly create :class:`Task` instances: use the :func:`async` function or the :meth:`BaseEventLoop.create_task` method. + This class is :ref:`not thread safe `. + .. classmethod:: all_tasks(loop=None) Return a set of all tasks for an event loop. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 14:26:17 2015 From: python-checkins at python.org (victor.stinner) Date: Wed, 25 Feb 2015 13:26:17 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_move_queues_to_a_new_page?= Message-ID: <20150225132454.3887.17345@psf.io> https://hg.python.org/cpython/rev/fee2385e2eee changeset: 94740:fee2385e2eee branch: 3.4 parent: 94738:c113cdfef1e1 user: Victor Stinner date: Wed Feb 25 13:55:43 2015 +0100 summary: asyncio doc: move queues to a new page files: Doc/library/asyncio-sync.rst | 295 +---------------------- Doc/library/asyncio-sync.rst | 172 +------------ Doc/library/asyncio.rst | 1 + 3 files changed, 15 insertions(+), 453 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-queue.rst copy from Doc/library/asyncio-sync.rst copy to Doc/library/asyncio-queue.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-queue.rst @@ -1,16 +1,7 @@ .. currentmodule:: asyncio -.. _asyncio-sync: -Synchronization primitives -========================== - -Locks: - -* :class:`Lock` -* :class:`Event` -* :class:`Condition` -* :class:`Semaphore` -* :class:`BoundedSemaphore` +Queues +====== Queues: @@ -19,284 +10,14 @@ * :class:`LifoQueue` * :class:`JoinableQueue` -asyncio locks and queues API were designed to be close to classes of the -:mod:`threading` module (:class:`~threading.Lock`, :class:`~threading.Event`, -:class:`~threading.Condition`, :class:`~threading.Semaphore`, -:class:`~threading.BoundedSemaphore`) and the :mod:`queue` module -(:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, -:class:`~queue.LifoQueue`), but they have no *timeout* parameter. The +asyncio queue API was designed to be close to classes of the :mod:`queue` +module (:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, +:class:`~queue.LifoQueue`), but it has no *timeout* parameter. The :func:`asyncio.wait_for` function can be used to cancel a task after a timeout. -Locks +Queue ----- -Lock -^^^^ - -.. class:: Lock(\*, loop=None) - - Primitive lock objects. - - A primitive lock is a synchronization primitive that is not owned by a - particular coroutine when locked. A primitive lock is in one of two states, - 'locked' or 'unlocked'. - - It is created in the unlocked state. It has two basic methods, :meth:`acquire` - and :meth:`release`. When the state is unlocked, acquire() changes the state to - locked and returns immediately. When the state is locked, acquire() blocks - until a call to release() in another coroutine changes it to unlocked, then - the acquire() call resets it to locked and returns. The release() method - should only be called in the locked state; it changes the state to unlocked - and returns immediately. If an attempt is made to release an unlocked lock, - a :exc:`RuntimeError` will be raised. - - When more than one coroutine is blocked in acquire() waiting for the state - to turn to unlocked, only one coroutine proceeds when a release() call - resets the state to unlocked; first coroutine which is blocked in acquire() - is being processed. - - :meth:`acquire` is a coroutine and should be called with ``yield from``. - - Locks also support the context management protocol. ``(yield from lock)`` - should be used as context manager expression. - - Usage:: - - lock = Lock() - ... - yield from lock - try: - ... - finally: - lock.release() - - Context manager usage:: - - lock = Lock() - ... - with (yield from lock): - ... - - Lock objects can be tested for locking state:: - - if not lock.locked(): - yield from lock - else: - # lock is acquired - ... - - .. method:: locked() - - Return ``True`` if the lock is acquired. - - .. coroutinemethod:: acquire() - - Acquire a lock. - - This method blocks until the lock is unlocked, then sets it to locked and - returns ``True``. - - This method is a :ref:`coroutine `. - - .. method:: release() - - Release a lock. - - When the lock is locked, reset it to unlocked, and return. If any other - coroutines are blocked waiting for the lock to become unlocked, allow - exactly one of them to proceed. - - When invoked on an unlocked lock, a :exc:`RuntimeError` is raised. - - There is no return value. - - -Event -^^^^^ - -.. class:: Event(\*, loop=None) - - An Event implementation, asynchronous equivalent to :class:`threading.Event`. - - Class implementing event objects. An event manages a flag that can be set to - true with the :meth:`set` method and reset to false with the :meth:`clear` - method. The :meth:`wait` method blocks until the flag is true. The flag is - initially false. - - .. method:: clear() - - Reset the internal flag to false. Subsequently, coroutines calling - :meth:`wait` will block until :meth:`set` is called to set the internal - flag to true again. - - .. method:: is_set() - - Return ``True`` if and only if the internal flag is true. - - .. method:: set() - - Set the internal flag to true. All coroutines waiting for it to become - true are awakened. Coroutine that call :meth:`wait` once the flag is true - will not block at all. - - .. coroutinemethod:: wait() - - Block until the internal flag is true. - - If the internal flag is true on entry, return ``True`` immediately. - Otherwise, block until another coroutine calls :meth:`set` to set the - flag to true, then return ``True``. - - This method is a :ref:`coroutine `. - - -Condition -^^^^^^^^^ - -.. class:: Condition(lock=None, \*, loop=None) - - A Condition implementation, asynchronous equivalent to - :class:`threading.Condition`. - - This class implements condition variable objects. A condition variable - allows one or more coroutines to wait until they are notified by another - coroutine. - - If the *lock* argument is given and not ``None``, it must be a :class:`Lock` - object, and it is used as the underlying lock. Otherwise, - a new :class:`Lock` object is created and used as the underlying lock. - - .. coroutinemethod:: acquire() - - Acquire the underlying lock. - - This method blocks until the lock is unlocked, then sets it to locked and - returns ``True``. - - This method is a :ref:`coroutine `. - - .. method:: notify(n=1) - - By default, wake up one coroutine waiting on this condition, if any. - If the calling coroutine has not acquired the lock when this method is - called, a :exc:`RuntimeError` is raised. - - This method wakes up at most *n* of the coroutines waiting for the - condition variable; it is a no-op if no coroutines are waiting. - - .. note:: - - An awakened coroutine does not actually return from its :meth:`wait` - call until it can reacquire the lock. Since :meth:`notify` does not - release the lock, its caller should. - - .. method:: locked() - - Return ``True`` if the underlying lock is acquired. - - .. method:: notify_all() - - Wake up all threads waiting on this condition. This method acts like - :meth:`notify`, but wakes up all waiting threads instead of one. If the - calling thread has not acquired the lock when this method is called, a - :exc:`RuntimeError` is raised. - - .. method:: release() - - Release the underlying lock. - - When the lock is locked, reset it to unlocked, and return. If any other - coroutines are blocked waiting for the lock to become unlocked, allow - exactly one of them to proceed. - - When invoked on an unlocked lock, a :exc:`RuntimeError` is raised. - - There is no return value. - - .. coroutinemethod:: wait() - - Wait until notified. - - If the calling coroutine has not acquired the lock when this method is - called, a :exc:`RuntimeError` is raised. - - This method releases the underlying lock, and then blocks until it is - awakened by a :meth:`notify` or :meth:`notify_all` call for the same - condition variable in another coroutine. Once awakened, it re-acquires - the lock and returns ``True``. - - This method is a :ref:`coroutine `. - - .. coroutinemethod:: wait_for(predicate) - - Wait until a predicate becomes true. - - The predicate should be a callable which result will be interpreted as a - boolean value. The final predicate value is the return value. - - This method is a :ref:`coroutine `. - - -Semaphores ----------- - -Semaphore -^^^^^^^^^ - -.. class:: Semaphore(value=1, \*, loop=None) - - A Semaphore implementation. - - A semaphore manages an internal counter which is decremented by each - :meth:`acquire` call and incremented by each :meth:`release` call. The - counter can never go below zero; when :meth:`acquire` finds that it is zero, - it blocks, waiting until some other thread calls :meth:`release`. - - Semaphores also support the context management protocol. - - The optional argument gives the initial value for the internal counter; it - defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` - is raised. - - .. coroutinemethod:: acquire() - - Acquire a semaphore. - - If the internal counter is larger than zero on entry, decrement it by one - and return ``True`` immediately. If it is zero on entry, block, waiting - until some other coroutine has called :meth:`release` to make it larger - than ``0``, and then return ``True``. - - This method is a :ref:`coroutine `. - - .. method:: locked() - - Returns ``True`` if semaphore can not be acquired immediately. - - .. coroutinemethod:: release() - - Release a semaphore, incrementing the internal counter by one. When it - was zero on entry and another coroutine is waiting for it to become - larger than zero again, wake up that coroutine. - - -BoundedSemaphore -^^^^^^^^^^^^^^^^ - -.. class:: BoundedSemaphore(value=1, \*, loop=None) - - A bounded semaphore implementation. Inherit from :class:`Semaphore`. - - This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would - increase the value above the initial value. - - -Queues ------- - -Queue -^^^^^ - .. class:: Queue(maxsize=0, \*, loop=None) A queue, useful for coordinating producer and consumer coroutines. @@ -402,7 +123,7 @@ PriorityQueue -^^^^^^^^^^^^^ +------------- .. class:: PriorityQueue @@ -413,7 +134,7 @@ LifoQueue -^^^^^^^^^ +--------- .. class:: LifoQueue diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -9,22 +9,16 @@ * :class:`Lock` * :class:`Event` * :class:`Condition` + +Semaphores: + * :class:`Semaphore` * :class:`BoundedSemaphore` -Queues: - -* :class:`Queue` -* :class:`PriorityQueue` -* :class:`LifoQueue` -* :class:`JoinableQueue` - -asyncio locks and queues API were designed to be close to classes of the -:mod:`threading` module (:class:`~threading.Lock`, :class:`~threading.Event`, +asyncio lock API was designed to be close to classes of the :mod:`threading` +module (:class:`~threading.Lock`, :class:`~threading.Event`, :class:`~threading.Condition`, :class:`~threading.Semaphore`, -:class:`~threading.BoundedSemaphore`) and the :mod:`queue` module -(:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, -:class:`~queue.LifoQueue`), but they have no *timeout* parameter. The +:class:`~threading.BoundedSemaphore`), but it has no *timeout* parameter. The :func:`asyncio.wait_for` function can be used to cancel a task after a timeout. Locks @@ -290,157 +284,3 @@ This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would increase the value above the initial value. - -Queues ------- - -Queue -^^^^^ - -.. class:: Queue(maxsize=0, \*, loop=None) - - A queue, useful for coordinating producer and consumer coroutines. - - If *maxsize* is less than or equal to zero, the queue size is infinite. If - it is an integer greater than ``0``, then ``yield from put()`` will block - when the queue reaches *maxsize*, until an item is removed by :meth:`get`. - - Unlike the standard library :mod:`queue`, you can reliably know this Queue's - size with :meth:`qsize`, since your single-threaded asyncio application won't - be interrupted between calling :meth:`qsize` and doing an operation on the - Queue. - - .. versionchanged:: 3.4.3 - New :meth:`join` and :meth:`task_done` methods. - - .. method:: empty() - - Return ``True`` if the queue is empty, ``False`` otherwise. - - .. method:: full() - - Return ``True`` if there are :attr:`maxsize` items in the queue. - - .. note:: - - If the Queue was initialized with ``maxsize=0`` (the default), then - :meth:`full()` is never ``True``. - - .. coroutinemethod:: get() - - Remove and return an item from the queue. If queue is empty, wait until - an item is available. - - This method is a :ref:`coroutine `. - - .. seealso:: - - The :meth:`empty` method. - - .. method:: get_nowait() - - Remove and return an item from the queue. - - Return an item if one is immediately available, else raise - :exc:`QueueEmpty`. - - .. coroutinemethod:: join() - - Block until all items in the queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls - :meth:`task_done` to indicate that the item was retrieved and all work on - it is complete. When the count of unfinished tasks drops to zero, - :meth:`join` unblocks. - - This method is a :ref:`coroutine `. - - .. versionadded:: 3.4.3 - - .. coroutinemethod:: put(item) - - Put an item into the queue. If the queue is full, wait until a free slot - is available before adding item. - - This method is a :ref:`coroutine `. - - .. seealso:: - - The :meth:`full` method. - - .. method:: put_nowait(item) - - Put an item into the queue without blocking. - - If no free slot is immediately available, raise :exc:`QueueFull`. - - .. method:: qsize() - - Number of items in the queue. - - .. method:: task_done() - - Indicate that a formerly enqueued task is complete. - - Used by queue consumers. For each :meth:`~Queue.get` used to fetch a task, a - subsequent call to :meth:`task_done` tells the queue that the processing - on the task is complete. - - If a :meth:`join` is currently blocking, it will resume when all items - have been processed (meaning that a :meth:`task_done` call was received - for every item that had been :meth:`~Queue.put` into the queue). - - Raises :exc:`ValueError` if called more times than there were items - placed in the queue. - - .. versionadded:: 3.4.3 - - .. attribute:: maxsize - - Number of items allowed in the queue. - - -PriorityQueue -^^^^^^^^^^^^^ - -.. class:: PriorityQueue - - A subclass of :class:`Queue`; retrieves entries in priority order (lowest - first). - - Entries are typically tuples of the form: (priority number, data). - - -LifoQueue -^^^^^^^^^ - -.. class:: LifoQueue - - A subclass of :class:`Queue` that retrieves most recently added entries - first. - - -JoinableQueue -^^^^^^^^^^^^^ - -.. class:: JoinableQueue - - Deprecated alias for :class:`Queue`. - - .. deprecated:: 3.4.3 - - -Exceptions -^^^^^^^^^^ - -.. exception:: QueueEmpty - - Exception raised when the :meth:`~Queue.get_nowait` method is called on a - :class:`Queue` object which is empty. - - -.. exception:: QueueFull - - Exception raised when the :meth:`~Queue.put_nowait` method is called on a - :class:`Queue` object which is full. diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -58,6 +58,7 @@ asyncio-stream.rst asyncio-subprocess.rst asyncio-sync.rst + asyncio-queue.rst asyncio-dev.rst .. seealso:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 16:17:07 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 25 Feb 2015 15:17:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogZml4IG1lcmdlX2Nv?= =?utf-8?q?llapse_to_actually_maintain_the_invariant_it_purports_to_=28clo?= =?utf-8?q?ses?= Message-ID: <20150225151706.109546.33442@psf.io> https://hg.python.org/cpython/rev/325aec842e3e changeset: 94744:325aec842e3e branch: 2.7 parent: 94737:8969c7f44d9e user: Benjamin Peterson date: Wed Feb 25 10:12:26 2015 -0500 summary: fix merge_collapse to actually maintain the invariant it purports to (closes #23515) See de Gouw, Stijn and Rot, Jurriaan and de Boer, Frank S and Bubel, Richard and H?hnle, Reiner "OpenJDK?s java.utils.Collection.sort() is broken: The good, the bad and the worst case" files: Objects/listobject.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1800,7 +1800,8 @@ assert(ms); while (ms->n > 1) { Py_ssize_t n = ms->n - 2; - if (n > 0 && p[n-1].len <= p[n].len + p[n+1].len) { + if ((n > 0 && p[n-1].len <= p[n].len + p[n+1].len) || + (n > 1 && p[n-2].len <= p[n-1].len + p[n].len)) { if (p[n-1].len < p[n+1].len) --n; if (merge_at(ms, n) < 0) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 16:17:07 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 25 Feb 2015 15:17:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjM1MTUp?= Message-ID: <20150225151706.116377.32080@psf.io> https://hg.python.org/cpython/rev/be5ddc8b6a88 changeset: 94746:be5ddc8b6a88 parent: 94743:a727eed3a811 parent: 94745:620cb13008b7 user: Benjamin Peterson date: Wed Feb 25 10:16:56 2015 -0500 summary: merge 3.4 (#23515) files: Objects/listobject.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1832,7 +1832,8 @@ assert(ms); while (ms->n > 1) { Py_ssize_t n = ms->n - 2; - if (n > 0 && p[n-1].len <= p[n].len + p[n+1].len) { + if ((n > 0 && p[n-1].len <= p[n].len + p[n+1].len) || + (n > 1 && p[n-2].len <= p[n-1].len + p[n].len)) { if (p[n-1].len < p[n+1].len) --n; if (merge_at(ms, n) < 0) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 16:17:07 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 25 Feb 2015 15:17:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogZml4IG1lcmdlX2Nv?= =?utf-8?q?llapse_to_actually_maintain_the_invariant_it_purports_to_=28clo?= =?utf-8?q?ses?= Message-ID: <20150225151706.116383.95192@psf.io> https://hg.python.org/cpython/rev/620cb13008b7 changeset: 94745:620cb13008b7 branch: 3.4 parent: 94742:14e7a28235c6 user: Benjamin Peterson date: Wed Feb 25 10:12:26 2015 -0500 summary: fix merge_collapse to actually maintain the invariant it purports to (closes #23515) See de Gouw, Stijn and Rot, Jurriaan and de Boer, Frank S and Bubel, Richard and H?hnle, Reiner "OpenJDK?s java.utils.Collection.sort() is broken: The good, the bad and the worst case" files: Objects/listobject.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1832,7 +1832,8 @@ assert(ms); while (ms->n > 1) { Py_ssize_t n = ms->n - 2; - if (n > 0 && p[n-1].len <= p[n].len + p[n+1].len) { + if ((n > 0 && p[n-1].len <= p[n].len + p[n+1].len) || + (n > 1 && p[n-2].len <= p[n-1].len + p[n].len)) { if (p[n-1].len < p[n+1].len) --n; if (merge_at(ms, n) < 0) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 16:18:55 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 25 Feb 2015 15:18:55 +0000 Subject: [Python-checkins] =?utf-8?q?devguide=3A_Added_the_=22argument_cli?= =?utf-8?q?nic=22_interest_area=2E?= Message-ID: <20150225151853.29668.45073@psf.io> https://hg.python.org/devguide/rev/0d97fefd1a4a changeset: 729:0d97fefd1a4a user: Serhiy Storchaka date: Wed Feb 25 17:18:38 2015 +0200 summary: Added the "argument clinic" interest area. files: experts.rst | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -304,6 +304,7 @@ Interest Area Maintainers ================== =========== algorithms +argument clinic larry ast/compiler ncoghlan, benjamin.peterson, brett.cannon, georg.brandl autoconf/makefiles bsd -- Repository URL: https://hg.python.org/devguide From python-checkins at python.org Wed Feb 25 17:14:42 2015 From: python-checkins at python.org (berker.peksag) Date: Wed, 25 Feb 2015 16:14:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2323511=3A_Port_email-simple=2Epy_to_Python_3=2E?= Message-ID: <20150225161436.6716.40627@psf.io> https://hg.python.org/cpython/rev/cb911e1fb3dc changeset: 94748:cb911e1fb3dc parent: 94746:be5ddc8b6a88 parent: 94747:89c6a6c2dd1f user: Berker Peksag date: Wed Feb 25 18:14:47 2015 +0200 summary: Issue #23511: Port email-simple.py to Python 3. Also, update email examples to use the context manager version of open(). Patch by Baptiste Mispelon. files: Doc/includes/email-headers.py | 5 +++-- Doc/includes/email-mime.py | 5 ++--- Doc/includes/email-read-alternative-new-api.py | 3 ++- Doc/includes/email-simple.py | 7 +++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/includes/email-headers.py b/Doc/includes/email-headers.py --- a/Doc/includes/email-headers.py +++ b/Doc/includes/email-headers.py @@ -1,8 +1,9 @@ # Import the email modules we'll need from email.parser import Parser -# If the e-mail headers are in a file, uncomment this line: -#headers = Parser().parse(open(messagefile, 'r')) +# If the e-mail headers are in a file, uncomment these two lines: +# with open(messagefile) as fp: +# headers = Parser().parse(fp) # Or for parsing headers in a string, use: headers = Parser().parsestr('From: \n' diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -20,9 +20,8 @@ for file in pngfiles: # Open the files in binary mode. Let the MIMEImage class automatically # guess the specific image type. - fp = open(file, 'rb') - img = MIMEImage(fp.read()) - fp.close() + with open(file, 'rb') as fp: + img = MIMEImage(fp.read()) msg.attach(img) # Send the email via our own SMTP server. diff --git a/Doc/includes/email-read-alternative-new-api.py b/Doc/includes/email-read-alternative-new-api.py --- a/Doc/includes/email-read-alternative-new-api.py +++ b/Doc/includes/email-read-alternative-new-api.py @@ -12,7 +12,8 @@ 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')) +with open('outgoing.msg', 'rb') as fp: + msg = BytesParser(policy=policy.default).parse(fp) # Now the header items can be accessed as a dictionary, and any non-ASCII will # be converted to unicode: diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -6,10 +6,9 @@ # Open a plain text file for reading. For this example, assume that # the text file contains only ASCII characters. -fp = open(textfile, 'rb') -# Create a text/plain message -msg = MIMEText(fp.read()) -fp.close() +with open(textfile) as fp: + # Create a text/plain message + msg = MIMEText(fp.read()) # me == the sender's email address # you == the recipient's email address -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 17:15:05 2015 From: python-checkins at python.org (berker.peksag) Date: Wed, 25 Feb 2015 16:15:05 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNTEx?= =?utf-8?q?=3A_Port_email-simple=2Epy_to_Python_3=2E?= Message-ID: <20150225161436.3881.68913@psf.io> https://hg.python.org/cpython/rev/89c6a6c2dd1f changeset: 94747:89c6a6c2dd1f branch: 3.4 parent: 94745:620cb13008b7 user: Berker Peksag date: Wed Feb 25 18:14:09 2015 +0200 summary: Issue #23511: Port email-simple.py to Python 3. Also, update email examples to use the context manager version of open(). Patch by Baptiste Mispelon. files: Doc/includes/email-headers.py | 5 +++-- Doc/includes/email-mime.py | 5 ++--- Doc/includes/email-read-alternative-new-api.py | 3 ++- Doc/includes/email-simple.py | 7 +++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/includes/email-headers.py b/Doc/includes/email-headers.py --- a/Doc/includes/email-headers.py +++ b/Doc/includes/email-headers.py @@ -1,8 +1,9 @@ # Import the email modules we'll need from email.parser import Parser -# If the e-mail headers are in a file, uncomment this line: -#headers = Parser().parse(open(messagefile, 'r')) +# If the e-mail headers are in a file, uncomment these two lines: +# with open(messagefile) as fp: +# headers = Parser().parse(fp) # Or for parsing headers in a string, use: headers = Parser().parsestr('From: \n' diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -20,9 +20,8 @@ for file in pngfiles: # Open the files in binary mode. Let the MIMEImage class automatically # guess the specific image type. - fp = open(file, 'rb') - img = MIMEImage(fp.read()) - fp.close() + with open(file, 'rb') as fp: + img = MIMEImage(fp.read()) msg.attach(img) # Send the email via our own SMTP server. diff --git a/Doc/includes/email-read-alternative-new-api.py b/Doc/includes/email-read-alternative-new-api.py --- a/Doc/includes/email-read-alternative-new-api.py +++ b/Doc/includes/email-read-alternative-new-api.py @@ -12,7 +12,8 @@ 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')) +with open('outgoing.msg', 'rb') as fp: + msg = BytesParser(policy=policy.default).parse(fp) # Now the header items can be accessed as a dictionary, and any non-ASCII will # be converted to unicode: diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -6,10 +6,9 @@ # Open a plain text file for reading. For this example, assume that # the text file contains only ASCII characters. -fp = open(textfile, 'rb') -# Create a text/plain message -msg = MIMEText(fp.read()) -fp.close() +with open(textfile) as fp: + # Create a text/plain message + msg = MIMEText(fp.read()) # me == the sender's email address # you == the recipient's email address -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 22:47:25 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 25 Feb 2015 21:47:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150225214725.10182.4585@psf.io> https://hg.python.org/cpython/rev/1bb9641713ec changeset: 94750:1bb9641713ec parent: 94748:cb911e1fb3dc parent: 94749:40a0c68ead00 user: Benjamin Peterson date: Wed Feb 25 16:47:20 2015 -0500 summary: merge 3.4 files: Lib/test/test_statistics.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -9,7 +9,6 @@ import math import random import sys -import types import unittest from decimal import Decimal -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Feb 25 22:47:31 2015 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 25 Feb 2015 21:47:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_remove_unused_?= =?utf-8?q?import?= Message-ID: <20150225214725.109538.62190@psf.io> https://hg.python.org/cpython/rev/40a0c68ead00 changeset: 94749:40a0c68ead00 branch: 3.4 parent: 94747:89c6a6c2dd1f user: Benjamin Peterson date: Wed Feb 25 16:47:14 2015 -0500 summary: remove unused import files: Lib/test/test_statistics.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -9,7 +9,6 @@ import math import random import sys -import types import unittest from decimal import Decimal -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 05:39:24 2015 From: python-checkins at python.org (steve.dower) Date: Thu, 26 Feb 2015 04:39:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Adds_=5FCRT=5FNON=5FCONFOR?= =?utf-8?q?MING=5FWCSTOK_to_retain_two-parameter_wcstok=2E?= Message-ID: <20150226043910.116377.6768@psf.io> https://hg.python.org/cpython/rev/e0d7134c35ed changeset: 94751:e0d7134c35ed user: Steve Dower date: Wed Feb 25 20:38:31 2015 -0800 summary: Adds _CRT_NON_CONFORMING_WCSTOK to retain two-parameter wcstok. files: PCbuild/pythoncore.vcxproj | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -67,7 +67,7 @@ /Zm200 %(AdditionalOptions) $(PySourcePath)Python;$(PySourcePath)Modules\zlib;%(AdditionalIncludeDirectories) - _USRDLL;Py_BUILD_CORE;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) + _CRT_NON_CONFORMING_WCSTOK;_USRDLL;Py_BUILD_CORE;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) ws2_32.lib;%(AdditionalDependencies) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 05:49:26 2015 From: python-checkins at python.org (steve.dower) Date: Thu, 26 Feb 2015 04:49:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Back-out_wcstok_deprecatio?= =?utf-8?q?n_suppression_and_updates_calls_to_use_wcstok=5Fs=2E?= Message-ID: <20150226044908.99321.48069@psf.io> https://hg.python.org/cpython/rev/8545624309f5 changeset: 94752:8545624309f5 user: Steve Dower date: Wed Feb 25 20:48:01 2015 -0800 summary: Back-out wcstok deprecation suppression and updates calls to use wcstok_s. files: Modules/main.c | 6 +++--- PC/getpathp.c | 7 ++++--- PCbuild/pythoncore.vcxproj | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -520,16 +520,16 @@ #ifdef MS_WINDOWS if (!Py_IgnoreEnvironmentFlag && (wp = _wgetenv(L"PYTHONWARNINGS")) && *wp != L'\0') { - wchar_t *buf, *warning; + wchar_t *buf, *warning, *context = NULL; buf = (wchar_t *)PyMem_RawMalloc((wcslen(wp) + 1) * sizeof(wchar_t)); if (buf == NULL) Py_FatalError( "not enough memory to copy PYTHONWARNINGS"); wcscpy(buf, wp); - for (warning = wcstok(buf, L","); + for (warning = wcstok_s(buf, L",", &context); warning != NULL; - warning = wcstok(NULL, L",")) { + warning = wcstok_s(NULL, L",", &context)) { PySys_AddWarnOption(warning); } PyMem_RawFree(buf); diff --git a/PC/getpathp.c b/PC/getpathp.c --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -451,11 +451,12 @@ tmpbuffer, MAXPATHLEN * 2); Py_DECREF(decoded); if (k >= 0) { - wchar_t * tok = wcstok(tmpbuffer, L" \t\r\n"); + wchar_t * context = NULL; + wchar_t * tok = wcstok_s(tmpbuffer, L" \t\r\n", &context); if ((tok != NULL) && !wcscmp(tok, key)) { - tok = wcstok(NULL, L" \t"); + tok = wcstok_s(NULL, L" \t", &context); if ((tok != NULL) && !wcscmp(tok, L"=")) { - tok = wcstok(NULL, L"\r\n"); + tok = wcstok_s(NULL, L"\r\n", &context); if (tok != NULL) { wcsncpy(value, tok, MAXPATHLEN); result = 1; diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -67,7 +67,7 @@ /Zm200 %(AdditionalOptions) $(PySourcePath)Python;$(PySourcePath)Modules\zlib;%(AdditionalIncludeDirectories) - _CRT_NON_CONFORMING_WCSTOK;_USRDLL;Py_BUILD_CORE;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) + _USRDLL;Py_BUILD_CORE;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) ws2_32.lib;%(AdditionalDependencies) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 10:39:39 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 26 Feb 2015 09:39:39 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_lock_classes_are_not_thread_safe?= Message-ID: <20150226093937.87095.96255@psf.io> https://hg.python.org/cpython/rev/366e3ad5e3bd changeset: 94753:366e3ad5e3bd branch: 3.4 parent: 94749:40a0c68ead00 user: Victor Stinner date: Thu Feb 26 10:39:16 2015 +0100 summary: asyncio doc: lock classes are not thread safe files: Doc/library/asyncio-sync.rst | 14 +++++++++++--- 1 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -54,6 +54,8 @@ Locks also support the context management protocol. ``(yield from lock)`` should be used as context manager expression. + This class is :ref:`not thread safe `. + Usage:: lock = Lock() @@ -117,6 +119,8 @@ method. The :meth:`wait` method blocks until the flag is true. The flag is initially false. + This class is :ref:`not thread safe `. + .. method:: clear() Reset the internal flag to false. Subsequently, coroutines calling @@ -160,6 +164,8 @@ object, and it is used as the underlying lock. Otherwise, a new :class:`Lock` object is created and used as the underlying lock. + This class is :ref:`not thread safe `. + .. coroutinemethod:: acquire() Acquire the underlying lock. @@ -252,6 +258,8 @@ defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` is raised. + This class is :ref:`not thread safe `. + .. coroutinemethod:: acquire() Acquire a semaphore. @@ -279,8 +287,8 @@ .. class:: BoundedSemaphore(value=1, \*, loop=None) - A bounded semaphore implementation. Inherit from :class:`Semaphore`. + A bounded semaphore implementation. Inherit from :class:`Semaphore`. - This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would - increase the value above the initial value. + This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would + increase the value above the initial value. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 10:39:39 2015 From: python-checkins at python.org (victor.stinner) Date: Thu, 26 Feb 2015 09:39:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio_doc=29?= Message-ID: <20150226093937.29668.24637@psf.io> https://hg.python.org/cpython/rev/7185a35fb293 changeset: 94754:7185a35fb293 parent: 94752:8545624309f5 parent: 94753:366e3ad5e3bd user: Victor Stinner date: Thu Feb 26 10:39:31 2015 +0100 summary: Merge 3.4 (asyncio doc) files: Doc/library/asyncio-sync.rst | 14 +++++++++++--- 1 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -54,6 +54,8 @@ Locks also support the context management protocol. ``(yield from lock)`` should be used as context manager expression. + This class is :ref:`not thread safe `. + Usage:: lock = Lock() @@ -117,6 +119,8 @@ method. The :meth:`wait` method blocks until the flag is true. The flag is initially false. + This class is :ref:`not thread safe `. + .. method:: clear() Reset the internal flag to false. Subsequently, coroutines calling @@ -160,6 +164,8 @@ object, and it is used as the underlying lock. Otherwise, a new :class:`Lock` object is created and used as the underlying lock. + This class is :ref:`not thread safe `. + .. coroutinemethod:: acquire() Acquire the underlying lock. @@ -252,6 +258,8 @@ defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` is raised. + This class is :ref:`not thread safe `. + .. coroutinemethod:: acquire() Acquire a semaphore. @@ -279,8 +287,8 @@ .. class:: BoundedSemaphore(value=1, \*, loop=None) - A bounded semaphore implementation. Inherit from :class:`Semaphore`. + A bounded semaphore implementation. Inherit from :class:`Semaphore`. - This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would - increase the value above the initial value. + This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would + increase the value above the initial value. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 13:11:19 2015 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 26 Feb 2015 12:11:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315955=3A_Add_an_o?= =?utf-8?q?ption_to_limit_the_output_size_in_bz2=2Edecompress=28=29=2E?= Message-ID: <20150226120954.39377.90838@psf.io> https://hg.python.org/cpython/rev/10dab1b596d4 changeset: 94755:10dab1b596d4 user: Antoine Pitrou date: Thu Feb 26 13:08:07 2015 +0100 summary: Issue #15955: Add an option to limit the output size in bz2.decompress(). Patch by Nikolaus Rath. files: Doc/library/bz2.rst | 36 ++- Lib/test/test_bz2.py | 103 ++++++++ Misc/NEWS | 3 + Modules/_bz2module.c | 263 ++++++++++++++++----- Modules/clinic/_bz2module.c.h | 37 +- 5 files changed, 362 insertions(+), 80 deletions(-) diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -162,15 +162,32 @@ you need to decompress a multi-stream input with :class:`BZ2Decompressor`, you must use a new decompressor for each stream. - .. method:: decompress(data) + .. method:: decompress(data, max_length=-1) - Provide data to the decompressor object. Returns a chunk of decompressed - data if possible, or an empty byte string otherwise. + Decompress *data* (a :term:`bytes-like object`), returning + uncompressed data as bytes. Some of *data* may be buffered + internally, for use in later calls to :meth:`decompress`. The + returned data should be concatenated with the output of any + previous calls to :meth:`decompress`. - Attempting to decompress data after the end of the current stream is - reached raises an :exc:`EOFError`. If any data is found after the end of - the stream, it is ignored and saved in the :attr:`unused_data` attribute. + If *max_length* is nonnegative, returns at most *max_length* + bytes of decompressed data. If this limit is reached and further + output can be produced, the :attr:`~.needs_input` attribute will + be set to ``False``. In this case, the next call to + :meth:`~.decompress` may provide *data* as ``b''`` to obtain + more of the output. + If all of the input data was decompressed and returned (either + because this was less than *max_length* bytes, or because + *max_length* was negative), the :attr:`~.needs_input` attribute + will be set to ``True``. + + Attempting to decompress data after the end of stream is reached + raises an `EOFError`. Any data found after the end of the + stream is ignored and saved in the :attr:`~.unused_data` attribute. + + .. versionchanged:: 3.5 + Added the *max_length* parameter. .. attribute:: eof @@ -186,6 +203,13 @@ If this attribute is accessed before the end of the stream has been reached, its value will be ``b''``. + .. attribute:: needs_input + + ``False`` if the :meth:`.decompress` method can provide more + decompressed data before requiring new uncompressed input. + + .. versionadded:: 3.5 + One-shot (de)compression ------------------------ diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -5,6 +5,7 @@ from io import BytesIO import os import pickle +import glob import random import subprocess import sys @@ -51,6 +52,19 @@ EMPTY_DATA = b'BZh9\x17rE8P\x90\x00\x00\x00\x00' BAD_DATA = b'this is not a valid bzip2 file' + # Some tests need more than one block of uncompressed data. Since one block + # is at least 100 kB, we gather some data dynamically and compress it. + # Note that this assumes that compression works correctly, so we cannot + # simply use the bigger test data for all tests. + test_size = 0 + BIG_TEXT = bytearray(128*1024) + for fname in glob.glob(os.path.join(os.path.dirname(__file__), '*.py')): + with open(fname, 'rb') as fh: + test_size += fh.readinto(memoryview(BIG_TEXT)[test_size:]) + if test_size > 128*1024: + break + BIG_DATA = bz2.compress(BIG_TEXT, compresslevel=1) + def setUp(self): self.filename = support.TESTFN @@ -707,6 +721,95 @@ with self.assertRaises(TypeError): pickle.dumps(BZ2Decompressor(), proto) + def testDecompressorChunksMaxsize(self): + bzd = BZ2Decompressor() + max_length = 100 + out = [] + + # Feed some input + len_ = len(self.BIG_DATA) - 64 + out.append(bzd.decompress(self.BIG_DATA[:len_], + max_length=max_length)) + self.assertFalse(bzd.needs_input) + self.assertEqual(len(out[-1]), max_length) + + # Retrieve more data without providing more input + out.append(bzd.decompress(b'', max_length=max_length)) + self.assertFalse(bzd.needs_input) + self.assertEqual(len(out[-1]), max_length) + + # Retrieve more data while providing more input + out.append(bzd.decompress(self.BIG_DATA[len_:], + max_length=max_length)) + self.assertLessEqual(len(out[-1]), max_length) + + # Retrieve remaining uncompressed data + while not bzd.eof: + out.append(bzd.decompress(b'', max_length=max_length)) + self.assertLessEqual(len(out[-1]), max_length) + + out = b"".join(out) + self.assertEqual(out, self.BIG_TEXT) + self.assertEqual(bzd.unused_data, b"") + + def test_decompressor_inputbuf_1(self): + # Test reusing input buffer after moving existing + # contents to beginning + bzd = BZ2Decompressor() + out = [] + + # Create input buffer and fill it + self.assertEqual(bzd.decompress(self.DATA[:100], + max_length=0), b'') + + # Retrieve some results, freeing capacity at beginning + # of input buffer + out.append(bzd.decompress(b'', 2)) + + # Add more data that fits into input buffer after + # moving existing data to beginning + out.append(bzd.decompress(self.DATA[100:105], 15)) + + # Decompress rest of data + out.append(bzd.decompress(self.DATA[105:])) + self.assertEqual(b''.join(out), self.TEXT) + + def test_decompressor_inputbuf_2(self): + # Test reusing input buffer by appending data at the + # end right away + bzd = BZ2Decompressor() + out = [] + + # Create input buffer and empty it + self.assertEqual(bzd.decompress(self.DATA[:200], + max_length=0), b'') + out.append(bzd.decompress(b'')) + + # Fill buffer with new data + out.append(bzd.decompress(self.DATA[200:280], 2)) + + # Append some more data, not enough to require resize + out.append(bzd.decompress(self.DATA[280:300], 2)) + + # Decompress rest of data + out.append(bzd.decompress(self.DATA[300:])) + self.assertEqual(b''.join(out), self.TEXT) + + def test_decompressor_inputbuf_3(self): + # Test reusing input buffer after extending it + + bzd = BZ2Decompressor() + out = [] + + # Create almost full input buffer + out.append(bzd.decompress(self.DATA[:200], 5)) + + # Add even more data to it, requiring resize + out.append(bzd.decompress(self.DATA[200:300], 5)) + + # Decompress rest of data + out.append(bzd.decompress(self.DATA[300:])) + self.assertEqual(b''.join(out), self.TEXT) class CompressDecompressTest(BaseTest): def testCompress(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #15955: Add an option to limit the output size in bz2.decompress(). + Patch by Nikolaus Rath. + - Issue #6639: Module-level turtle functions no longer raise TclError after closing the window. diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -51,6 +51,14 @@ bz_stream bzs; char eof; /* T_BOOL expects a char */ PyObject *unused_data; + char needs_input; + char *input_buffer; + size_t input_buffer_size; + + /* bzs->avail_in is only 32 bit, so we store the true length + separately. Conversion and looping is encapsulated in + decompress_buf() */ + size_t bzs_avail_in_real; #ifdef WITH_THREAD PyThread_type_lock lock; #endif @@ -111,19 +119,23 @@ } #if BUFSIZ < 8192 -#define SMALLCHUNK 8192 +#define INITIAL_BUFFER_SIZE 8192 #else -#define SMALLCHUNK BUFSIZ +#define INITIAL_BUFFER_SIZE BUFSIZ #endif static int -grow_buffer(PyObject **buf) +grow_buffer(PyObject **buf, Py_ssize_t max_length) { /* Expand the buffer by an amount proportional to the current size, giving us amortized linear-time behavior. Use a less-than-double growth factor to avoid excessive allocation. */ size_t size = PyBytes_GET_SIZE(*buf); size_t new_size = size + (size >> 3) + 6; + + if (max_length > 0 && new_size > (size_t) max_length) + new_size = (size_t) max_length; + if (new_size > size) { return _PyBytes_Resize(buf, new_size); } else { /* overflow */ @@ -142,14 +154,14 @@ size_t data_size = 0; PyObject *result; - result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); + result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE); if (result == NULL) return NULL; c->bzs.next_in = data; c->bzs.avail_in = 0; c->bzs.next_out = PyBytes_AS_STRING(result); - c->bzs.avail_out = SMALLCHUNK; + c->bzs.avail_out = INITIAL_BUFFER_SIZE; for (;;) { char *this_out; int bzerror; @@ -168,7 +180,7 @@ if (c->bzs.avail_out == 0) { size_t buffer_left = PyBytes_GET_SIZE(result) - data_size; if (buffer_left == 0) { - if (grow_buffer(&result) < 0) + if (grow_buffer(&result, -1) < 0) goto error; c->bzs.next_out = PyBytes_AS_STRING(result) + data_size; buffer_left = PyBytes_GET_SIZE(result) - data_size; @@ -402,64 +414,176 @@ /* BZ2Decompressor class. */ -static PyObject * -decompress(BZ2Decompressor *d, char *data, size_t len) +/* Decompress data of length d->bzs_avail_in_real in d->bzs.next_in. The output + buffer is allocated dynamically and returned. At most max_length bytes are + returned, so some of the input may not be consumed. d->bzs.next_in and + d->bzs_avail_in_real are updated to reflect the consumed input. */ +static PyObject* +decompress_buf(BZ2Decompressor *d, Py_ssize_t max_length) { - size_t data_size = 0; + /* data_size is strictly positive, but because we repeatedly have to + compare against max_length and PyBytes_GET_SIZE we declare it as + signed */ + Py_ssize_t data_size = 0; PyObject *result; + bz_stream *bzs = &d->bzs; - result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); + if (max_length < 0 || max_length >= INITIAL_BUFFER_SIZE) + result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE); + else + result = PyBytes_FromStringAndSize(NULL, max_length); if (result == NULL) - return result; - d->bzs.next_in = data; - /* On a 64-bit system, len might not fit in avail_in (an unsigned int). - Do decompression in chunks of no more than UINT_MAX bytes each. */ - d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX); - len -= d->bzs.avail_in; - d->bzs.next_out = PyBytes_AS_STRING(result); - d->bzs.avail_out = SMALLCHUNK; + return NULL; + + bzs->next_out = PyBytes_AS_STRING(result); for (;;) { - char *this_out; - int bzerror; + int bzret; + size_t avail; + + /* On a 64-bit system, buffer length might not fit in avail_out, so we + do decompression in chunks of no more than UINT_MAX bytes + each. Note that the expression for `avail` is guaranteed to be + positive, so the cast is safe. */ + avail = (size_t) (PyBytes_GET_SIZE(result) - data_size); + bzs->avail_out = (unsigned int)Py_MIN(avail, UINT_MAX); + bzs->avail_in = (unsigned int)Py_MIN(d->bzs_avail_in_real, UINT_MAX); + d->bzs_avail_in_real -= bzs->avail_in; Py_BEGIN_ALLOW_THREADS - this_out = d->bzs.next_out; - bzerror = BZ2_bzDecompress(&d->bzs); - data_size += d->bzs.next_out - this_out; + bzret = BZ2_bzDecompress(bzs); + data_size = bzs->next_out - PyBytes_AS_STRING(result); + d->bzs_avail_in_real += bzs->avail_in; Py_END_ALLOW_THREADS - if (catch_bz2_error(bzerror)) + if (catch_bz2_error(bzret)) goto error; - if (bzerror == BZ_STREAM_END) { + if (bzret == BZ_STREAM_END) { d->eof = 1; - len += d->bzs.avail_in; - if (len > 0) { /* Save leftover input to unused_data */ - Py_CLEAR(d->unused_data); - d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, len); - if (d->unused_data == NULL) - goto error; - } break; - } - if (d->bzs.avail_in == 0) { - if (len == 0) + } else if (d->bzs_avail_in_real == 0) { + break; + } else if (bzs->avail_out == 0) { + if (data_size == max_length) break; - d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX); - len -= d->bzs.avail_in; - } - if (d->bzs.avail_out == 0) { - size_t buffer_left = PyBytes_GET_SIZE(result) - data_size; - if (buffer_left == 0) { - if (grow_buffer(&result) < 0) - goto error; - d->bzs.next_out = PyBytes_AS_STRING(result) + data_size; - buffer_left = PyBytes_GET_SIZE(result) - data_size; - } - d->bzs.avail_out = (unsigned int)Py_MIN(buffer_left, UINT_MAX); + if (data_size == PyBytes_GET_SIZE(result) && + grow_buffer(&result, max_length) == -1) + goto error; + bzs->next_out = PyBytes_AS_STRING(result) + data_size; } } - if (data_size != (size_t)PyBytes_GET_SIZE(result)) - if (_PyBytes_Resize(&result, data_size) < 0) + if (data_size != PyBytes_GET_SIZE(result)) + if (_PyBytes_Resize(&result, data_size) == -1) goto error; + + return result; + +error: + Py_XDECREF(result); + return NULL; +} + + +static PyObject * +decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length) +{ + char input_buffer_in_use; + PyObject *result; + bz_stream *bzs = &d->bzs; + + /* Prepend unconsumed input if necessary */ + if (bzs->next_in != NULL) { + size_t avail_now, avail_total; + + /* Number of bytes we can append to input buffer */ + avail_now = (d->input_buffer + d->input_buffer_size) + - (bzs->next_in + d->bzs_avail_in_real); + + /* Number of bytes we can append if we move existing + contents to beginning of buffer (overwriting + consumed input) */ + avail_total = d->input_buffer_size - d->bzs_avail_in_real; + + if (avail_total < len) { + size_t offset = bzs->next_in - d->input_buffer; + char *tmp; + size_t new_size = d->input_buffer_size + len - avail_now; + + /* Assign to temporary variable first, so we don't + lose address of allocated buffer if realloc fails */ + tmp = PyMem_Realloc(d->input_buffer, new_size); + if (tmp == NULL) { + PyErr_SetNone(PyExc_MemoryError); + return NULL; + } + d->input_buffer = tmp; + d->input_buffer_size = new_size; + + bzs->next_in = d->input_buffer + offset; + } + else if (avail_now < len) { + memmove(d->input_buffer, bzs->next_in, + d->bzs_avail_in_real); + bzs->next_in = d->input_buffer; + } + memcpy((void*)(bzs->next_in + d->bzs_avail_in_real), data, len); + d->bzs_avail_in_real += len; + input_buffer_in_use = 1; + } + else { + bzs->next_in = data; + d->bzs_avail_in_real = len; + input_buffer_in_use = 0; + } + + result = decompress_buf(d, max_length); + if(result == NULL) + return NULL; + + if (d->eof) { + d->needs_input = 0; + if (d->bzs_avail_in_real > 0) { + Py_CLEAR(d->unused_data); + d->unused_data = PyBytes_FromStringAndSize( + bzs->next_in, d->bzs_avail_in_real); + if (d->unused_data == NULL) + goto error; + } + } + else if (d->bzs_avail_in_real == 0) { + bzs->next_in = NULL; + d->needs_input = 1; + } + else { + d->needs_input = 0; + + /* If we did not use the input buffer, we now have + to copy the tail from the caller's buffer into the + input buffer */ + if (!input_buffer_in_use) { + + /* Discard buffer if it's too small + (resizing it may needlessly copy the current contents) */ + if (d->input_buffer != NULL && + d->input_buffer_size < d->bzs_avail_in_real) { + PyMem_Free(d->input_buffer); + d->input_buffer = NULL; + } + + /* Allocate if necessary */ + if (d->input_buffer == NULL) { + d->input_buffer = PyMem_Malloc(d->bzs_avail_in_real); + if (d->input_buffer == NULL) { + PyErr_SetNone(PyExc_MemoryError); + goto error; + } + d->input_buffer_size = d->bzs_avail_in_real; + } + + /* Copy tail */ + memcpy(d->input_buffer, bzs->next_in, d->bzs_avail_in_real); + bzs->next_in = d->input_buffer; + } + } + return result; error: @@ -470,21 +594,29 @@ /*[clinic input] _bz2.BZ2Decompressor.decompress + self: self(type="BZ2Decompressor *") data: Py_buffer - / + max_length: Py_ssize_t=-1 -Provide data to the decompressor object. +Decompress *data*, returning uncompressed data as bytes. -Returns a chunk of decompressed data if possible, or b'' otherwise. +If *max_length* is nonnegative, returns at most *max_length* bytes of +decompressed data. If this limit is reached and further output can be +produced, *self.needs_input* will be set to ``False``. In this case, the next +call to *decompress()* may provide *data* as b'' to obtain more of the output. -Attempting to decompress data after the end of stream is reached -raises an EOFError. Any data found after the end of the stream -is ignored and saved in the unused_data attribute. +If all of the input data was decompressed and returned (either because this +was less than *max_length* bytes, or because *max_length* was negative), +*self.needs_input* will be set to True. + +Attempting to decompress data after the end of stream is reached raises an +EOFError. Any data found after the end of the stream is ignored and saved in +the unused_data attribute. [clinic start generated code]*/ static PyObject * -_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data) -/*[clinic end generated code: output=086e4b99e60cb3f6 input=616c2a6db5269961]*/ +_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, Py_ssize_t max_length) +/*[clinic end generated code: output=7eeb5794035a2ca3 input=9558b424c8b00516]*/ { PyObject *result = NULL; @@ -492,7 +624,7 @@ if (self->eof) PyErr_SetString(PyExc_EOFError, "End of stream already reached"); else - result = decompress(self, data->buf, data->len); + result = decompress(self, data->buf, data->len, max_length); RELEASE_LOCK(self); return result; } @@ -527,10 +659,14 @@ } #endif - self->unused_data = PyBytes_FromStringAndSize("", 0); + self->needs_input = 1; + self->bzs_avail_in_real = 0; + self->input_buffer = NULL; + self->input_buffer_size = 0; + self->unused_data = PyBytes_FromStringAndSize(NULL, 0); if (self->unused_data == NULL) goto error; - + bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0); if (catch_bz2_error(bzerror)) goto error; @@ -549,6 +685,8 @@ static void BZ2Decompressor_dealloc(BZ2Decompressor *self) { + if(self->input_buffer != NULL) + PyMem_Free(self->input_buffer); BZ2_bzDecompressEnd(&self->bzs); Py_CLEAR(self->unused_data); #ifdef WITH_THREAD @@ -570,11 +708,16 @@ PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__, "Data found after the end of the compressed stream."); +PyDoc_STRVAR(BZ2Decompressor_needs_input_doc, +"True if more input is needed before more decompressed data can be produced."); + static PyMemberDef BZ2Decompressor_members[] = { {"eof", T_BOOL, offsetof(BZ2Decompressor, eof), READONLY, BZ2Decompressor_eof__doc__}, {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data), READONLY, BZ2Decompressor_unused_data__doc__}, + {"needs_input", T_BOOL, offsetof(BZ2Decompressor, needs_input), READONLY, + BZ2Decompressor_needs_input_doc}, {NULL} }; diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -95,34 +95,43 @@ } PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, -"decompress($self, data, /)\n" +"decompress($self, /, data, max_length=-1)\n" "--\n" "\n" -"Provide data to the decompressor object.\n" +"Decompress *data*, returning uncompressed data as bytes.\n" "\n" -"Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" +"If *max_length* is nonnegative, returns at most *max_length* bytes of\n" +"decompressed data. If this limit is reached and further output can be\n" +"produced, *self.needs_input* will be set to ``False``. In this case, the next\n" +"call to *decompress()* may provide *data* as b\'\' to obtain more of the output.\n" "\n" -"Attempting to decompress data after the end of stream is reached\n" -"raises an EOFError. Any data found after the end of the stream\n" -"is ignored and saved in the unused_data attribute."); +"If all of the input data was decompressed and returned (either because this\n" +"was less than *max_length* bytes, or because *max_length* was negative),\n" +"*self.needs_input* will be set to True.\n" +"\n" +"Attempting to decompress data after the end of stream is reached raises an\n" +"EOFError. Any data found after the end of the stream is ignored and saved in\n" +"the unused_data attribute."); #define _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF \ - {"decompress", (PyCFunction)_bz2_BZ2Decompressor_decompress, METH_VARARGS, _bz2_BZ2Decompressor_decompress__doc__}, + {"decompress", (PyCFunction)_bz2_BZ2Decompressor_decompress, METH_VARARGS|METH_KEYWORDS, _bz2_BZ2Decompressor_decompress__doc__}, static PyObject * -_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data); +_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, Py_ssize_t max_length); static PyObject * -_bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args) +_bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; + static char *_keywords[] = {"data", "max_length", NULL}; Py_buffer data = {NULL, NULL}; + Py_ssize_t max_length = -1; - if (!PyArg_ParseTuple(args, - "y*:decompress", - &data)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "y*|n:decompress", _keywords, + &data, &max_length)) goto exit; - return_value = _bz2_BZ2Decompressor_decompress_impl(self, &data); + return_value = _bz2_BZ2Decompressor_decompress_impl(self, &data, max_length); exit: /* Cleanup for data */ @@ -159,4 +168,4 @@ exit: return return_value; } -/*[clinic end generated code: output=21ca4405519a0931 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8e65e3953430bc3d input=a9049054013a1b77]*/ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:28:25 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 26 Feb 2015 13:28:25 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Silenced_minor_GCC_warning?= =?utf-8?q?s=2E?= Message-ID: <20150226132823.4024.85803@psf.io> https://hg.python.org/cpython/rev/7c6e3358221a changeset: 94756:7c6e3358221a user: Serhiy Storchaka date: Thu Feb 26 15:27:57 2015 +0200 summary: Silenced minor GCC warnings. files: Modules/_ctypes/_ctypes.c | 5 +++-- Modules/_testcapimodule.c | 7 +++++++ Modules/socketmodule.c | 7 +++++++ Programs/_freeze_importlib.c | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2819,8 +2819,9 @@ src->b_ptr, size); - if (PyCPointerTypeObject_Check(type)) - /* XXX */; + if (PyCPointerTypeObject_Check(type)) { + /* XXX */ + } value = GetKeepedObjects(src); if (value == NULL) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -69,6 +69,10 @@ static PyObject* test_sizeof_c_types(PyObject *self) { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif #define CHECK_SIZEOF(TYPE, EXPECTED) \ if (EXPECTED != sizeof(TYPE)) { \ PyErr_Format(TestError, \ @@ -126,6 +130,9 @@ #undef IS_SIGNED #undef CHECK_SIGNESS #undef CHECK_SIZEOF +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif } diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1966,8 +1966,15 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-compare" #endif + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wtype-limits" + #endif if (msg->msg_controllen < 0) return 0; + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif #ifdef __clang__ #pragma clang diagnostic pop #endif diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c --- a/Programs/_freeze_importlib.c +++ b/Programs/_freeze_importlib.c @@ -17,7 +17,7 @@ of frozen modules instead, left deliberately blank so as to avoid unintentional import of a stale version of _frozen_importlib. */ -const static struct _frozen _PyImport_FrozenModules[] = { +static const struct _frozen _PyImport_FrozenModules[] = { {0, 0, 0} /* sentinel */ }; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:59:40 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 13:59:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Checking_in_th?= =?utf-8?q?is_change__LOCAL_ONLY__NO_UPLOAD_ANYWHERE?= Message-ID: <20150226135923.29668.46836@psf.io> https://hg.python.org/cpython/rev/b4cbecbc0781 changeset: 94760:b4cbecbc0781 branch: 3.4 tag: v3.4.3 user: Larry Hastings date: Wed Feb 25 04:15:33 2015 -0800 summary: Checking in this change LOCAL ONLY NO UPLOAD ANYWHERE files: Doc/library/codecs.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -393,7 +393,7 @@ Implements the ``'replace'`` error handling (for :term:`text encodings ` only): substitutes ``'?'`` for encoding errors (to be encoded by the codec), and ``'\ufffd'`` (the Unicode replacement - character, ``'?'``) for decoding errors. + character) for decoding errors. .. function:: ignore_errors(exception) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:59:40 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 13:59:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Added_tag_v3?= =?utf-8?q?=2E4=2E3_for_changeset_9b73f1c3e601?= Message-ID: <20150226135923.10168.51117@psf.io> https://hg.python.org/cpython/rev/933c3041d548 changeset: 94759:933c3041d548 branch: 3.4 user: Larry Hastings date: Sun Feb 22 23:55:48 2015 -0800 summary: Added tag v3.4.3 for changeset 9b73f1c3e601 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -143,3 +143,4 @@ 8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 +9b73f1c3e6012e556da7e2d40dd7a382d3726334 v3.4.3 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:59:40 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 13:59:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Release_bump_f?= =?utf-8?b?b3IgMy40LjMgZmluYWwu?= Message-ID: <20150226135923.10186.18306@psf.io> https://hg.python.org/cpython/rev/9b73f1c3e601 changeset: 94758:9b73f1c3e601 branch: 3.4 user: Larry Hastings date: Sun Feb 22 23:55:39 2015 -0800 summary: Release bump for 3.4.3 final. files: Include/patchlevel.h | 6 +++--- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 14 +------------- Misc/RPM/python-3.4.spec | 2 +- README | 4 ++-- 6 files changed, 9 insertions(+), 21 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -19,11 +19,11 @@ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 4 #define PY_MICRO_VERSION 3 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.4.3rc1+" +#define PY_VERSION "3.4.3" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.4.3rc1" +__version__ = "3.4.3" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.4.3rc1" +IDLE_VERSION = "3.4.3" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,19 +5,7 @@ What's New in Python 3.4.3? =========================== -Release date: 2015-02-22 - -Core and Builtins ------------------ - -Library -------- - - -What's New in Python 3.4.3rc1? -============================== - -Release date: 2015-02-08 +Release date: 2015-02-23 Core and Builtins ----------------- diff --git a/Misc/RPM/python-3.4.spec b/Misc/RPM/python-3.4.spec --- a/Misc/RPM/python-3.4.spec +++ b/Misc/RPM/python-3.4.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.4.3rc1 +%define version 3.4.3 %define libvers 3.4 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Python version 3.4.3rc1 -=============================== +This is Python version 3.4.3 +============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Python Software Foundation. All rights reserved. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:59:40 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 13:59:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Post-release_c?= =?utf-8?q?hanges_for_3=2E4=2E3=2E?= Message-ID: <20150226135923.14043.20281@psf.io> https://hg.python.org/cpython/rev/961c1f520e41 changeset: 94762:961c1f520e41 branch: 3.4 user: Larry Hastings date: Thu Feb 26 05:56:32 2015 -0800 summary: Post-release changes for 3.4.3. files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.4.3" +#define PY_VERSION "3.4.3+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.4.4rc1? +============================== + +Release date: tba + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.4.3? =========================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:59:41 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 13:59:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Added_tag_v3?= =?utf-8?q?=2E4=2E3_for_changeset_b4cbecbc0781?= Message-ID: <20150226135923.77536.94728@psf.io> https://hg.python.org/cpython/rev/5862b8be6714 changeset: 94761:5862b8be6714 branch: 3.4 user: Larry Hastings date: Wed Feb 25 04:17:04 2015 -0800 summary: Added tag v3.4.3 for changeset b4cbecbc0781 files: .hgtags | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -144,3 +144,5 @@ ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 9b73f1c3e6012e556da7e2d40dd7a382d3726334 v3.4.3 +9b73f1c3e6012e556da7e2d40dd7a382d3726334 v3.4.3 +b4cbecbc0781e89a309d03b60a1f75f8499250e6 v3.4.3 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:59:41 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 13:59:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Doc_updates_fo?= =?utf-8?q?r_3=2E4=2E3_final=2E?= Message-ID: <20150226135922.39363.79310@psf.io> https://hg.python.org/cpython/rev/660ff8a51cf2 changeset: 94757:660ff8a51cf2 branch: 3.4 parent: 94570:84a05605caeb user: Larry Hastings date: Sun Feb 22 23:54:38 2015 -0800 summary: Doc updates for 3.4.3 final. files: Lib/pydoc_data/topics.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sat Feb 7 15:53:49 2015 +# Autogenerated by Sphinx on Sun Feb 22 23:52:05 2015 topics = {'assert': u'\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': u'\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for\n*attributeref*, *subscription*, and *slicing*.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the target\n sequence allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nAlthough the definition of assignment implies that overlaps between\nthe left-hand side and the right-hand side are \'simultanenous\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables occur left-to-right, sometimes\nresulting in confusion. For instance, the following program prints\n"[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2 # i is updated, then x[i] is updated\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions of the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nUnlike normal assignments, augmented assignments evaluate the left-\nhand side *before* evaluating the right-hand side. For example, "a[i]\n+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs\nthe addition, and lastly, it writes the result back to "a[i]".\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': u'\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n', -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 14:59:41 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 13:59:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNCk6?= =?utf-8?q?_Merge_3=2E4=2E3_release_engineering_changes_back_into_3=2E4=2E?= Message-ID: <20150226135924.87115.82635@psf.io> https://hg.python.org/cpython/rev/4ce53fdb6438 changeset: 94763:4ce53fdb6438 branch: 3.4 parent: 94762:961c1f520e41 parent: 94753:366e3ad5e3bd user: Larry Hastings date: Thu Feb 26 05:58:48 2015 -0800 summary: Merge 3.4.3 release engineering changes back into 3.4. files: Doc/extending/newtypes.rst | 2 +- Doc/includes/email-headers.py | 5 +- Doc/includes/email-mime.py | 5 +- Doc/includes/email-read-alternative-new-api.py | 3 +- Doc/includes/email-simple.py | 7 +- Doc/library/asyncio-dev.rst | 2 + Doc/library/asyncio-eventloop.rst | 37 +- Doc/library/asyncio-protocol.rst | 2 + Doc/library/asyncio-sync.rst | 395 +------- Doc/library/asyncio-stream.rst | 20 +- Doc/library/asyncio-subprocess.rst | 17 +- Doc/library/asyncio-sync.rst | 192 +--- Doc/library/asyncio-task.rst | 12 +- Doc/library/asyncio.rst | 6 + Doc/library/binascii.rst | 6 - Doc/library/copyreg.rst | 2 +- Doc/library/http.client.rst | 6 + Doc/library/http.server.rst | 12 + Doc/library/mimetypes.rst | 4 +- Doc/library/os.rst | 3 +- Doc/library/re.rst | 7 +- Doc/reference/expressions.rst | 2 +- Doc/tools/extensions/pyspecific.py | 21 + Include/unicodeobject.h | 2 +- Lib/asyncio/base_subprocess.py | 9 +- Lib/asyncio/queues.py | 104 +- Lib/dbm/dumb.py | 3 +- Lib/http/client.py | 4 +- Lib/http/server.py | 25 +- Lib/pathlib.py | 4 + Lib/pydoc.py | 26 +- Lib/sre_parse.py | 20 + Lib/ssl.py | 6 +- Lib/tarfile.py | 16 +- Lib/test/_test_multiprocessing.py | 20 +- Lib/test/pickletester.py | 433 +++++---- Lib/test/test__locale.py | 97 +- Lib/test/test_asyncio/test_queues.py | 10 +- Lib/test/test_asyncio/test_subprocess.py | 64 + Lib/test/test_asyncio/test_unix_events.py | 6 +- Lib/test/test_bz2.py | 10 +- Lib/test/test_cgi.py | 4 +- Lib/test/test_dbm_dumb.py | 9 + Lib/test/test_functools.py | 16 +- Lib/test/test_gdb.py | 2 + Lib/test/test_httplib.py | 15 + Lib/test/test_httpservers.py | 53 + Lib/test/test_io.py | 53 +- Lib/test/test_locale.py | 2 +- Lib/test/test_multibytecodec.py | 7 + Lib/test/test_pathlib.py | 36 +- Lib/test/test_pydoc.py | 41 + Lib/test/test_re.py | 33 +- Lib/test/test_statistics.py | 1 - Lib/test/test_subprocess.py | 4 +- Lib/test/test_tarfile.py | 15 + Lib/test/test_zipfile.py | 10 + Lib/turtle.py | 69 +- Lib/turtledemo/__main__.py | 4 + Misc/ACKS | 1 + Misc/NEWS | 38 + Misc/README | 1 - Misc/RPM/README | 33 - Misc/RPM/python-3.4.spec | 389 -------- Modules/_ctypes/_ctypes.c | 9 +- Modules/_ctypes/stgdict.c | 12 +- Modules/_io/fileio.c | 21 +- Modules/_localemodule.c | 2 +- Modules/_ssl.c | 7 +- Modules/_testbuffer.c | 2 +- Modules/_testcapimodule.c | 2 +- Modules/_tkinter.c | 2 +- Modules/_winapi.c | 14 +- Modules/binascii.c | 4 +- Modules/cjkcodecs/multibytecodec.c | 19 +- Modules/faulthandler.c | 9 +- Modules/getpath.c | 2 +- Modules/posixmodule.c | 20 +- Modules/pyexpat.c | 4 +- Modules/socketmodule.c | 6 +- Modules/unicodedata.c | 4 +- Modules/zipimport.c | 2 +- Objects/listobject.c | 3 +- Objects/unicodeobject.c | 31 +- PC/winreg.c | 6 +- Python/frozenmain.c | 15 +- Python/peephole.c | 4 +- configure | 6 +- configure.ac | 6 +- 89 files changed, 1171 insertions(+), 1504 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -1205,7 +1205,7 @@ { if (strcmp(name, "data") == 0) { - return PyInt_FromLong(obj->data); + return PyLong_FromLong(obj->data); } PyErr_Format(PyExc_AttributeError, diff --git a/Doc/includes/email-headers.py b/Doc/includes/email-headers.py --- a/Doc/includes/email-headers.py +++ b/Doc/includes/email-headers.py @@ -1,8 +1,9 @@ # Import the email modules we'll need from email.parser import Parser -# If the e-mail headers are in a file, uncomment this line: -#headers = Parser().parse(open(messagefile, 'r')) +# If the e-mail headers are in a file, uncomment these two lines: +# with open(messagefile) as fp: +# headers = Parser().parse(fp) # Or for parsing headers in a string, use: headers = Parser().parsestr('From: \n' diff --git a/Doc/includes/email-mime.py b/Doc/includes/email-mime.py --- a/Doc/includes/email-mime.py +++ b/Doc/includes/email-mime.py @@ -20,9 +20,8 @@ for file in pngfiles: # Open the files in binary mode. Let the MIMEImage class automatically # guess the specific image type. - fp = open(file, 'rb') - img = MIMEImage(fp.read()) - fp.close() + with open(file, 'rb') as fp: + img = MIMEImage(fp.read()) msg.attach(img) # Send the email via our own SMTP server. diff --git a/Doc/includes/email-read-alternative-new-api.py b/Doc/includes/email-read-alternative-new-api.py --- a/Doc/includes/email-read-alternative-new-api.py +++ b/Doc/includes/email-read-alternative-new-api.py @@ -12,7 +12,8 @@ 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')) +with open('outgoing.msg', 'rb') as fp: + msg = BytesParser(policy=policy.default).parse(fp) # Now the header items can be accessed as a dictionary, and any non-ASCII will # be converted to unicode: diff --git a/Doc/includes/email-simple.py b/Doc/includes/email-simple.py --- a/Doc/includes/email-simple.py +++ b/Doc/includes/email-simple.py @@ -6,10 +6,9 @@ # Open a plain text file for reading. For this example, assume that # the text file contains only ASCII characters. -fp = open(textfile, 'rb') -# Create a text/plain message -msg = MIMEText(fp.read()) -fp.close() +with open(textfile) as fp: + # Create a text/plain message + msg = MIMEText(fp.read()) # me == the sender's email address # you == the recipient's email address diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -212,6 +212,7 @@ loop = asyncio.get_event_loop() asyncio.async(bug()) loop.run_forever() + loop.close() Output:: @@ -258,6 +259,7 @@ loop = asyncio.get_event_loop() asyncio.async(handle_exception()) loop.run_forever() + loop.close() Another option is to use the :meth:`BaseEventLoop.run_until_complete` function:: diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -22,6 +22,8 @@ Base class of event loops. + This class is :ref:`not thread safe `. + Run an event loop ----------------- @@ -104,6 +106,9 @@ Like :meth:`call_soon`, but thread safe. + See the :ref:`concurrency and multithreading ` + section of the documentation. + .. _asyncio-delayed-calls: @@ -180,7 +185,7 @@ Creating connections -------------------- -.. method:: BaseEventLoop.create_connection(protocol_factory, host=None, port=None, \*, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None) +.. coroutinemethod:: BaseEventLoop.create_connection(protocol_factory, host=None, port=None, \*, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None) Create a streaming transport connection to a given Internet *host* and *port*: socket family :py:data:`~socket.AF_INET` or @@ -253,7 +258,7 @@ (:class:`StreamReader`, :class:`StreamWriter`) instead of a protocol. -.. method:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) +.. coroutinemethod:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) Create datagram connection: socket family :py:data:`~socket.AF_INET` or :py:data:`~socket.AF_INET6` depending on *host* (or *family* if specified), @@ -271,7 +276,7 @@ :ref:`UDP echo server protocol ` examples. -.. method:: BaseEventLoop.create_unix_connection(protocol_factory, path, \*, ssl=None, sock=None, server_hostname=None) +.. coroutinemethod:: BaseEventLoop.create_unix_connection(protocol_factory, path, \*, ssl=None, sock=None, server_hostname=None) Create UNIX connection: socket family :py:data:`~socket.AF_UNIX`, socket type :py:data:`~socket.SOCK_STREAM`. The :py:data:`~socket.AF_UNIX` socket @@ -290,7 +295,7 @@ Creating listening connections ------------------------------ -.. method:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None) +.. coroutinemethod:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None) Create a TCP server (socket type :data:`~socket.SOCK_STREAM`) bound to *host* and *port*. @@ -336,11 +341,13 @@ :class:`StreamWriter`) pair and calls back a function with this pair. -.. method:: BaseEventLoop.create_unix_server(protocol_factory, path=None, \*, sock=None, backlog=100, ssl=None) +.. coroutinemethod:: BaseEventLoop.create_unix_server(protocol_factory, path=None, \*, sock=None, backlog=100, ssl=None) Similar to :meth:`BaseEventLoop.create_server`, but specific to the socket family :py:data:`~socket.AF_UNIX`. + This method is a :ref:`coroutine `. + Availability: UNIX. @@ -384,7 +391,7 @@ Low-level socket operations --------------------------- -.. method:: BaseEventLoop.sock_recv(sock, nbytes) +.. coroutinemethod:: BaseEventLoop.sock_recv(sock, nbytes) Receive data from the socket. The return value is a bytes object representing the data received. The maximum amount of data to be received @@ -399,7 +406,7 @@ The :meth:`socket.socket.recv` method. -.. method:: BaseEventLoop.sock_sendall(sock, data) +.. coroutinemethod:: BaseEventLoop.sock_sendall(sock, data) Send data to the socket. The socket must be connected to a remote socket. This method continues to send data from *data* until either all data has @@ -416,7 +423,7 @@ The :meth:`socket.socket.sendall` method. -.. method:: BaseEventLoop.sock_connect(sock, address) +.. coroutinemethod:: BaseEventLoop.sock_connect(sock, address) Connect to a remote socket at *address*. @@ -438,7 +445,7 @@ method. -.. method:: BaseEventLoop.sock_accept(sock) +.. coroutinemethod:: BaseEventLoop.sock_accept(sock) Accept a connection. The socket must be bound to an address and listening for connections. The return value is a pair ``(conn, address)`` where *conn* @@ -459,12 +466,12 @@ Resolve host name ----------------- -.. method:: BaseEventLoop.getaddrinfo(host, port, \*, family=0, type=0, proto=0, flags=0) +.. coroutinemethod:: BaseEventLoop.getaddrinfo(host, port, \*, family=0, type=0, proto=0, flags=0) This method is a :ref:`coroutine `, similar to :meth:`socket.getaddrinfo` function but non-blocking. -.. method:: BaseEventLoop.getnameinfo(sockaddr, flags=0) +.. coroutinemethod:: BaseEventLoop.getnameinfo(sockaddr, flags=0) This method is a :ref:`coroutine `, similar to :meth:`socket.getnameinfo` function but non-blocking. @@ -476,7 +483,7 @@ On Windows with :class:`SelectorEventLoop`, these methods are not supported. Use :class:`ProactorEventLoop` to support pipes on Windows. -.. method:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) +.. coroutinemethod:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) Register read pipe in eventloop. @@ -490,7 +497,7 @@ This method is a :ref:`coroutine `. -.. method:: BaseEventLoop.connect_write_pipe(protocol_factory, pipe) +.. coroutinemethod:: BaseEventLoop.connect_write_pipe(protocol_factory, pipe) Register write pipe in eventloop. @@ -543,7 +550,7 @@ pool of processes). By default, an event loop uses a thread pool executor (:class:`~concurrent.futures.ThreadPoolExecutor`). -.. method:: BaseEventLoop.run_in_executor(executor, callback, \*args) +.. coroutinemethod:: BaseEventLoop.run_in_executor(executor, callback, \*args) Arrange for a callback to be called in the specified executor. @@ -654,7 +661,7 @@ The server is closed asynchonously, use the :meth:`wait_closed` coroutine to wait until the server is closed. - .. method:: wait_closed() + .. coroutinemethod:: wait_closed() Wait until the :meth:`close` method completes. diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -23,6 +23,8 @@ subprocess pipes. The methods available on a transport depend on the transport's kind. +The transport classes are :ref:`not thread safe `. + BaseTransport ------------- diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-queue.rst copy from Doc/library/asyncio-sync.rst copy to Doc/library/asyncio-queue.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-queue.rst @@ -1,16 +1,7 @@ .. currentmodule:: asyncio -.. _asyncio-sync: -Synchronization primitives -========================== - -Locks: - -* :class:`Lock` -* :class:`Event` -* :class:`Condition` -* :class:`Semaphore` -* :class:`BoundedSemaphore` +Queues +====== Queues: @@ -19,284 +10,14 @@ * :class:`LifoQueue` * :class:`JoinableQueue` -asyncio locks and queues API were designed to be close to classes of the -:mod:`threading` module (:class:`~threading.Lock`, :class:`~threading.Event`, -:class:`~threading.Condition`, :class:`~threading.Semaphore`, -:class:`~threading.BoundedSemaphore`) and the :mod:`queue` module -(:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, -:class:`~queue.LifoQueue`), but they have no *timeout* parameter. The +asyncio queue API was designed to be close to classes of the :mod:`queue` +module (:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, +:class:`~queue.LifoQueue`), but it has no *timeout* parameter. The :func:`asyncio.wait_for` function can be used to cancel a task after a timeout. -Locks +Queue ----- -Lock -^^^^ - -.. class:: Lock(\*, loop=None) - - Primitive lock objects. - - A primitive lock is a synchronization primitive that is not owned by a - particular coroutine when locked. A primitive lock is in one of two states, - 'locked' or 'unlocked'. - - It is created in the unlocked state. It has two basic methods, :meth:`acquire` - and :meth:`release`. When the state is unlocked, acquire() changes the state to - locked and returns immediately. When the state is locked, acquire() blocks - until a call to release() in another coroutine changes it to unlocked, then - the acquire() call resets it to locked and returns. The release() method - should only be called in the locked state; it changes the state to unlocked - and returns immediately. If an attempt is made to release an unlocked lock, - a :exc:`RuntimeError` will be raised. - - When more than one coroutine is blocked in acquire() waiting for the state - to turn to unlocked, only one coroutine proceeds when a release() call - resets the state to unlocked; first coroutine which is blocked in acquire() - is being processed. - - :meth:`acquire` is a coroutine and should be called with ``yield from``. - - Locks also support the context management protocol. ``(yield from lock)`` - should be used as context manager expression. - - Usage:: - - lock = Lock() - ... - yield from lock - try: - ... - finally: - lock.release() - - Context manager usage:: - - lock = Lock() - ... - with (yield from lock): - ... - - Lock objects can be tested for locking state:: - - if not lock.locked(): - yield from lock - else: - # lock is acquired - ... - - .. method:: locked() - - Return ``True`` if the lock is acquired. - - .. method:: acquire() - - Acquire a lock. - - This method blocks until the lock is unlocked, then sets it to locked and - returns ``True``. - - This method is a :ref:`coroutine `. - - .. method:: release() - - Release a lock. - - When the lock is locked, reset it to unlocked, and return. If any other - coroutines are blocked waiting for the lock to become unlocked, allow - exactly one of them to proceed. - - When invoked on an unlocked lock, a :exc:`RuntimeError` is raised. - - There is no return value. - - -Event -^^^^^ - -.. class:: Event(\*, loop=None) - - An Event implementation, asynchronous equivalent to :class:`threading.Event`. - - Class implementing event objects. An event manages a flag that can be set to - true with the :meth:`set` method and reset to false with the :meth:`clear` - method. The :meth:`wait` method blocks until the flag is true. The flag is - initially false. - - .. method:: clear() - - Reset the internal flag to false. Subsequently, coroutines calling - :meth:`wait` will block until :meth:`set` is called to set the internal - flag to true again. - - .. method:: is_set() - - Return ``True`` if and only if the internal flag is true. - - .. method:: set() - - Set the internal flag to true. All coroutines waiting for it to become - true are awakened. Coroutine that call :meth:`wait` once the flag is true - will not block at all. - - .. method:: wait() - - Block until the internal flag is true. - - If the internal flag is true on entry, return ``True`` immediately. - Otherwise, block until another coroutine calls :meth:`set` to set the - flag to true, then return ``True``. - - This method is a :ref:`coroutine `. - - -Condition -^^^^^^^^^ - -.. class:: Condition(lock=None, \*, loop=None) - - A Condition implementation, asynchronous equivalent to - :class:`threading.Condition`. - - This class implements condition variable objects. A condition variable - allows one or more coroutines to wait until they are notified by another - coroutine. - - If the *lock* argument is given and not ``None``, it must be a :class:`Lock` - object, and it is used as the underlying lock. Otherwise, - a new :class:`Lock` object is created and used as the underlying lock. - - .. method:: acquire() - - Acquire the underlying lock. - - This method blocks until the lock is unlocked, then sets it to locked and - returns ``True``. - - This method is a :ref:`coroutine `. - - .. method:: notify(n=1) - - By default, wake up one coroutine waiting on this condition, if any. - If the calling coroutine has not acquired the lock when this method is - called, a :exc:`RuntimeError` is raised. - - This method wakes up at most *n* of the coroutines waiting for the - condition variable; it is a no-op if no coroutines are waiting. - - .. note:: - - An awakened coroutine does not actually return from its :meth:`wait` - call until it can reacquire the lock. Since :meth:`notify` does not - release the lock, its caller should. - - .. method:: locked() - - Return ``True`` if the underlying lock is acquired. - - .. method:: notify_all() - - Wake up all threads waiting on this condition. This method acts like - :meth:`notify`, but wakes up all waiting threads instead of one. If the - calling thread has not acquired the lock when this method is called, a - :exc:`RuntimeError` is raised. - - .. method:: release() - - Release the underlying lock. - - When the lock is locked, reset it to unlocked, and return. If any other - coroutines are blocked waiting for the lock to become unlocked, allow - exactly one of them to proceed. - - When invoked on an unlocked lock, a :exc:`RuntimeError` is raised. - - There is no return value. - - .. method:: wait() - - Wait until notified. - - If the calling coroutine has not acquired the lock when this method is - called, a :exc:`RuntimeError` is raised. - - This method releases the underlying lock, and then blocks until it is - awakened by a :meth:`notify` or :meth:`notify_all` call for the same - condition variable in another coroutine. Once awakened, it re-acquires - the lock and returns ``True``. - - This method is a :ref:`coroutine `. - - .. method:: wait_for(predicate) - - Wait until a predicate becomes true. - - The predicate should be a callable which result will be interpreted as a - boolean value. The final predicate value is the return value. - - This method is a :ref:`coroutine `. - - -Semaphores ----------- - -Semaphore -^^^^^^^^^ - -.. class:: Semaphore(value=1, \*, loop=None) - - A Semaphore implementation. - - A semaphore manages an internal counter which is decremented by each - :meth:`acquire` call and incremented by each :meth:`release` call. The - counter can never go below zero; when :meth:`acquire` finds that it is zero, - it blocks, waiting until some other thread calls :meth:`release`. - - Semaphores also support the context management protocol. - - The optional argument gives the initial value for the internal counter; it - defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` - is raised. - - .. method:: acquire() - - Acquire a semaphore. - - If the internal counter is larger than zero on entry, decrement it by one - and return ``True`` immediately. If it is zero on entry, block, waiting - until some other coroutine has called :meth:`release` to make it larger - than ``0``, and then return ``True``. - - This method is a :ref:`coroutine `. - - .. method:: locked() - - Returns ``True`` if semaphore can not be acquired immediately. - - .. method:: release() - - Release a semaphore, incrementing the internal counter by one. When it - was zero on entry and another coroutine is waiting for it to become - larger than zero again, wake up that coroutine. - - -BoundedSemaphore -^^^^^^^^^^^^^^^^ - -.. class:: BoundedSemaphore(value=1, \*, loop=None) - - A bounded semaphore implementation. Inherit from :class:`Semaphore`. - - This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would - increase the value above the initial value. - - -Queues ------- - -Queue -^^^^^ - .. class:: Queue(maxsize=0, \*, loop=None) A queue, useful for coordinating producer and consumer coroutines. @@ -310,6 +31,11 @@ be interrupted between calling :meth:`qsize` and doing an operation on the Queue. + This class is :ref:`not thread safe `. + + .. versionchanged:: 3.4.3 + New :meth:`join` and :meth:`task_done` methods. + .. method:: empty() Return ``True`` if the queue is empty, ``False`` otherwise. @@ -323,7 +49,7 @@ If the Queue was initialized with ``maxsize=0`` (the default), then :meth:`full()` is never ``True``. - .. method:: get() + .. coroutinemethod:: get() Remove and return an item from the queue. If queue is empty, wait until an item is available. @@ -341,7 +67,21 @@ Return an item if one is immediately available, else raise :exc:`QueueEmpty`. - .. method:: put(item) + .. coroutinemethod:: join() + + Block until all items in the queue have been gotten and processed. + + The count of unfinished tasks goes up whenever an item is added to the + queue. The count goes down whenever a consumer thread calls + :meth:`task_done` to indicate that the item was retrieved and all work on + it is complete. When the count of unfinished tasks drops to zero, + :meth:`join` unblocks. + + This method is a :ref:`coroutine `. + + .. versionadded:: 3.4.3 + + .. coroutinemethod:: put(item) Put an item into the queue. If the queue is full, wait until a free slot is available before adding item. @@ -362,51 +102,6 @@ Number of items in the queue. - .. attribute:: maxsize - - Number of items allowed in the queue. - - -PriorityQueue -^^^^^^^^^^^^^ - -.. class:: PriorityQueue - - A subclass of :class:`Queue`; retrieves entries in priority order (lowest - first). - - Entries are typically tuples of the form: (priority number, data). - - -LifoQueue -^^^^^^^^^ - -.. class:: LifoQueue - - A subclass of :class:`Queue` that retrieves most recently added entries - first. - - -JoinableQueue -^^^^^^^^^^^^^ - -.. class:: JoinableQueue - - A subclass of :class:`Queue` with :meth:`task_done` and :meth:`join` - methods. - - .. method:: join() - - Block until all items in the queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls - :meth:`task_done` to indicate that the item was retrieved and all work on - it is complete. When the count of unfinished tasks drops to zero, - :meth:`join` unblocks. - - This method is a :ref:`coroutine `. - .. method:: task_done() Indicate that a formerly enqueued task is complete. @@ -422,6 +117,42 @@ Raises :exc:`ValueError` if called more times than there were items placed in the queue. + .. versionadded:: 3.4.3 + + .. attribute:: maxsize + + Number of items allowed in the queue. + + +PriorityQueue +------------- + +.. class:: PriorityQueue + + A subclass of :class:`Queue`; retrieves entries in priority order (lowest + first). + + Entries are typically tuples of the form: (priority number, data). + + +LifoQueue +--------- + +.. class:: LifoQueue + + A subclass of :class:`Queue` that retrieves most recently added entries + first. + + +JoinableQueue +^^^^^^^^^^^^^ + +.. class:: JoinableQueue + + Deprecated alias for :class:`Queue`. + + .. deprecated:: 3.4.3 + Exceptions ^^^^^^^^^^ diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -9,7 +9,7 @@ Stream functions ================ -.. function:: open_connection(host=None, port=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: open_connection(host=None, port=None, \*, loop=None, limit=None, \*\*kwds) A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, writer) pair. @@ -32,7 +32,7 @@ This function is a :ref:`coroutine `. -.. function:: start_server(client_connected_cb, host=None, port=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: start_server(client_connected_cb, host=None, port=None, \*, loop=None, limit=None, \*\*kwds) Start a socket server, with a callback for each client connected. The return value is the same as :meth:`~BaseEventLoop.create_server()`. @@ -56,7 +56,7 @@ This function is a :ref:`coroutine `. -.. function:: open_unix_connection(path=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: open_unix_connection(path=None, \*, loop=None, limit=None, **kwds) A wrapper for :meth:`~BaseEventLoop.create_unix_connection()` returning a (reader, writer) pair. @@ -68,7 +68,7 @@ Availability: UNIX. -.. function:: start_unix_server(client_connected_cb, path=None, \*, loop=None, limit=None, **kwds) +.. coroutinefunction:: start_unix_server(client_connected_cb, path=None, \*, loop=None, limit=None, **kwds) Start a UNIX Domain Socket server, with a callback for each client connected. @@ -85,6 +85,8 @@ .. class:: StreamReader(limit=None, loop=None) + This class is :ref:`not thread safe `. + .. method:: exception() Get the exception. @@ -106,7 +108,7 @@ Set the transport. - .. method:: read(n=-1) + .. coroutinemethod:: read(n=-1) Read up to *n* bytes. If *n* is not provided, or set to ``-1``, read until EOF and return all read bytes. @@ -116,7 +118,7 @@ This method is a :ref:`coroutine `. - .. method:: readline() + .. coroutinemethod:: readline() Read one line, where "line" is a sequence of bytes ending with ``\n``. @@ -128,7 +130,7 @@ This method is a :ref:`coroutine `. - .. method:: readexactly(n) + .. coroutinemethod:: readexactly(n) Read exactly *n* bytes. Raise an :exc:`IncompleteReadError` if the end of the stream is reached before *n* can be read, the @@ -155,6 +157,8 @@ wait for flow control. It also adds a transport attribute which references the :class:`Transport` directly. + This class is :ref:`not thread safe `. + .. attribute:: transport Transport. @@ -168,7 +172,7 @@ Close the transport: see :meth:`BaseTransport.close`. - .. method:: drain() + .. coroutinemethod:: drain() Let the write buffer of the underlying transport a chance to be flushed. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -27,7 +27,7 @@ Create a subprocess: high-level API using Process ------------------------------------------------- -.. function:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) +.. coroutinefunction:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) Create a subprocess. @@ -39,7 +39,7 @@ This function is a :ref:`coroutine `. -.. function:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) +.. coroutinefunction:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds) Run the shell command *cmd*. @@ -67,7 +67,7 @@ Run subprocesses asynchronously using the :mod:`subprocess` module. -.. method:: BaseEventLoop.subprocess_exec(protocol_factory, \*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) +.. coroutinemethod:: BaseEventLoop.subprocess_exec(protocol_factory, \*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) Create a subprocess from one or more string arguments (character strings or bytes strings encoded to the :ref:`filesystem encoding @@ -116,7 +116,7 @@ See the constructor of the :class:`subprocess.Popen` class for parameters. -.. method:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) +.. coroutinemethod:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \*\*kwargs) Create a subprocess from *cmd*, which is a character string or a bytes string encoded to the :ref:`filesystem encoding `, @@ -193,7 +193,10 @@ :meth:`~subprocess.Popen.wait` method of the :class:`~subprocess.Popen` class is implemented as a busy loop. - .. method:: wait() + This class is :ref:`not thread safe `. See also the + :ref:`Subprocess and threads ` section. + + .. coroutinemethod:: wait() Wait for child process to terminate. Set and return :attr:`returncode` attribute. @@ -207,7 +210,7 @@ blocks waiting for the OS pipe buffer to accept more data. Use the :meth:`communicate` method when using pipes to avoid that. - .. method:: communicate(input=None) + .. coroutinemethod:: communicate(input=None) Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. @@ -310,6 +313,8 @@ subprocesses from other threads. Call the :func:`get_child_watcher` function in the main thread to instantiate the child watcher. +The :class:`asyncio.subprocess.Process` class is not thread safe. + .. seealso:: The :ref:`Concurrency and multithreading in asyncio diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -9,22 +9,16 @@ * :class:`Lock` * :class:`Event` * :class:`Condition` + +Semaphores: + * :class:`Semaphore` * :class:`BoundedSemaphore` -Queues: - -* :class:`Queue` -* :class:`PriorityQueue` -* :class:`LifoQueue` -* :class:`JoinableQueue` - -asyncio locks and queues API were designed to be close to classes of the -:mod:`threading` module (:class:`~threading.Lock`, :class:`~threading.Event`, +asyncio lock API was designed to be close to classes of the :mod:`threading` +module (:class:`~threading.Lock`, :class:`~threading.Event`, :class:`~threading.Condition`, :class:`~threading.Semaphore`, -:class:`~threading.BoundedSemaphore`) and the :mod:`queue` module -(:class:`~queue.Queue`, :class:`~queue.PriorityQueue`, -:class:`~queue.LifoQueue`), but they have no *timeout* parameter. The +:class:`~threading.BoundedSemaphore`), but it has no *timeout* parameter. The :func:`asyncio.wait_for` function can be used to cancel a task after a timeout. Locks @@ -60,6 +54,8 @@ Locks also support the context management protocol. ``(yield from lock)`` should be used as context manager expression. + This class is :ref:`not thread safe `. + Usage:: lock = Lock() @@ -89,7 +85,7 @@ Return ``True`` if the lock is acquired. - .. method:: acquire() + .. coroutinemethod:: acquire() Acquire a lock. @@ -123,6 +119,8 @@ method. The :meth:`wait` method blocks until the flag is true. The flag is initially false. + This class is :ref:`not thread safe `. + .. method:: clear() Reset the internal flag to false. Subsequently, coroutines calling @@ -139,7 +137,7 @@ true are awakened. Coroutine that call :meth:`wait` once the flag is true will not block at all. - .. method:: wait() + .. coroutinemethod:: wait() Block until the internal flag is true. @@ -166,7 +164,9 @@ object, and it is used as the underlying lock. Otherwise, a new :class:`Lock` object is created and used as the underlying lock. - .. method:: acquire() + This class is :ref:`not thread safe `. + + .. coroutinemethod:: acquire() Acquire the underlying lock. @@ -213,7 +213,7 @@ There is no return value. - .. method:: wait() + .. coroutinemethod:: wait() Wait until notified. @@ -227,7 +227,7 @@ This method is a :ref:`coroutine `. - .. method:: wait_for(predicate) + .. coroutinemethod:: wait_for(predicate) Wait until a predicate becomes true. @@ -258,7 +258,9 @@ defaults to ``1``. If the value given is less than ``0``, :exc:`ValueError` is raised. - .. method:: acquire() + This class is :ref:`not thread safe `. + + .. coroutinemethod:: acquire() Acquire a semaphore. @@ -273,7 +275,7 @@ Returns ``True`` if semaphore can not be acquired immediately. - .. method:: release() + .. coroutinemethod:: release() Release a semaphore, incrementing the internal counter by one. When it was zero on entry and another coroutine is waiting for it to become @@ -285,154 +287,8 @@ .. class:: BoundedSemaphore(value=1, \*, loop=None) - A bounded semaphore implementation. Inherit from :class:`Semaphore`. + A bounded semaphore implementation. Inherit from :class:`Semaphore`. - This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would - increase the value above the initial value. + This raises :exc:`ValueError` in :meth:`~Semaphore.release` if it would + increase the value above the initial value. - -Queues ------- - -Queue -^^^^^ - -.. class:: Queue(maxsize=0, \*, loop=None) - - A queue, useful for coordinating producer and consumer coroutines. - - If *maxsize* is less than or equal to zero, the queue size is infinite. If - it is an integer greater than ``0``, then ``yield from put()`` will block - when the queue reaches *maxsize*, until an item is removed by :meth:`get`. - - Unlike the standard library :mod:`queue`, you can reliably know this Queue's - size with :meth:`qsize`, since your single-threaded asyncio application won't - be interrupted between calling :meth:`qsize` and doing an operation on the - Queue. - - .. method:: empty() - - Return ``True`` if the queue is empty, ``False`` otherwise. - - .. method:: full() - - Return ``True`` if there are :attr:`maxsize` items in the queue. - - .. note:: - - If the Queue was initialized with ``maxsize=0`` (the default), then - :meth:`full()` is never ``True``. - - .. method:: get() - - Remove and return an item from the queue. If queue is empty, wait until - an item is available. - - This method is a :ref:`coroutine `. - - .. seealso:: - - The :meth:`empty` method. - - .. method:: get_nowait() - - Remove and return an item from the queue. - - Return an item if one is immediately available, else raise - :exc:`QueueEmpty`. - - .. method:: put(item) - - Put an item into the queue. If the queue is full, wait until a free slot - is available before adding item. - - This method is a :ref:`coroutine `. - - .. seealso:: - - The :meth:`full` method. - - .. method:: put_nowait(item) - - Put an item into the queue without blocking. - - If no free slot is immediately available, raise :exc:`QueueFull`. - - .. method:: qsize() - - Number of items in the queue. - - .. attribute:: maxsize - - Number of items allowed in the queue. - - -PriorityQueue -^^^^^^^^^^^^^ - -.. class:: PriorityQueue - - A subclass of :class:`Queue`; retrieves entries in priority order (lowest - first). - - Entries are typically tuples of the form: (priority number, data). - - -LifoQueue -^^^^^^^^^ - -.. class:: LifoQueue - - A subclass of :class:`Queue` that retrieves most recently added entries - first. - - -JoinableQueue -^^^^^^^^^^^^^ - -.. class:: JoinableQueue - - A subclass of :class:`Queue` with :meth:`task_done` and :meth:`join` - methods. - - .. method:: join() - - Block until all items in the queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls - :meth:`task_done` to indicate that the item was retrieved and all work on - it is complete. When the count of unfinished tasks drops to zero, - :meth:`join` unblocks. - - This method is a :ref:`coroutine `. - - .. method:: task_done() - - Indicate that a formerly enqueued task is complete. - - Used by queue consumers. For each :meth:`~Queue.get` used to fetch a task, a - subsequent call to :meth:`task_done` tells the queue that the processing - on the task is complete. - - If a :meth:`join` is currently blocking, it will resume when all items - have been processed (meaning that a :meth:`task_done` call was received - for every item that had been :meth:`~Queue.put` into the queue). - - Raises :exc:`ValueError` if called more times than there were items - placed in the queue. - - -Exceptions -^^^^^^^^^^ - -.. exception:: QueueEmpty - - Exception raised when the :meth:`~Queue.get_nowait` method is called on a - :class:`Queue` object which is empty. - - -.. exception:: QueueFull - - Exception raised when the :meth:`~Queue.put_nowait` method is called on a - :class:`Queue` object which is full. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -209,6 +209,8 @@ :func:`~concurrent.futures.as_completed` functions in the :mod:`concurrent.futures` package. + This class is :ref:`not thread safe `. + .. method:: cancel() Cancel the future and schedule callbacks. @@ -375,6 +377,8 @@ Don't directly create :class:`Task` instances: use the :func:`async` function or the :meth:`BaseEventLoop.create_task` method. + This class is :ref:`not thread safe `. + .. classmethod:: all_tasks(loop=None) Return a set of all tasks for an event loop. @@ -545,7 +549,7 @@ Return ``True`` if *func* is a decorated :ref:`coroutine function `. -.. function:: sleep(delay, result=None, \*, loop=None) +.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) Create a :ref:`coroutine ` that completes after a given time (in seconds). If *result* is provided, it is produced to the caller @@ -554,6 +558,8 @@ The resolution of the sleep depends on the :ref:`granularity of the event loop `. + This function is a :ref:`coroutine `. + .. function:: shield(arg, \*, loop=None) Wait for a future, shielding it from cancellation. @@ -581,7 +587,7 @@ except CancelledError: res = None -.. function:: wait(futures, \*, loop=None, timeout=None, return_when=ALL_COMPLETED) +.. coroutinefunction:: wait(futures, \*, loop=None, timeout=None, return_when=ALL_COMPLETED) Wait for the Futures and coroutine objects given by the sequence *futures* to complete. Coroutines will be wrapped in Tasks. Returns two sets of @@ -626,7 +632,7 @@ when the timeout occurs are returned in the second set. -.. function:: wait_for(fut, timeout, \*, loop=None) +.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None) Wait for the single :class:`Future` or :ref:`coroutine object ` to complete with timeout. If *timeout* is ``None``, block until the future diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -46,6 +46,11 @@ you absolutely, positively have to use a library that makes blocking I/O calls. +Asynchronous programming is more complex than classical "sequential" +programming: see the :ref:`Develop with asyncio ` page which lists +common traps and explains how to avoid them. :ref:`Enable the debug mode +` during development to detect common issues. + Table of contents: .. toctree:: @@ -58,6 +63,7 @@ asyncio-stream.rst asyncio-subprocess.rst asyncio-sync.rst + asyncio-queue.rst asyncio-dev.rst .. seealso:: diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -65,9 +65,6 @@ data. More than one line may be passed at a time. If the optional argument *header* is present and true, underscores will be decoded as spaces. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. function:: b2a_qp(data, quotetabs=False, istext=True, header=False) @@ -156,9 +153,6 @@ of hexadecimal digits (which can be upper or lower case), otherwise a :exc:`TypeError` is raised. - .. versionchanged:: 3.2 - Accept only bytestring or bytearray objects as input. - .. exception:: Error diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -9,7 +9,7 @@ module: pickle module: copy -The :mod:`copyreg` module offers a way to define fuctions used while pickling +The :mod:`copyreg` module offers a way to define functions used while pickling specific objects. The :mod:`pickle` and :mod:`copy` modules use those functions when pickling/copying those objects. The module provides configuration information about object constructors which are not classes. diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -169,6 +169,12 @@ status code that we don't understand. +.. exception:: LineTooLong + + A subclass of :exc:`HTTPException`. Raised if an excessively long line + is received in the HTTP protocol from the server. + + The constants defined in this module are: .. data:: HTTP_PORT diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -64,6 +64,18 @@ Contains the server instance. + .. attribute:: close_connection + + Boolean that should be set before :meth:`handle_one_request` returns, + indicating if another request may be expected, or if the connection should + be shut down. + + .. attribute:: requestline + + Contains the string representation of the HTTP request line. The + terminating CRLF is stripped. This attribute should be set by + :meth:`handle_one_request`. If no valid request line was processed, it + should be set to the empty string. .. attribute:: command diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -106,8 +106,8 @@ extension is already known, the new type will replace the old one. When the type is already known the extension will be added to the list of known extensions. - When *strict* is ``True`` (the default), the mapping will added to the official MIME - types, otherwise to the non-standard ones. + When *strict* is ``True`` (the default), the mapping will be added to the + official MIME types, otherwise to the non-standard ones. .. data:: inited diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2159,7 +2159,8 @@ contain :func:`os.access`, otherwise it will be empty. To check whether you can use the *effective_ids* parameter for - :func:`os.access`, use the ``in`` operator on ``supports_dir_fd``, like so:: + :func:`os.access`, use the ``in`` operator on ``supports_effective_ids``, + like so:: os.access in os.supports_effective_ids diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -281,7 +281,9 @@ assertion`. ``(?<=abc)def`` will find a match in ``abcdef``, since the lookbehind will back up 3 characters and check if the contained pattern matches. The contained pattern must only match strings of some fixed length, meaning that - ``abc`` or ``a|b`` are allowed, but ``a*`` and ``a{3,4}`` are not. Note that + ``abc`` or ``a|b`` are allowed, but ``a*`` and ``a{3,4}`` are not. Group + references are not supported even if they match strings of some fixed length. + Note that patterns which start with positive lookbehind assertions will not match at the beginning of the string being searched; you will most likely want to use the :func:`search` function rather than the :func:`match` function: @@ -301,7 +303,8 @@ Matches if the current position in the string is not preceded by a match for ``...``. This is called a :dfn:`negative lookbehind assertion`. Similar to positive lookbehind assertions, the contained pattern must only match strings of - some fixed length. Patterns which start with negative lookbehind assertions may + some fixed length and shouldn't contain group references. + Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched. ``(?(id/name)yes-pattern|no-pattern)`` diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1067,7 +1067,7 @@ * Numbers are compared arithmetically. * The values :const:`float('NaN')` and :const:`Decimal('NaN')` are special. - The are identical to themselves, ``x is x`` but are not equal to themselves, + They are identical to themselves, ``x is x`` but are not equal to themselves, ``x != x``. Additionally, comparing any value to a not-a-number value will return ``False``. For example, both ``3 < float('NaN')`` and ``float('NaN') < 3`` will return ``False``. diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -145,6 +145,25 @@ return PyClassmember.run(self) +class PyCoroutineMixin(object): + def handle_signature(self, sig, signode): + ret = super(PyCoroutineMixin, self).handle_signature(sig, signode) + signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine ')) + return ret + + +class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel): + def run(self): + self.name = 'py:function' + return PyModulelevel.run(self) + + +class PyCoroutineMethod(PyCoroutineMixin, PyClassmember): + def run(self): + self.name = 'py:method' + return PyClassmember.run(self) + + # Support for documenting version of removal in deprecations class DeprecatedRemoved(Directive): @@ -347,5 +366,7 @@ app.add_description_unit('2to3fixer', '2to3fixer', '%s (2to3 fixer)') app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction) app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod) + app.add_directive_to_domain('py', 'coroutinefunction', PyCoroutineFunction) + app.add_directive_to_domain('py', 'coroutinemethod', PyCoroutineMethod) app.add_directive('miscnews', MiscNews) return {'version': '1.0', 'parallel_read_safe': True} diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -1052,7 +1052,7 @@ always ends with a nul character. If size is not NULL, write the number of wide characters (excluding the null character) into *size. - Returns a buffer allocated by PyMem_Alloc() (use PyMem_Free() to free it) + Returns a buffer allocated by PyMem_Malloc() (use PyMem_Free() to free it) on success. On error, returns NULL, *size is undefined and raises a MemoryError. */ diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -57,6 +57,8 @@ info.append('pid=%s' % self._pid) if self._returncode is not None: info.append('returncode=%s' % self._returncode) + else: + info.append('running') stdin = self._pipes.get(0) if stdin is not None: @@ -93,7 +95,12 @@ continue proto.pipe.close() - if self._proc is not None and self._returncode is None: + if (self._proc is not None + # the child process finished? + and self._returncode is None + # the child process finished but the transport was not notified yet? + and self._proc.poll() is None + ): if self._loop.get_debug(): logger.warning('Close running child process: kill %r', self) diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -1,7 +1,7 @@ """Queues""" -__all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'JoinableQueue', - 'QueueFull', 'QueueEmpty'] +__all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'QueueFull', 'QueueEmpty', + 'JoinableQueue'] import collections import heapq @@ -49,6 +49,9 @@ self._getters = collections.deque() # Pairs of (item, Future). self._putters = collections.deque() + self._unfinished_tasks = 0 + self._finished = locks.Event(loop=self._loop) + self._finished.set() self._init(maxsize) def _init(self, maxsize): @@ -59,6 +62,8 @@ def _put(self, item): self._queue.append(item) + self._unfinished_tasks += 1 + self._finished.clear() def __repr__(self): return '<{} at {:#x} {}>'.format( @@ -75,6 +80,8 @@ result += ' _getters[{}]'.format(len(self._getters)) if self._putters: result += ' _putters[{}]'.format(len(self._putters)) + if self._unfinished_tasks: + result += ' tasks={}'.format(self._unfinished_tasks) return result def _consume_done_getters(self): @@ -126,9 +133,6 @@ 'queue non-empty, why are getters waiting?') getter = self._getters.popleft() - - # Use _put and _get instead of passing item straight to getter, in - # case a subclass has logic that must run (e.g. JoinableQueue). self._put(item) # getter cannot be cancelled, we just removed done getters @@ -154,9 +158,6 @@ 'queue non-empty, why are getters waiting?') getter = self._getters.popleft() - - # Use _put and _get instead of passing item straight to getter, in - # case a subclass has logic that must run (e.g. JoinableQueue). self._put(item) # getter cannot be cancelled, we just removed done getters @@ -219,56 +220,6 @@ else: raise QueueEmpty - -class PriorityQueue(Queue): - """A subclass of Queue; retrieves entries in priority order (lowest first). - - Entries are typically tuples of the form: (priority number, data). - """ - - def _init(self, maxsize): - self._queue = [] - - def _put(self, item, heappush=heapq.heappush): - heappush(self._queue, item) - - def _get(self, heappop=heapq.heappop): - return heappop(self._queue) - - -class LifoQueue(Queue): - """A subclass of Queue that retrieves most recently added entries first.""" - - def _init(self, maxsize): - self._queue = [] - - def _put(self, item): - self._queue.append(item) - - def _get(self): - return self._queue.pop() - - -class JoinableQueue(Queue): - """A subclass of Queue with task_done() and join() methods.""" - - def __init__(self, maxsize=0, *, loop=None): - super().__init__(maxsize=maxsize, loop=loop) - self._unfinished_tasks = 0 - self._finished = locks.Event(loop=self._loop) - self._finished.set() - - def _format(self): - result = Queue._format(self) - if self._unfinished_tasks: - result += ' tasks={}'.format(self._unfinished_tasks) - return result - - def _put(self, item): - super()._put(item) - self._unfinished_tasks += 1 - self._finished.clear() - def task_done(self): """Indicate that a formerly enqueued task is complete. @@ -294,9 +245,42 @@ """Block until all items in the queue have been gotten and processed. The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls task_done() - to indicate that the item was retrieved and all work on it is complete. + queue. The count goes down whenever a consumer calls task_done() to + indicate that the item was retrieved and all work on it is complete. When the count of unfinished tasks drops to zero, join() unblocks. """ if self._unfinished_tasks > 0: yield from self._finished.wait() + + +class PriorityQueue(Queue): + """A subclass of Queue; retrieves entries in priority order (lowest first). + + Entries are typically tuples of the form: (priority number, data). + """ + + def _init(self, maxsize): + self._queue = [] + + def _put(self, item, heappush=heapq.heappush): + heappush(self._queue, item) + + def _get(self, heappop=heapq.heappop): + return heappop(self._queue) + + +class LifoQueue(Queue): + """A subclass of Queue that retrieves most recently added entries first.""" + + def _init(self, maxsize): + self._queue = [] + + def _put(self, item): + self._queue.append(item) + + def _get(self): + return self._queue.pop() + + +JoinableQueue = Queue +"""Deprecated alias for Queue.""" diff --git a/Lib/dbm/dumb.py b/Lib/dbm/dumb.py --- a/Lib/dbm/dumb.py +++ b/Lib/dbm/dumb.py @@ -21,6 +21,7 @@ """ +import ast as _ast import io as _io import os as _os import collections @@ -85,7 +86,7 @@ with f: for line in f: line = line.rstrip() - key, pos_and_siz_pair = eval(line) + key, pos_and_siz_pair = _ast.literal_eval(line) key = key.encode('Latin-1') self._index[key] = pos_and_siz_pair diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -74,12 +74,14 @@ import collections from urllib.parse import urlsplit +# HTTPMessage, parse_headers(), and the HTTP status code constants are +# intentionally omitted for simplicity __all__ = ["HTTPResponse", "HTTPConnection", "HTTPException", "NotConnected", "UnknownProtocol", "UnknownTransferEncoding", "UnimplementedFileMode", "IncompleteRead", "InvalidURL", "ImproperConnectionState", "CannotSendRequest", "CannotSendHeader", "ResponseNotReady", - "BadStatusLine", "error", "responses"] + "BadStatusLine", "LineTooLong", "error", "responses"] HTTP_PORT = 80 HTTPS_PORT = 443 diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -82,7 +82,10 @@ __version__ = "0.6" -__all__ = ["HTTPServer", "BaseHTTPRequestHandler"] +__all__ = [ + "HTTPServer", "BaseHTTPRequestHandler", + "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler", +] import html import http.client @@ -270,7 +273,7 @@ """ self.command = None # set in case of error on the first line self.request_version = version = self.default_request_version - self.close_connection = 1 + self.close_connection = True requestline = str(self.raw_requestline, 'iso-8859-1') requestline = requestline.rstrip('\r\n') self.requestline = requestline @@ -296,14 +299,14 @@ self.send_error(400, "Bad request version (%r)" % version) return False if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1": - self.close_connection = 0 + self.close_connection = False if version_number >= (2, 0): self.send_error(505, "Invalid HTTP Version (%s)" % base_version_number) return False elif len(words) == 2: command, path = words - self.close_connection = 1 + self.close_connection = True if command != 'GET': self.send_error(400, "Bad HTTP/0.9 request type (%r)" % command) @@ -325,10 +328,10 @@ conntype = self.headers.get('Connection', "") if conntype.lower() == 'close': - self.close_connection = 1 + self.close_connection = True elif (conntype.lower() == 'keep-alive' and self.protocol_version >= "HTTP/1.1"): - self.close_connection = 0 + self.close_connection = False # Examine the headers and look for an Expect directive expect = self.headers.get('Expect', "") if (expect.lower() == "100-continue" and @@ -373,7 +376,7 @@ self.send_error(414) return if not self.raw_requestline: - self.close_connection = 1 + self.close_connection = True return if not self.parse_request(): # An error code has been sent, just exit @@ -388,12 +391,12 @@ except socket.timeout as e: #a read or a write timed out. Discard this connection self.log_error("Request timed out: %r", e) - self.close_connection = 1 + self.close_connection = True return def handle(self): """Handle multiple requests if necessary.""" - self.close_connection = 1 + self.close_connection = True self.handle_one_request() while not self.close_connection: @@ -475,9 +478,9 @@ if keyword.lower() == 'connection': if value.lower() == 'close': - self.close_connection = 1 + self.close_connection = True elif value.lower() == 'keep-alive': - self.close_connection = 0 + self.close_connection = False def end_headers(self): """Send the blank line ending the MIME headers.""" diff --git a/Lib/pathlib.py b/Lib/pathlib.py --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -73,6 +73,10 @@ # parts. This makes the result of parsing e.g. # ("C:", "/", "a") reasonably intuitive. for part in it: + if not part: + continue + if altsep: + part = part.replace(altsep, sep) drv = self.splitroot(part)[0] if drv: break diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -270,7 +270,7 @@ except: return None del sys.modules['__temp__'] - result = (module.__doc__ or '').splitlines()[0] + result = module.__doc__.splitlines()[0] if module.__doc__ else None # Cache the result. cache[filename] = (mtime, result) return result @@ -1407,9 +1407,6 @@ def pager(text): """The first time this is called, determine what kind of pager to use.""" global pager - # Escape non-encodable characters to avoid encoding errors later - encoding = sys.getfilesystemencoding() - text = text.encode(encoding, 'backslashreplace').decode(encoding) pager = getpager() pager(text) @@ -1452,10 +1449,12 @@ def pipepager(text, cmd): """Page through text by feeding it to another program.""" - pipe = os.popen(cmd, 'w') + import subprocess + proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE) try: - pipe.write(text) - pipe.close() + with proc: + with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe: + pipe.write(text) except OSError: pass # Ignore broken pipes caused by quitting the pager program. @@ -1463,16 +1462,21 @@ """Page through text by invoking a program on a temporary file.""" import tempfile filename = tempfile.mktemp() - with open(filename, 'w') as file: + with open(filename, 'w', errors='backslashreplace') as file: file.write(text) try: os.system(cmd + ' "' + filename + '"') finally: os.unlink(filename) +def _escape_stdout(text): + # Escape non-encodable characters to avoid encoding errors later + encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8' + return text.encode(encoding, 'backslashreplace').decode(encoding) + def ttypager(text): """Page through text on a text terminal.""" - lines = plain(text).split('\n') + lines = plain(_escape_stdout(text)).split('\n') try: import tty fd = sys.stdin.fileno() @@ -1516,7 +1520,7 @@ def plainpager(text): """Simply print unformatted text. This is the ultimate fallback.""" - sys.stdout.write(plain(text)) + sys.stdout.write(plain(_escape_stdout(text))) def describe(thing): """Produce a short description of the given thing.""" @@ -2075,7 +2079,7 @@ if onerror: onerror(modname) continue - desc = (module.__doc__ or '').splitlines()[0] + desc = module.__doc__.splitlines()[0] if module.__doc__ else '' path = getattr(module,'__file__',None) name = modname + ' - ' + desc if name.lower().find(key) >= 0: diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -69,6 +69,8 @@ self.open = [] self.groups = 1 self.groupdict = {} + self.lookbehind = 0 + def opengroup(self, name=None): gid = self.groups self.groups = gid + 1 @@ -352,6 +354,11 @@ if group < state.groups: if not state.checkgroup(group): raise error("cannot refer to open group") + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) return GROUPREF, group raise ValueError if len(escape) == 2: @@ -630,6 +637,11 @@ if gid is None: msg = "unknown group name: {0!r}".format(name) raise error(msg) + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) subpatternappend((GROUPREF, gid)) continue else: @@ -658,7 +670,10 @@ raise error("syntax error") dir = -1 # lookbehind char = sourceget() + state.lookbehind += 1 p = _parse_sub(source, state) + if dir < 0: + state.lookbehind -= 1 if not sourcematch(")"): raise error("unbalanced parenthesis") if char == "=": @@ -689,6 +704,11 @@ condgroup = int(condname) except ValueError: raise error("bad character in group name") + if state.lookbehind: + import warnings + warnings.warn('group references in lookbehind ' + 'assertions are not supported', + RuntimeWarning) else: # flags if not source.next in FLAGS: diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -170,14 +170,12 @@ # * Prefer any AES-GCM over any AES-CBC for better performance and security # * Then Use HIGH cipher suites as a fallback # * Then Use 3DES as fallback which is secure but slow -# * Finally use RC4 as a fallback which is problematic but needed for -# compatibility some times. # * Disable NULL authentication, NULL encryption, and MD5 MACs for security # reasons _DEFAULT_CIPHERS = ( 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' - 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' - 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' + 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' + '!eNULL:!MD5' ) # Restricted and more secure ciphers for the server side diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2491,16 +2491,16 @@ _, ext = os.path.splitext(tar_name) compressions = { # gz - 'gz': 'gz', - 'tgz': 'gz', + '.gz': 'gz', + '.tgz': 'gz', # xz - 'xz': 'xz', - 'txz': 'xz', + '.xz': 'xz', + '.txz': 'xz', # bz2 - 'bz2': 'bz2', - 'tbz': 'bz2', - 'tbz2': 'bz2', - 'tb2': 'bz2', + '.bz2': 'bz2', + '.tbz': 'bz2', + '.tbz2': 'bz2', + '.tb2': 'bz2', } tar_mode = 'w:' + compressions[ext] if ext in compressions else 'w' tar_files = args.create diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -2020,6 +2020,12 @@ class _TestRemoteManager(BaseTestCase): ALLOWED_TYPES = ('manager',) + values = ['hello world', None, True, 2.25, + 'hall\xe5 v\xe4rlden', + '\u043f\u0440\u0438\u0432\u0456\u0442 \u0441\u0432\u0456\u0442', + b'hall\xe5 v\xe4rlden', + ] + result = values[:] @classmethod def _putter(cls, address, authkey): @@ -2028,7 +2034,8 @@ ) manager.connect() queue = manager.get_queue() - queue.put(('hello world', None, True, 2.25)) + # Note that xmlrpclib will deserialize object as a list not a tuple + queue.put(tuple(cls.values)) def test_remote(self): authkey = os.urandom(32) @@ -2048,8 +2055,7 @@ manager2.connect() queue = manager2.get_queue() - # Note that xmlrpclib will deserialize object as a list not a tuple - self.assertEqual(queue.get(), ['hello world', None, True, 2.25]) + self.assertEqual(queue.get(), self.result) # Because we are using xmlrpclib for serialization instead of # pickle this will cause a serialization error. @@ -3405,12 +3411,12 @@ name = os.path.join(os.path.dirname(__file__), 'mp_fork_bomb.py') if sm != 'fork': rc, out, err = test.script_helper.assert_python_failure(name, sm) - self.assertEqual('', out.decode('ascii')) - self.assertIn('RuntimeError', err.decode('ascii')) + self.assertEqual(out, b'') + self.assertIn(b'RuntimeError', err) else: rc, out, err = test.script_helper.assert_python_ok(name, sm) - self.assertEqual('123', out.decode('ascii').rstrip()) - self.assertEqual('', err.decode('ascii')) + self.assertEqual(out.rstrip(), b'123') + self.assertEqual(err, b'') # # Issue #17555: ForkAwareThreadLock diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -144,21 +144,22 @@ # the object returned by create_data(). DATA0 = ( - b'(lp0\nL0L\naL1L\naF2.0\nac' - b'builtins\ncomplex\n' - b'p1\n(F3.0\nF0.0\ntp2\nRp' - b'3\naL1L\naL-1L\naL255L\naL-' - b'255L\naL-256L\naL65535L\na' - b'L-65535L\naL-65536L\naL2' - b'147483647L\naL-2147483' - b'647L\naL-2147483648L\na(' - b'Vabc\np4\ng4\nccopyreg' - b'\n_reconstructor\np5\n(' - b'c__main__\nC\np6\ncbu' - b'iltins\nobject\np7\nNt' - b'p8\nRp9\n(dp10\nVfoo\np1' - b'1\nL1L\nsVbar\np12\nL2L\nsb' - b'g9\ntp13\nag13\naL5L\na.' + b'(lp0\nL0L\naL1L\naF2.0\n' + b'ac__builtin__\ncomple' + b'x\np1\n(F3.0\nF0.0\ntp2\n' + b'Rp3\naL1L\naL-1L\naL255' + b'L\naL-255L\naL-256L\naL' + b'65535L\naL-65535L\naL-' + b'65536L\naL2147483647L' + b'\naL-2147483647L\naL-2' + b'147483648L\na(Vabc\np4' + b'\ng4\nccopy_reg\n_recon' + b'structor\np5\n(c__main' + b'__\nC\np6\nc__builtin__' + b'\nobject\np7\nNtp8\nRp9\n' + b'(dp10\nVfoo\np11\nL1L\ns' + b'Vbar\np12\nL2L\nsbg9\ntp' + b'13\nag13\naL5L\na.' ) # Disassembly of DATA0 @@ -172,88 +173,88 @@ 14: a APPEND 15: F FLOAT 2.0 20: a APPEND - 21: c GLOBAL 'builtins complex' - 39: p PUT 1 - 42: ( MARK - 43: F FLOAT 3.0 - 48: F FLOAT 0.0 - 53: t TUPLE (MARK at 42) - 54: p PUT 2 - 57: R REDUCE - 58: p PUT 3 - 61: a APPEND - 62: L LONG 1 - 66: a APPEND - 67: L LONG -1 - 72: a APPEND - 73: L LONG 255 - 79: a APPEND - 80: L LONG -255 - 87: a APPEND - 88: L LONG -256 - 95: a APPEND - 96: L LONG 65535 - 104: a APPEND - 105: L LONG -65535 - 114: a APPEND - 115: L LONG -65536 - 124: a APPEND - 125: L LONG 2147483647 - 138: a APPEND - 139: L LONG -2147483647 - 153: a APPEND - 154: L LONG -2147483648 - 168: a APPEND - 169: ( MARK - 170: V UNICODE 'abc' - 175: p PUT 4 - 178: g GET 4 - 181: c GLOBAL 'copyreg _reconstructor' - 205: p PUT 5 - 208: ( MARK - 209: c GLOBAL '__main__ C' - 221: p PUT 6 - 224: c GLOBAL 'builtins object' - 241: p PUT 7 - 244: N NONE - 245: t TUPLE (MARK at 208) - 246: p PUT 8 - 249: R REDUCE - 250: p PUT 9 - 253: ( MARK - 254: d DICT (MARK at 253) - 255: p PUT 10 - 259: V UNICODE 'foo' - 264: p PUT 11 - 268: L LONG 1 - 272: s SETITEM - 273: V UNICODE 'bar' - 278: p PUT 12 - 282: L LONG 2 - 286: s SETITEM - 287: b BUILD - 288: g GET 9 - 291: t TUPLE (MARK at 169) - 292: p PUT 13 - 296: a APPEND - 297: g GET 13 - 301: a APPEND - 302: L LONG 5 - 306: a APPEND - 307: . STOP + 21: c GLOBAL '__builtin__ complex' + 42: p PUT 1 + 45: ( MARK + 46: F FLOAT 3.0 + 51: F FLOAT 0.0 + 56: t TUPLE (MARK at 45) + 57: p PUT 2 + 60: R REDUCE + 61: p PUT 3 + 64: a APPEND + 65: L LONG 1 + 69: a APPEND + 70: L LONG -1 + 75: a APPEND + 76: L LONG 255 + 82: a APPEND + 83: L LONG -255 + 90: a APPEND + 91: L LONG -256 + 98: a APPEND + 99: L LONG 65535 + 107: a APPEND + 108: L LONG -65535 + 117: a APPEND + 118: L LONG -65536 + 127: a APPEND + 128: L LONG 2147483647 + 141: a APPEND + 142: L LONG -2147483647 + 156: a APPEND + 157: L LONG -2147483648 + 171: a APPEND + 172: ( MARK + 173: V UNICODE 'abc' + 178: p PUT 4 + 181: g GET 4 + 184: c GLOBAL 'copy_reg _reconstructor' + 209: p PUT 5 + 212: ( MARK + 213: c GLOBAL '__main__ C' + 225: p PUT 6 + 228: c GLOBAL '__builtin__ object' + 248: p PUT 7 + 251: N NONE + 252: t TUPLE (MARK at 212) + 253: p PUT 8 + 256: R REDUCE + 257: p PUT 9 + 260: ( MARK + 261: d DICT (MARK at 260) + 262: p PUT 10 + 266: V UNICODE 'foo' + 271: p PUT 11 + 275: L LONG 1 + 279: s SETITEM + 280: V UNICODE 'bar' + 285: p PUT 12 + 289: L LONG 2 + 293: s SETITEM + 294: b BUILD + 295: g GET 9 + 298: t TUPLE (MARK at 172) + 299: p PUT 13 + 303: a APPEND + 304: g GET 13 + 308: a APPEND + 309: L LONG 5 + 313: a APPEND + 314: . STOP highest protocol among opcodes = 0 """ DATA1 = ( - b']q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c' - b'builtins\ncomplex\nq\x01' + b']q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c__' + b'builtin__\ncomplex\nq\x01' b'(G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00t' b'q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xffJ' b'\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff' b'\xff\x7fJ\x01\x00\x00\x80J\x00\x00\x00\x80(X\x03\x00\x00\x00ab' - b'cq\x04h\x04ccopyreg\n_reco' + b'cq\x04h\x04ccopy_reg\n_reco' b'nstructor\nq\x05(c__main' - b'__\nC\nq\x06cbuiltins\n' + b'__\nC\nq\x06c__builtin__\n' b'object\nq\x07Ntq\x08Rq\t}q\n(' b'X\x03\x00\x00\x00fooq\x0bK\x01X\x03\x00\x00\x00bar' b'q\x0cK\x02ubh\ttq\rh\rK\x05e.' @@ -267,66 +268,66 @@ 4: K BININT1 0 6: K BININT1 1 8: G BINFLOAT 2.0 - 17: c GLOBAL 'builtins complex' - 35: q BINPUT 1 - 37: ( MARK - 38: G BINFLOAT 3.0 - 47: G BINFLOAT 0.0 - 56: t TUPLE (MARK at 37) - 57: q BINPUT 2 - 59: R REDUCE - 60: q BINPUT 3 - 62: K BININT1 1 - 64: J BININT -1 - 69: K BININT1 255 - 71: J BININT -255 - 76: J BININT -256 - 81: M BININT2 65535 - 84: J BININT -65535 - 89: J BININT -65536 - 94: J BININT 2147483647 - 99: J BININT -2147483647 - 104: J BININT -2147483648 - 109: ( MARK - 110: X BINUNICODE 'abc' - 118: q BINPUT 4 - 120: h BINGET 4 - 122: c GLOBAL 'copyreg _reconstructor' - 146: q BINPUT 5 - 148: ( MARK - 149: c GLOBAL '__main__ C' - 161: q BINPUT 6 - 163: c GLOBAL 'builtins object' - 180: q BINPUT 7 - 182: N NONE - 183: t TUPLE (MARK at 148) - 184: q BINPUT 8 - 186: R REDUCE - 187: q BINPUT 9 - 189: } EMPTY_DICT - 190: q BINPUT 10 - 192: ( MARK - 193: X BINUNICODE 'foo' - 201: q BINPUT 11 - 203: K BININT1 1 - 205: X BINUNICODE 'bar' - 213: q BINPUT 12 - 215: K BININT1 2 - 217: u SETITEMS (MARK at 192) - 218: b BUILD - 219: h BINGET 9 - 221: t TUPLE (MARK at 109) - 222: q BINPUT 13 - 224: h BINGET 13 - 226: K BININT1 5 - 228: e APPENDS (MARK at 3) - 229: . STOP + 17: c GLOBAL '__builtin__ complex' + 38: q BINPUT 1 + 40: ( MARK + 41: G BINFLOAT 3.0 + 50: G BINFLOAT 0.0 + 59: t TUPLE (MARK at 40) + 60: q BINPUT 2 + 62: R REDUCE + 63: q BINPUT 3 + 65: K BININT1 1 + 67: J BININT -1 + 72: K BININT1 255 + 74: J BININT -255 + 79: J BININT -256 + 84: M BININT2 65535 + 87: J BININT -65535 + 92: J BININT -65536 + 97: J BININT 2147483647 + 102: J BININT -2147483647 + 107: J BININT -2147483648 + 112: ( MARK + 113: X BINUNICODE 'abc' + 121: q BINPUT 4 + 123: h BINGET 4 + 125: c GLOBAL 'copy_reg _reconstructor' + 150: q BINPUT 5 + 152: ( MARK + 153: c GLOBAL '__main__ C' + 165: q BINPUT 6 + 167: c GLOBAL '__builtin__ object' + 187: q BINPUT 7 + 189: N NONE + 190: t TUPLE (MARK at 152) + 191: q BINPUT 8 + 193: R REDUCE + 194: q BINPUT 9 + 196: } EMPTY_DICT + 197: q BINPUT 10 + 199: ( MARK + 200: X BINUNICODE 'foo' + 208: q BINPUT 11 + 210: K BININT1 1 + 212: X BINUNICODE 'bar' + 220: q BINPUT 12 + 222: K BININT1 2 + 224: u SETITEMS (MARK at 199) + 225: b BUILD + 226: h BINGET 9 + 228: t TUPLE (MARK at 112) + 229: q BINPUT 13 + 231: h BINGET 13 + 233: K BININT1 5 + 235: e APPENDS (MARK at 3) + 236: . STOP highest protocol among opcodes = 1 """ DATA2 = ( b'\x80\x02]q\x00(K\x00K\x01G@\x00\x00\x00\x00\x00\x00\x00c' - b'builtins\ncomplex\n' + b'__builtin__\ncomplex\n' b'q\x01G@\x08\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00' b'\x86q\x02Rq\x03K\x01J\xff\xff\xff\xffK\xffJ\x01\xff\xff\xff' b'J\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff' @@ -346,52 +347,52 @@ 6: K BININT1 0 8: K BININT1 1 10: G BINFLOAT 2.0 - 19: c GLOBAL 'builtins complex' - 37: q BINPUT 1 - 39: G BINFLOAT 3.0 - 48: G BINFLOAT 0.0 - 57: \x86 TUPLE2 - 58: q BINPUT 2 - 60: R REDUCE - 61: q BINPUT 3 - 63: K BININT1 1 - 65: J BININT -1 - 70: K BININT1 255 - 72: J BININT -255 - 77: J BININT -256 - 82: M BININT2 65535 - 85: J BININT -65535 - 90: J BININT -65536 - 95: J BININT 2147483647 - 100: J BININT -2147483647 - 105: J BININT -2147483648 - 110: ( MARK - 111: X BINUNICODE 'abc' - 119: q BINPUT 4 - 121: h BINGET 4 - 123: c GLOBAL '__main__ C' - 135: q BINPUT 5 - 137: ) EMPTY_TUPLE - 138: \x81 NEWOBJ - 139: q BINPUT 6 - 141: } EMPTY_DICT - 142: q BINPUT 7 - 144: ( MARK - 145: X BINUNICODE 'foo' - 153: q BINPUT 8 - 155: K BININT1 1 - 157: X BINUNICODE 'bar' - 165: q BINPUT 9 - 167: K BININT1 2 - 169: u SETITEMS (MARK at 144) - 170: b BUILD - 171: h BINGET 6 - 173: t TUPLE (MARK at 110) - 174: q BINPUT 10 - 176: h BINGET 10 - 178: K BININT1 5 - 180: e APPENDS (MARK at 5) - 181: . STOP + 19: c GLOBAL '__builtin__ complex' + 40: q BINPUT 1 + 42: G BINFLOAT 3.0 + 51: G BINFLOAT 0.0 + 60: \x86 TUPLE2 + 61: q BINPUT 2 + 63: R REDUCE + 64: q BINPUT 3 + 66: K BININT1 1 + 68: J BININT -1 + 73: K BININT1 255 + 75: J BININT -255 + 80: J BININT -256 + 85: M BININT2 65535 + 88: J BININT -65535 + 93: J BININT -65536 + 98: J BININT 2147483647 + 103: J BININT -2147483647 + 108: J BININT -2147483648 + 113: ( MARK + 114: X BINUNICODE 'abc' + 122: q BINPUT 4 + 124: h BINGET 4 + 126: c GLOBAL '__main__ C' + 138: q BINPUT 5 + 140: ) EMPTY_TUPLE + 141: \x81 NEWOBJ + 142: q BINPUT 6 + 144: } EMPTY_DICT + 145: q BINPUT 7 + 147: ( MARK + 148: X BINUNICODE 'foo' + 156: q BINPUT 8 + 158: K BININT1 1 + 160: X BINUNICODE 'bar' + 168: q BINPUT 9 + 170: K BININT1 2 + 172: u SETITEMS (MARK at 147) + 173: b BUILD + 174: h BINGET 6 + 176: t TUPLE (MARK at 113) + 177: q BINPUT 10 + 179: h BINGET 10 + 181: K BININT1 5 + 183: e APPENDS (MARK at 5) + 184: . STOP highest protocol among opcodes = 2 """ @@ -570,14 +571,14 @@ xname = X.__name__.encode('ascii') # Protocol 0 (text mode pickle): """ - 0: ( MARK - 1: i INST '__main__ X' (MARK at 0) - 15: p PUT 0 - 18: ( MARK - 19: d DICT (MARK at 18) - 20: p PUT 1 - 23: b BUILD - 24: . STOP + 0: ( MARK + 1: i INST '__main__ X' (MARK at 0) + 13: p PUT 0 + 16: ( MARK + 17: d DICT (MARK at 16) + 18: p PUT 1 + 21: b BUILD + 22: . STOP """ pickle0 = (b"(i__main__\n" b"X\n" @@ -587,15 +588,15 @@ # Protocol 1 (binary mode pickle) """ - 0: ( MARK - 1: c GLOBAL '__main__ X' - 15: q BINPUT 0 - 17: o OBJ (MARK at 0) - 18: q BINPUT 1 - 20: } EMPTY_DICT - 21: q BINPUT 2 - 23: b BUILD - 24: . STOP + 0: ( MARK + 1: c GLOBAL '__main__ X' + 13: q BINPUT 0 + 15: o OBJ (MARK at 0) + 16: q BINPUT 1 + 18: } EMPTY_DICT + 19: q BINPUT 2 + 21: b BUILD + 22: . STOP """ pickle1 = (b'(c__main__\n' b'X\n' @@ -604,16 +605,16 @@ # Protocol 2 (pickle2 = b'\x80\x02' + pickle1) """ - 0: \x80 PROTO 2 - 2: ( MARK - 3: c GLOBAL '__main__ X' - 17: q BINPUT 0 - 19: o OBJ (MARK at 2) - 20: q BINPUT 1 - 22: } EMPTY_DICT - 23: q BINPUT 2 - 25: b BUILD - 26: . STOP + 0: \x80 PROTO 2 + 2: ( MARK + 3: c GLOBAL '__main__ X' + 15: q BINPUT 0 + 17: o OBJ (MARK at 2) + 18: q BINPUT 1 + 20: } EMPTY_DICT + 21: q BINPUT 2 + 23: b BUILD + 24: . STOP """ pickle2 = (b'\x80\x02(c__main__\n' b'X\n' diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -9,7 +9,6 @@ import sys import unittest from platform import uname -from test.support import run_unittest if uname().system == "Darwin": maj, min, mic = [int(part) for part in uname().release.split(".")] @@ -24,45 +23,52 @@ 'da_DK', 'nn_NO', 'cs_CZ', 'de_LU', 'es_BO', 'sq_AL', 'sk_SK', 'fr_CH', 'de_DE', 'sr_YU', 'br_FR', 'nl_BE', 'sv_FI', 'pl_PL', 'fr_CA', 'fo_FO', 'bs_BA', 'fr_LU', 'kl_GL', 'fa_IR', 'de_BE', 'sv_SE', 'it_CH', 'uk_UA', - 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'en_US', + 'eu_ES', 'vi_VN', 'af_ZA', 'nb_NO', 'en_DK', 'tg_TJ', 'ps_AF', 'en_US', 'es_ES.ISO8859-1', 'fr_FR.ISO8859-15', 'ru_RU.KOI8-R', 'ko_KR.eucKR'] -# Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to -# workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses -# the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is -# decoded as U+30000020 (an invalid character) by mbstowcs(). -if sys.platform == 'sunos5': - old_locale = locale.setlocale(locale.LC_ALL) - try: - locales = [] - for loc in candidate_locales: - try: - locale.setlocale(locale.LC_ALL, loc) - except Error: - continue - encoding = locale.getpreferredencoding(False) - try: - localeconv() - except Exception as err: - print("WARNING: Skip locale %s (encoding %s): [%s] %s" - % (loc, encoding, type(err), err)) - else: - locales.append(loc) - candidate_locales = locales - finally: - locale.setlocale(locale.LC_ALL, old_locale) +def setUpModule(): + global candidate_locales + # Issue #13441: Skip some locales (e.g. cs_CZ and hu_HU) on Solaris to + # workaround a mbstowcs() bug. For example, on Solaris, the hu_HU locale uses + # the locale encoding ISO-8859-2, the thousauds separator is b'\xA0' and it is + # decoded as U+30000020 (an invalid character) by mbstowcs(). + if sys.platform == 'sunos5': + old_locale = locale.setlocale(locale.LC_ALL) + try: + locales = [] + for loc in candidate_locales: + try: + locale.setlocale(locale.LC_ALL, loc) + except Error: + continue + encoding = locale.getpreferredencoding(False) + try: + localeconv() + except Exception as err: + print("WARNING: Skip locale %s (encoding %s): [%s] %s" + % (loc, encoding, type(err), err)) + else: + locales.append(loc) + candidate_locales = locales + finally: + locale.setlocale(locale.LC_ALL, old_locale) -# Workaround for MSVC6(debug) crash bug -if "MSC v.1200" in sys.version: - def accept(loc): - a = loc.split(".") - return not(len(a) == 2 and len(a[-1]) >= 9) - candidate_locales = [loc for loc in candidate_locales if accept(loc)] + # Workaround for MSVC6(debug) crash bug + if "MSC v.1200" in sys.version: + def accept(loc): + a = loc.split(".") + return not(len(a) == 2 and len(a[-1]) >= 9) + candidate_locales = [loc for loc in candidate_locales if accept(loc)] # List known locale values to test against when available. # Dict formatted as `` : (, )``. If a # value is not known, use '' . -known_numerics = {'fr_FR' : (',', ''), 'en_US':('.', ',')} +known_numerics = { + 'en_US': ('.', ','), + 'fr_FR' : (',', ' '), + 'de_DE' : (',', '.'), + 'ps_AF': ('\u066b', '\u066c'), +} class _LocaleTests(unittest.TestCase): @@ -91,10 +97,12 @@ calc_value, known_value, calc_type, data_type, set_locale, used_locale)) + return True @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_nl_langinfo(self): # Test nl_langinfo against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -103,10 +111,14 @@ continue for li, lc in ((RADIXCHAR, "decimal_point"), (THOUSEP, "thousands_sep")): - self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc) + if self.numeric_tester('nl_langinfo', nl_langinfo(li), lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') def test_lc_numeric_localeconv(self): # Test localeconv against known values + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -116,11 +128,15 @@ formatting = localeconv() for lc in ("decimal_point", "thousands_sep"): - self.numeric_tester('localeconv', formatting[lc], lc, loc) + if self.numeric_tester('localeconv', formatting[lc], lc, loc): + tested = True + if not tested: + self.skipTest('no suitable locales') @unittest.skipUnless(nl_langinfo, "nl_langinfo is not available") def test_lc_numeric_basic(self): # Test nl_langinfo against localeconv + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -140,10 +156,14 @@ "(set to %s, using %s)" % ( nl_radixchar, li_radixchar, loc, set_locale)) + tested = True + if not tested: + self.skipTest('no suitable locales') def test_float_parsing(self): # Bug #1391872: Test whether float parsing is okay on European # locales. + tested = False for loc in candidate_locales: try: setlocale(LC_NUMERIC, loc) @@ -162,9 +182,10 @@ if localeconv()['decimal_point'] != '.': self.assertRaises(ValueError, float, localeconv()['decimal_point'].join(['1', '23'])) + tested = True + if not tested: + self.skipTest('no suitable locales') -def test_main(): - run_unittest(_LocaleTests) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py --- a/Lib/test/test_asyncio/test_queues.py +++ b/Lib/test/test_asyncio/test_queues.py @@ -408,14 +408,14 @@ self.assertEqual([1, 2, 3], items) -class JoinableQueueTests(_QueueTestBase): +class QueueJoinTests(_QueueTestBase): def test_task_done_underflow(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) self.assertRaises(ValueError, q.task_done) def test_task_done(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) for i in range(100): q.put_nowait(i) @@ -452,7 +452,7 @@ self.loop.run_until_complete(asyncio.wait(tasks, loop=self.loop)) def test_join_empty_queue(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) # Test that a queue join()s successfully, and before anything else # (done twice for insurance). @@ -465,7 +465,7 @@ self.loop.run_until_complete(join()) def test_format(self): - q = asyncio.JoinableQueue(loop=self.loop) + q = asyncio.Queue(loop=self.loop) self.assertEqual(q._format(), 'maxsize=0') q._unfinished_tasks = 2 diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -349,6 +349,70 @@ self.loop.run_until_complete(cancel_make_transport()) test_utils.run_briefly(self.loop) + def test_close_kill_running(self): + @asyncio.coroutine + def kill_running(): + create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + *PROGRAM_BLOCKED) + transport, protocol = yield from create + + kill_called = False + def kill(): + nonlocal kill_called + kill_called = True + orig_kill() + + proc = transport.get_extra_info('subprocess') + orig_kill = proc.kill + proc.kill = kill + returncode = transport.get_returncode() + transport.close() + yield from transport._wait() + return (returncode, kill_called) + + # Ignore "Close running child process: kill ..." log + with test_utils.disable_logger(): + returncode, killed = self.loop.run_until_complete(kill_running()) + self.assertIsNone(returncode) + + # transport.close() must kill the process if it is still running + self.assertTrue(killed) + test_utils.run_briefly(self.loop) + + def test_close_dont_kill_finished(self): + @asyncio.coroutine + def kill_running(): + create = self.loop.subprocess_exec(asyncio.SubprocessProtocol, + *PROGRAM_BLOCKED) + transport, protocol = yield from create + proc = transport.get_extra_info('subprocess') + + # kill the process (but asyncio is not notified immediatly) + proc.kill() + proc.wait() + + proc.kill = mock.Mock() + proc_returncode = proc.poll() + transport_returncode = transport.get_returncode() + transport.close() + return (proc_returncode, transport_returncode, proc.kill.called) + + # Ignore "Unknown child process pid ..." log of SafeChildWatcher, + # emitted because the test already consumes the exit status: + # proc.wait() + with test_utils.disable_logger(): + result = self.loop.run_until_complete(kill_running()) + test_utils.run_briefly(self.loop) + + proc_returncode, transport_return_code, killed = result + + self.assertIsNotNone(proc_returncode) + self.assertIsNone(transport_return_code) + + # transport.close() must not kill the process if it finished, even if + # the transport was not notified yet + self.assertFalse(killed) + if sys.platform != 'win32': # Unix diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -295,7 +295,7 @@ def test_create_unix_connection_path_sock(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', sock=object()) + lambda: None, os.devnull, sock=object()) with self.assertRaisesRegex(ValueError, 'path and sock can not be'): self.loop.run_until_complete(coro) @@ -308,14 +308,14 @@ def test_create_unix_connection_nossl_serverhost(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', server_hostname='spam') + lambda: None, os.devnull, server_hostname='spam') with self.assertRaisesRegex(ValueError, 'server_hostname is only meaningful'): self.loop.run_until_complete(coro) def test_create_unix_connection_ssl_noserverhost(self): coro = self.loop.create_unix_connection( - lambda: None, '/dev/null', ssl=True) + lambda: None, os.devnull, ssl=True) with self.assertRaisesRegex( ValueError, 'you have to pass server_hostname when using ssl'): diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -87,11 +87,11 @@ def testBadArgs(self): self.assertRaises(TypeError, BZ2File, 123.456) - self.assertRaises(ValueError, BZ2File, "/dev/null", "z") - self.assertRaises(ValueError, BZ2File, "/dev/null", "rx") - self.assertRaises(ValueError, BZ2File, "/dev/null", "rbt") - self.assertRaises(ValueError, BZ2File, "/dev/null", compresslevel=0) - self.assertRaises(ValueError, BZ2File, "/dev/null", compresslevel=10) + self.assertRaises(ValueError, BZ2File, os.devnull, "z") + self.assertRaises(ValueError, BZ2File, os.devnull, "rx") + self.assertRaises(ValueError, BZ2File, os.devnull, "rbt") + self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=0) + self.assertRaises(ValueError, BZ2File, os.devnull, compresslevel=10) def testRead(self): self.createTempFile() diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -186,9 +186,9 @@ cgi.initlog("%s", "Testing initlog 1") cgi.log("%s", "Testing log 2") self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n") - if os.path.exists("/dev/null"): + if os.path.exists(os.devnull): cgi.logfp = None - cgi.logfile = "/dev/null" + cgi.logfile = os.devnull cgi.initlog("%s", "Testing log 3") self.addCleanup(cgi.closelog) cgi.log("Testing log 4") diff --git a/Lib/test/test_dbm_dumb.py b/Lib/test/test_dbm_dumb.py --- a/Lib/test/test_dbm_dumb.py +++ b/Lib/test/test_dbm_dumb.py @@ -217,6 +217,15 @@ self.assertEqual(str(cm.exception), "DBM object has already been closed") + def test_eval(self): + with open(_fname + '.dir', 'w') as stream: + stream.write("str(print('Hacked!')), 0\n") + with support.captured_stdout() as stdout: + with self.assertRaises(ValueError): + with dumbdbm.open(_fname) as f: + pass + self.assertEqual(stdout.getvalue(), '') + def tearDown(self): _delete_files() diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -155,9 +155,9 @@ def test_repr(self): args = (object(), object()) args_repr = ', '.join(repr(a) for a in args) - #kwargs = {'a': object(), 'b': object()} - kwargs = {'a': object()} - kwargs_repr = ', '.join("%s=%r" % (k, v) for k, v in kwargs.items()) + kwargs = {'a': object(), 'b': object()} + kwargs_reprs = ['a={a!r}, b={b!r}'.format_map(kwargs), + 'b={b!r}, a={a!r}'.format_map(kwargs)] if self.partial is c_functools.partial: name = 'functools.partial' else: @@ -172,12 +172,14 @@ repr(f)) f = self.partial(capture, **kwargs) - self.assertEqual('{}({!r}, {})'.format(name, capture, kwargs_repr), - repr(f)) + self.assertIn(repr(f), + ['{}({!r}, {})'.format(name, capture, kwargs_repr) + for kwargs_repr in kwargs_reprs]) f = self.partial(capture, *args, **kwargs) - self.assertEqual('{}({!r}, {}, {})'.format(name, capture, args_repr, kwargs_repr), - repr(f)) + self.assertIn(repr(f), + ['{}({!r}, {}, {})'.format(name, capture, args_repr, kwargs_repr) + for kwargs_repr in kwargs_reprs]) def test_pickle(self): f = self.partial(signature, 'asdf', bar=True) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -190,6 +190,8 @@ 'linux-vdso.so', 'warning: Could not load shared library symbols for ' 'linux-gate.so', + 'warning: Could not load shared library symbols for ' + 'linux-vdso64.so', 'Do you need "set solib-search-path" or ' '"set sysroot"?', 'warning: Source file is more recent than executable.', diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -708,7 +708,22 @@ self.assertTrue(response.closed) self.assertTrue(conn.sock.file_closed) + class OfflineTest(TestCase): + def test_all(self): + # Documented objects defined in the module should be in __all__ + expected = {"responses"} # White-list documented dict() object + # HTTPMessage, parse_headers(), and the HTTP status code constants are + # intentionally omitted for simplicity + blacklist = {"HTTPMessage", "parse_headers"} + for name in dir(client): + if name in blacklist: + continue + module_object = getattr(client, name) + if getattr(module_object, "__module__", None) == "http.client": + expected.add(name) + self.assertCountEqual(client.__all__, expected) + def test_responses(self): self.assertEqual(client.responses[client.NOT_FOUND], "Not Found") diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -616,6 +616,11 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.1') + self.assertSequenceEqual(self.handler.headers.items(), ()) def test_http_1_0(self): result = self.send_typical_request(b'GET / HTTP/1.0\r\n\r\n') @@ -623,6 +628,11 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.0') + self.assertSequenceEqual(self.handler.headers.items(), ()) def test_http_0_9(self): result = self.send_typical_request(b'GET / HTTP/0.9\r\n\r\n') @@ -636,6 +646,12 @@ self.verify_expected_headers(result[1:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.0') + headers = (("Expect", "100-continue"),) + self.assertSequenceEqual(self.handler.headers.items(), headers) def test_with_continue_1_1(self): result = self.send_typical_request(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n') @@ -645,6 +661,12 @@ self.verify_expected_headers(result[2:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + self.assertEqual(self.handler.command, 'GET') + self.assertEqual(self.handler.path, '/') + self.assertEqual(self.handler.request_version, 'HTTP/1.1') + headers = (("Expect", "100-continue"),) + self.assertSequenceEqual(self.handler.headers.items(), headers) def test_header_buffering_of_send_error(self): @@ -730,6 +752,7 @@ result = self.send_typical_request(b'GET ' + b'x' * 65537) self.assertEqual(result[0], b'HTTP/1.1 414 Request-URI Too Long\r\n') self.assertFalse(self.handler.get_called) + self.assertIsInstance(self.handler.requestline, str) def test_header_length(self): # Issue #6791: same for headers @@ -737,6 +760,22 @@ b'GET / HTTP/1.1\r\nX-Foo: bar' + b'r' * 65537 + b'\r\n\r\n') self.assertEqual(result[0], b'HTTP/1.1 400 Line too long\r\n') self.assertFalse(self.handler.get_called) + self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1') + + def test_close_connection(self): + # handle_one_request() should be repeatedly called until + # it sets close_connection + def handle_one_request(): + self.handler.close_connection = next(close_values) + self.handler.handle_one_request = handle_one_request + + close_values = iter((True,)) + self.handler.handle() + self.assertRaises(StopIteration, next, close_values) + + close_values = iter((False, False, True)) + self.handler.handle() + self.assertRaises(StopIteration, next, close_values) class SimpleHTTPRequestHandlerTestCase(unittest.TestCase): """ Test url parsing """ @@ -760,6 +799,19 @@ self.assertEqual(path, self.translated) +class MiscTestCase(unittest.TestCase): + def test_all(self): + expected = [] + blacklist = {'executable', 'nobody_uid', 'test'} + for name in dir(server): + if name.startswith('_') or name in blacklist: + continue + module_object = getattr(server, name) + if getattr(module_object, '__module__', None) == 'http.server': + expected.append(name) + self.assertCountEqual(server.__all__, expected) + + def test_main(verbose=None): cwd = os.getcwd() try: @@ -769,6 +821,7 @@ SimpleHTTPServerTestCase, CGIHTTPServerTestCase, SimpleHTTPRequestHandlerTestCase, + MiscTestCase, ) finally: os.chdir(cwd) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -593,13 +593,44 @@ with self.open(zero, "r") as f: self.assertRaises(OverflowError, f.read) - def test_flush_error_on_close(self): - f = self.open(support.TESTFN, "wb", buffering=0) + def check_flush_error_on_close(self, *args, **kwargs): + # Test that the file is closed despite failed flush + # and that flush() is called before file closed. + f = self.open(*args, **kwargs) + closed = [] def bad_flush(): + closed[:] = [f.closed] raise OSError() f.flush = bad_flush self.assertRaises(OSError, f.close) # exception not swallowed self.assertTrue(f.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + f.flush = lambda: None # break reference loop + + def test_flush_error_on_close(self): + # raw file + # Issue #5700: io.FileIO calls flush() after file closed + self.check_flush_error_on_close(support.TESTFN, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0, closefd=False) + os.close(fd) + # buffered io + self.check_flush_error_on_close(support.TESTFN, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', closefd=False) + os.close(fd) + # text io + self.check_flush_error_on_close(support.TESTFN, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w', closefd=False) + os.close(fd) def test_multi_close(self): f = self.open(support.TESTFN, "wb", buffering=0) @@ -788,13 +819,22 @@ self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname) def test_flush_error_on_close(self): + # Test that buffered file is closed despite failed flush + # and that flush() is called before file closed. raw = self.MockRawIO() + closed = [] def bad_flush(): + closed[:] = [b.closed, raw.closed] raise OSError() raw.flush = bad_flush b = self.tp(raw) self.assertRaises(OSError, b.close) # exception not swallowed self.assertTrue(b.closed) + self.assertTrue(raw.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) + raw.flush = lambda: None # break reference loop def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2618,12 +2658,21 @@ self.assertEqual(content.count("Thread%03d\n" % n), 1) def test_flush_error_on_close(self): + # Test that text file is closed despite failed flush + # and that flush() is called before file closed. txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + closed = [] def bad_flush(): + closed[:] = [txt.closed, txt.buffer.closed] raise OSError() txt.flush = bad_flush self.assertRaises(OSError, txt.close) # exception not swallowed self.assertTrue(txt.closed) + self.assertTrue(txt.buffer.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) + txt.flush = lambda: None # break reference loop def test_close_error_on_close(self): buffer = self.BytesIO(self.testdata) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -511,7 +511,7 @@ self.skipTest('test needs Turkish locale') loc = locale.getlocale(locale.LC_CTYPE) if verbose: - print('got locale %a' % (loc,)) + print('testing with %a' % (loc,), end=' ', flush=True) locale.setlocale(locale.LC_CTYPE, loc) self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE)) diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -44,6 +44,13 @@ self.assertRaises(IndexError, dec, b'apple\x92ham\x93spam', 'test.cjktest') + def test_errorcallback_custom_ignore(self): + # Issue #23215: MemoryError with custom error handlers and multibyte codecs + data = 100 * "\udc00" + codecs.register_error("test.ignore", codecs.ignore_errors) + for enc in ALL_CJKENCODINGS: + self.assertEqual(data.encode(enc, "test.ignore"), b'') + def test_codingspec(self): try: for enc in ALL_CJKENCODINGS: diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -105,31 +105,35 @@ check = self._check_parse_parts # First part is anchored check(['c:'], ('c:', '', ['c:'])) - check(['c:\\'], ('c:', '\\', ['c:\\'])) - check(['\\'], ('', '\\', ['\\'])) + check(['c:/'], ('c:', '\\', ['c:\\'])) + check(['/'], ('', '\\', ['\\'])) check(['c:a'], ('c:', '', ['c:', 'a'])) - check(['c:\\a'], ('c:', '\\', ['c:\\', 'a'])) - check(['\\a'], ('', '\\', ['\\', 'a'])) + check(['c:/a'], ('c:', '\\', ['c:\\', 'a'])) + check(['/a'], ('', '\\', ['\\', 'a'])) # UNC paths - check(['\\\\a\\b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['\\\\a\\b\\'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['\\\\a\\b\\c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) + check(['//a/b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['//a/b/'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['//a/b/c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) # Second part is anchored, so that the first part is ignored check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c'])) - check(['a', 'Z:\\b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) - check(['a', '\\b', 'c'], ('', '\\', ['\\', 'b', 'c'])) + check(['a', 'Z:/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) # UNC paths - check(['a', '\\\\b\\c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + check(['a', '//b/c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) # Collapsing and stripping excess slashes - check(['a', 'Z:\\\\b\\\\c\\', 'd\\'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) + check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) # UNC paths - check(['a', '\\\\b\\c\\\\', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + check(['a', '//b/c//', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) # Extended paths - check(['\\\\?\\c:\\'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) - check(['\\\\?\\c:\\a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) + check(['//?/c:/'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) + check(['//?/c:/a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) + check(['//?/c:/a', '/b'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b'])) # Extended UNC paths (format is "\\?\UNC\server\share") - check(['\\\\?\\UNC\\b\\c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) - check(['\\\\?\\UNC\\b\\c\\d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) + check(['//?/UNC/b/c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) + check(['//?/UNC/b/c/d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) + # Second part has a root but not drive + check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c'])) + check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) + check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c'])) def test_splitroot(self): f = self.flavour.splitroot diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -3,12 +3,15 @@ import builtins import contextlib import difflib +import importlib.util import inspect import pydoc +import py_compile import keyword import _pickle import pkgutil import re +import stat import string import test.support import time @@ -32,6 +35,10 @@ except ImportError: threading = None +class nonascii: + '?? ?? ????????' + pass + if test.support.HAVE_DOCSTRINGS: expected_data_docstrings = ( 'dictionary for instance variables (if defined)', @@ -471,6 +478,11 @@ self.assertEqual(expected, result, "documentation for missing module found") + def test_not_ascii(self): + result = run_pydoc('test.test_pydoc.nonascii', PYTHONIOENCODING='ascii') + encoded = nonascii.__doc__.encode('ascii', 'backslashreplace') + self.assertIn(encoded, result) + def test_input_strip(self): missing_module = " test.i_am_not_here " result = str(run_pydoc(missing_module), 'ascii') @@ -557,6 +569,18 @@ self.assertEqual(synopsis, expected) + def test_synopsis_sourceless_empty_doc(self): + with test.support.temp_cwd() as test_dir: + init_path = os.path.join(test_dir, 'foomod42.py') + cached_path = importlib.util.cache_from_source(init_path) + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + py_compile.compile(init_path) + synopsis = pydoc.synopsis(init_path, {}) + self.assertIsNone(synopsis) + synopsis_cached = pydoc.synopsis(cached_path, {}) + self.assertIsNone(synopsis_cached) + def test_splitdoc_with_description(self): example_string = "I Am A Doc\n\n\nHere is my description" self.assertEqual(pydoc.splitdoc(example_string), @@ -612,6 +636,7 @@ def setUp(self): self.test_dir = os.mkdir(TESTFN) self.addCleanup(rmtree, TESTFN) + importlib.invalidate_caches() def test_badimport(self): # This tests the fix for issue 5230, where if pydoc found the module @@ -670,6 +695,22 @@ self.assertEqual(out.getvalue(), '') self.assertEqual(err.getvalue(), '') + def test_apropos_empty_doc(self): + pkgdir = os.path.join(TESTFN, 'walkpkg') + os.mkdir(pkgdir) + self.addCleanup(rmtree, pkgdir) + init_path = os.path.join(pkgdir, '__init__.py') + with open(init_path, 'w') as fobj: + fobj.write("foo = 1") + current_mode = stat.S_IMODE(os.stat(pkgdir).st_mode) + try: + os.chmod(pkgdir, current_mode & ~stat.S_IEXEC) + with self.restrict_walk_packages(path=[TESTFN]), captured_stdout() as stdout: + pydoc.apropos('') + self.assertIn('walkpkg', stdout.getvalue()) + finally: + os.chmod(pkgdir, current_mode) + @unittest.skip('causes undesireable side-effects (#20128)') def test_modules(self): # See Helper.listmodules(). diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -557,7 +557,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_non_consuming(self): + def test_lookahead(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -571,6 +571,37 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") + # Group reference. + self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) + self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) + # Named group reference. + self.assertTrue(re.match(r'(?Pa)b(?=(?P=g))a', 'aba')) + self.assertIsNone(re.match(r'(?Pa)b(?=(?P=g))c', 'abac')) + # Conditional group reference. + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match(r'(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) + self.assertTrue(re.match(r'(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) + # Group used before defined. + self.assertTrue(re.match(r'(a)b(?=(?(2)x|c))(c)', 'abc')) + self.assertIsNone(re.match(r'(a)b(?=(?(2)b|x))(c)', 'abc')) + self.assertTrue(re.match(r'(a)b(?=(?(1)c|x))(c)', 'abc')) + + def test_lookbehind(self): + self.assertTrue(re.match(r'ab(?<=b)c', 'abc')) + self.assertIsNone(re.match(r'ab(?<=c)c', 'abc')) + self.assertIsNone(re.match(r'ab(?a)a(?<=(?P=g))c') + # Conditional group reference. + self.assertWarns(RuntimeWarning, re.compile, r'(a)b(?<=(?(1)b|x))c') + # Group used before defined. + self.assertWarns(RuntimeWarning, re.compile, r'(a)b(?<=(?(2)b|x))(c)') + def test_ignore_case(self): self.assertEqual(re.match("abc", "ABC", re.I).group(0), "ABC") self.assertEqual(re.match(b"abc", b"ABC", re.I).group(0), b"ABC") diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -9,7 +9,6 @@ import math import random import sys -import types import unittest from decimal import Decimal diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1922,7 +1922,7 @@ open_fds = set(fds) # add a bunch more fds for _ in range(9): - fd = os.open("/dev/null", os.O_RDONLY) + fd = os.open(os.devnull, os.O_RDONLY) self.addCleanup(os.close, fd) open_fds.add(fd) @@ -1984,7 +1984,7 @@ open_fds = set() # Add a bunch more fds to pass down. for _ in range(40): - fd = os.open("/dev/null", os.O_RDONLY) + fd = os.open(os.devnull, os.O_RDONLY) open_fds.add(fd) # Leave a two pairs of low ones available for use by the diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1994,6 +1994,21 @@ finally: support.unlink(tar_name) + def test_create_command_compressed(self): + files = [support.findfile('tokenize_tests.txt'), + support.findfile('tokenize_tests-no-coding-cookie-' + 'and-utf8-bom-sig-only.txt')] + for filetype in (GzipTest, Bz2Test, LzmaTest): + if not filetype.open: + continue + try: + tar_name = tmpname + '.' + filetype.suffix + out = self.tarfilecmd('-c', tar_name, *files) + with filetype.taropen(tar_name) as tar: + tar.getmembers() + finally: + support.unlink(tar_name) + def test_extract_command(self): self.make_simple_tarfile(tmpname) for opt in '-e', '--extract': diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -648,7 +648,14 @@ if name + 'o' not in namelist: self.assertIn(name + 'c', namelist) + def requiresWriteAccess(self, path): + # effective_ids unavailable on windows + if not os.access(path, os.W_OK, + effective_ids=os.access in os.supports_effective_ids): + self.skipTest('requires write access to the installed location') + def test_write_pyfile(self): + self.requiresWriteAccess(os.path.dirname(__file__)) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): @@ -680,6 +687,7 @@ def test_write_python_package(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: zipfp.writepy(packagedir) @@ -693,6 +701,7 @@ def test_write_filtered_python_package(self): import test packagedir = os.path.dirname(test.__file__) + self.requiresWriteAccess(packagedir) with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: @@ -721,6 +730,7 @@ def test_write_with_optimization(self): import email packagedir = os.path.dirname(email.__file__) + self.requiresWriteAccess(packagedir) # use .pyc if running test in optimization mode, # use .pyo if running test in debug mode optlevel = 1 if __debug__ else 0 diff --git a/Lib/turtle.py b/Lib/turtle.py --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -1288,7 +1288,7 @@ def _incrementudc(self): """Increment update counter.""" if not TurtleScreen._RUNNING: - TurtleScreen._RUNNNING = True + TurtleScreen._RUNNING = True raise Terminator if self._tracing > 0: self._updatecounter += 1 @@ -3754,7 +3754,7 @@ Turtle._screen = None _Screen._root = None _Screen._canvas = None - TurtleScreen._RUNNING = True + TurtleScreen._RUNNING = False root.destroy() def bye(self): @@ -3795,7 +3795,6 @@ except AttributeError: exit(0) - class Turtle(RawTurtle): """RawTurtle auto-creating (scrolled) canvas. @@ -3818,18 +3817,6 @@ Pen = Turtle -def _getpen(): - """Create the 'anonymous' turtle if not already present.""" - if Turtle._pen is None: - Turtle._pen = Turtle() - return Turtle._pen - -def _getscreen(): - """Create a TurtleScreen if not already present.""" - if Turtle._screen is None: - Turtle._screen = Screen() - return Turtle._screen - def write_docstringdict(filename="turtle_docstringdict"): """Create and write docstring-dictionary to file. @@ -3952,26 +3939,38 @@ ## as functions. So we can enhance, change, add, delete methods to these ## classes and do not need to change anything here. - -for methodname in _tg_screen_functions: - pl1, pl2 = getmethparlist(eval('_Screen.' + methodname)) - if pl1 == "": - print(">>>>>>", pl1, pl2) - continue - defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec(defstr) - eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__) - -for methodname in _tg_turtle_functions: - pl1, pl2 = getmethparlist(eval('Turtle.' + methodname)) - if pl1 == "": - print(">>>>>>", pl1, pl2) - continue - defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" % - {'key':methodname, 'pl1':pl1, 'pl2':pl2}) - exec(defstr) - eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__) +__func_body = """\ +def {name}{paramslist}: + if {obj} is None: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + {obj} = {init} + try: + return {obj}.{name}{argslist} + except TK.TclError: + if not TurtleScreen._RUNNING: + TurtleScreen._RUNNING = True + raise Terminator + raise +""" + +def _make_global_funcs(functions, cls, obj, init, docrevise): + for methodname in functions: + method = getattr(cls, methodname) + pl1, pl2 = getmethparlist(method) + if pl1 == "": + print(">>>>>>", pl1, pl2) + continue + defstr = __func_body.format(obj=obj, init=init, name=methodname, + paramslist=pl1, argslist=pl2) + exec(defstr, globals()) + globals()[methodname].__doc__ = docrevise(method.__doc__) + +_make_global_funcs(_tg_screen_functions, _Screen, + 'Turtle._screen', 'Screen()', _screen_docrevise) +_make_global_funcs(_tg_turtle_functions, Turtle, + 'Turtle._pen', 'Turtle()', _turtle_docrevise) done = mainloop diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -344,6 +344,8 @@ else: self.state = DONE except turtle.Terminator: + if self.root is None: + return self.state = DONE result = "stopped!" if self.state == DONE: @@ -369,7 +371,9 @@ turtle.TurtleScreen._RUNNING = False def _destroy(self): + turtle.TurtleScreen._RUNNING = False self.root.destroy() + self.root = None def main(): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -506,6 +506,7 @@ Dag Gruneau Filip Gruszczy?ski Thomas Guettler +Yuyang Guo Anuj Gupta Michael Guravage Lars Gust?bel diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,44 @@ Library ------- +- Issue #6639: Module-level turtle functions no longer raise TclError after + closing the window. + +- Issues #814253, #9179: Warnings now are raised when group references and + conditional group references are used in lookbehind assertions in regular + expressions. + +- Issue #23215: Multibyte codecs with custom error handlers that ignores errors + consumed too much memory and raised SystemError or MemoryError. + Original patch by Aleksi Torhamo. + +- Issue #5700: io.FileIO() called flush() after closing the file. + flush() was not called in close() if closefd=False. + +- Issue #23374: Fixed pydoc failure with non-ASCII files when stdout encoding + differs from file system encoding (e.g. on Mac OS). + +- Issue #23481: Remove RC4 from the SSL module's default cipher list. + +- Issue #21548: Fix pydoc.synopsis() and pydoc.apropos() on modules with empty + docstrings. + +- Issue #22885: Fixed arbitrary code execution vulnerability in the dbm.dumb + module. Original patch by Claudiu Popa. + +- Issue #23146: Fix mishandling of absolute Windows paths with forward + slashes in pathlib. + +- Issue #23421: Fixed compression in tarfile CLI. Patch by wdv4758h. + +- Issue #23361: Fix possible overflow in Windows subprocess creation code. + +Build +----- + +- Issue #23445: pydebug builds now use "gcc -Og" where possible, to make + the resulting executable faster. + What's New in Python 3.4.3? =========================== diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -21,7 +21,6 @@ README.AIX Information about using Python on AIX README.coverity Information about running Coverity's Prevent on Python README.valgrind Information for Valgrind users, see valgrind-python.supp -RPM (Old) tools to build RPMs SpecialBuilds.txt Describes extra symbols you can set for debug builds svnmap.txt Map of old SVN revs and branches to hg changeset ids valgrind-python.supp Valgrind suppression file, see README.valgrind diff --git a/Misc/RPM/README b/Misc/RPM/README deleted file mode 100644 --- a/Misc/RPM/README +++ /dev/null @@ -1,33 +0,0 @@ -This directory contains support file used to build RPM releases of -Python. Its contents are maintained by Sean Reifschneider -. - -If you wish to build RPMs from the base Python release tar-file, note -that you will have to download the -"doc//html-.tar.bz2" -file from python.org and place it into your "SOURCES" directory for -the build to complete. This is the same directory that you place the -Python-2.3.1 release tar-file in. You can then use the ".spec" file in -this directory to build RPMs. - -You may also wish to pursue RPMs provided by distribution makers to see if -they have one suitable for your uses. If, for example, you just want a -slightly newer version of Python than what the distro provides, you could -pick up the closest SRPM your distro provides, and then modify it to -the newer version, and build that. It may be as simple as just changing -the "version" information in the spec file (or it may require fixing -patches). - -NOTE: I am *NOT* recommending just using the binary RPM, and never do an -install with "--force" or "--nodeps". - -Also worth pursuing may be newer versions provided by similar distros. For -example, a Python 3 SRPM from Fedora may be a good baseline to try building -on CentOS. - -Many newer SRPMs won't install on older distros because of format changes. -You can manually extract these SRPMS with: - - mkdir foo - cd foo - rpm2cpio <../python3-*.src.rpm | cpio -ivd diff --git a/Misc/RPM/python-3.4.spec b/Misc/RPM/python-3.4.spec deleted file mode 100644 --- a/Misc/RPM/python-3.4.spec +++ /dev/null @@ -1,389 +0,0 @@ -########################## -# User-modifiable configs -########################## - -# Is the resulting package and the installed binary named "python" or -# "python2"? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_binsuffix none -%define config_binsuffix 2.6 - -# Build tkinter? "auto" enables it if /usr/bin/wish exists. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_tkinter no -%define config_tkinter yes -%define config_tkinter auto - -# Use pymalloc? The last line (commented or not) determines wether -# pymalloc is used. -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_pymalloc no -%define config_pymalloc yes - -# Enable IPV6? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_ipv6 yes -%define config_ipv6 no - -# Build shared libraries or .a library? -#WARNING: Commenting out doesn't work. Last line is what's used. -%define config_sharedlib no -%define config_sharedlib yes - -# Location of the HTML directory. -%define config_htmldir /var/www/html/python - -################################# -# End of user-modifiable configs -################################# - -%define name python -#--start constants-- -%define version 3.4.3 -%define libvers 3.4 -#--end constants-- -%define release 1pydotorg -%define __prefix /usr - -# kludge to get around rpm define weirdness -%define ipv6 %(if [ "%{config_ipv6}" = yes ]; then echo --enable-ipv6; else echo --disable-ipv6; fi) -%define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) -%define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) -%define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) -%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) -%define sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo --enable-shared; else echo ; fi) -%define include_sharedlib %(if [ "%{config_sharedlib}" = yes ]; then echo 1; else echo 0; fi) - -# detect if documentation is available -%define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) - -Summary: An interpreted, interactive, object-oriented programming language. -Name: %{name}%{binsuffix} -Version: %{version} -Release: %{release} -License: PSF -Group: Development/Languages -Source: Python-%{version}.tar.bz2 -%if %{include_docs} -Source1: html-%{version}.tar.bz2 -%endif -BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildPrereq: expat-devel -BuildPrereq: db4-devel -BuildPrereq: gdbm-devel -BuildPrereq: sqlite-devel -Prefix: %{__prefix} -Packager: Sean Reifschneider - -%description -Python is an interpreted, interactive, object-oriented programming -language. It incorporates modules, exceptions, dynamic typing, very high -level dynamic data types, and classes. Python combines remarkable power -with very clear syntax. It has interfaces to many system calls and -libraries, as well as to various window systems, and is extensible in C or -C++. It is also usable as an extension language for applications that need -a programmable interface. Finally, Python is portable: it runs on many -brands of UNIX, on PCs under Windows, MS-DOS, and on the Mac. - -%package devel -Summary: The libraries and header files needed for Python extension development. -Prereq: python%{binsuffix} = %{PACKAGE_VERSION} -Group: Development/Libraries - -%description devel -The Python programming language's interpreter can be extended with -dynamically loaded extensions and can be embedded in other programs. -This package contains the header files and libraries needed to do -these types of tasks. - -Install python-devel if you want to develop Python extensions. The -python package will also need to be installed. You'll probably also -want to install the python-docs package, which contains Python -documentation. - -%if %{include_tkinter} -%package tkinter -Summary: A graphical user interface for the Python scripting language. -Group: Development/Languages -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tkinter -The Tkinter (Tk interface) program is an graphical user interface for -the Python scripting language. - -You should install the tkinter package if you'd like to use a graphical -user interface for Python programming. -%endif - -%package tools -Summary: A collection of development tools included with Python. -Group: Development/Tools -Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} - -%description tools -The Python package includes several development tools that are used -to build python programs. This package contains a selection of those -tools, including the IDLE Python IDE. - -Install python-tools if you want to use these tools to develop -Python programs. You will also need to install the python and -tkinter packages. - -%if %{include_docs} -%package docs -Summary: Python-related documentation. -Group: Development/Documentation - -%description docs -Documentation relating to the Python programming language in HTML and info -formats. -%endif - -%changelog -* Mon Dec 20 2004 Sean Reifschneider [2.4-2pydotorg] -- Changing the idle wrapper so that it passes arguments to idle. - -* Tue Oct 19 2004 Sean Reifschneider [2.4b1-1pydotorg] -- Updating to 2.4. - -* Thu Jul 22 2004 Sean Reifschneider [2.3.4-3pydotorg] -- Paul Tiemann fixes for %{prefix}. -- Adding permission changes for directory as suggested by reimeika.ca -- Adding code to detect when it should be using lib64. -- Adding a define for the location of /var/www/html for docs. - -* Thu May 27 2004 Sean Reifschneider [2.3.4-2pydotorg] -- Including changes from Ian Holsman to build under Red Hat 7.3. -- Fixing some problems with the /usr/local path change. - -* Sat Mar 27 2004 Sean Reifschneider [2.3.2-3pydotorg] -- Being more agressive about finding the paths to fix for - #!/usr/local/bin/python. - -* Sat Feb 07 2004 Sean Reifschneider [2.3.3-2pydotorg] -- Adding code to remove "#!/usr/local/bin/python" from particular files and - causing the RPM build to terminate if there are any unexpected files - which have that line in them. - -* Mon Oct 13 2003 Sean Reifschneider [2.3.2-1pydotorg] -- Adding code to detect wether documentation is available to build. - -* Fri Sep 19 2003 Sean Reifschneider [2.3.1-1pydotorg] -- Updating to the 2.3.1 release. - -* Mon Feb 24 2003 Sean Reifschneider [2.3b1-1pydotorg] -- Updating to 2.3b1 release. - -* Mon Feb 17 2003 Sean Reifschneider [2.3a1-1] -- Updating to 2.3 release. - -* Sun Dec 23 2001 Sean Reifschneider -[Release 2.2-2] -- Added -docs package. -- Added "auto" config_tkinter setting which only enables tk if - /usr/bin/wish exists. - -* Sat Dec 22 2001 Sean Reifschneider -[Release 2.2-1] -- Updated to 2.2. -- Changed the extension to "2" from "2.2". - -* Tue Nov 18 2001 Sean Reifschneider -[Release 2.2c1-1] -- Updated to 2.2c1. - -* Thu Nov 1 2001 Sean Reifschneider -[Release 2.2b1-3] -- Changed the way the sed for fixing the #! in pydoc works. - -* Wed Oct 24 2001 Sean Reifschneider -[Release 2.2b1-2] -- Fixed missing "email" package, thanks to anonymous report on sourceforge. -- Fixed missing "compiler" package. - -* Mon Oct 22 2001 Sean Reifschneider -[Release 2.2b1-1] -- Updated to 2.2b1. - -* Mon Oct 9 2001 Sean Reifschneider -[Release 2.2a4-4] -- otto at balinor.mat.unimi.it mentioned that the license file is missing. - -* Sun Sep 30 2001 Sean Reifschneider -[Release 2.2a4-3] -- Ignacio Vazquez-Abrams pointed out that I had a spruious double-quote in - the spec files. Thanks. - -* Wed Jul 25 2001 Sean Reifschneider -[Release 2.2a1-1] -- Updated to 2.2a1 release. -- Changed idle and pydoc to use binsuffix macro - -####### -# PREP -####### -%prep -%setup -n Python-%{version} - -######## -# BUILD -######## -%build -echo "Setting for ipv6: %{ipv6}" -echo "Setting for pymalloc: %{pymalloc}" -echo "Setting for binsuffix: %{binsuffix}" -echo "Setting for include_tkinter: %{include_tkinter}" -echo "Setting for libdirname: %{libdirname}" -echo "Setting for sharedlib: %{sharedlib}" -echo "Setting for include_sharedlib: %{include_sharedlib}" -./configure --enable-unicode=ucs4 %{sharedlib} %{ipv6} %{pymalloc} --prefix=%{__prefix} -make - -########## -# INSTALL -########## -%install -# set the install path -echo '[install_scripts]' >setup.cfg -echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg - -[ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload -make prefix=$RPM_BUILD_ROOT%{__prefix} install - -# REPLACE PATH IN PYDOC -if [ ! -z "%{binsuffix}" ] -then - ( - cd $RPM_BUILD_ROOT%{__prefix}/bin - mv pydoc pydoc.old - sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ - pydoc.old >pydoc - chmod 755 pydoc - rm -f pydoc.old - ) -fi - -# add the binsuffix -if [ ! -z "%{binsuffix}" ] -then - rm -f $RPM_BUILD_ROOT%{__prefix}/bin/python[0-9a-zA-Z]* - ( cd $RPM_BUILD_ROOT%{__prefix}/bin; - for file in *; do mv "$file" "$file"%{binsuffix}; done ) - ( cd $RPM_BUILD_ROOT%{_mandir}/man1; mv python.1 python%{binsuffix}.1 ) -fi - -######## -# Tools -echo '#!%{__prefix}/bin/env python%{binsuffix}' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'import os, sys' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'os.execvp("%{__prefix}/bin/python%{binsuffix}", ["%{__prefix}/bin/python%{binsuffix}", "%{__prefix}/lib/python%{libvers}/idlelib/idle.py"] + sys.argv[1:])' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'print "Failed to exec Idle"' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -echo 'sys.exit(1)' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} -chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} -cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} - -# MAKE FILE LISTS -rm -f mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers} -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/python%{libvers}/config$' -e '_tkinter.so$' >mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f -o -type l | - sed "s|^${RPM_BUILD_ROOT}|/|" | - grep -v -e '/bin/2to3%{binsuffix}$' | - grep -v -e '/bin/pydoc%{binsuffix}$' | - grep -v -e '/bin/smtpd.py%{binsuffix}$' | - grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files - -rm -f tools.files -find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ - "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | - sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files -echo "%{__prefix}"/bin/2to3%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/pydoc%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/smtpd.py%{binsuffix} >>tools.files -echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files - -###### -# Docs -%if %{include_docs} -mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} -( - cd "$RPM_BUILD_ROOT"%{config_htmldir} - bunzip2 < %{SOURCE1} | tar x -) -%endif - -# fix the #! line in installed files -find "$RPM_BUILD_ROOT" -type f -print0 | - xargs -0 grep -l /usr/local/bin/python | while read file -do - FIXFILE="$file" - sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ - "$FIXFILE" >/tmp/fix-python-path.$$ - cat /tmp/fix-python-path.$$ >"$FIXFILE" - rm -f /tmp/fix-python-path.$$ -done - -# check to see if there are any straggling #! lines -find "$RPM_BUILD_ROOT" -type f | xargs egrep -n '^#! */usr/local/bin/python' \ - | grep ':1:#!' >/tmp/python-rpm-files.$$ || true -if [ -s /tmp/python-rpm-files.$$ ] -then - echo '*****************************************************' - cat /tmp/python-rpm-files.$$ - cat <<@EOF - ***************************************************** - There are still files referencing /usr/local/bin/python in the - install directory. They are listed above. Please fix the .spec - file and try again. If you are an end-user, you probably want - to report this to jafo-rpms at tummy.com as well. - ***************************************************** - at EOF - rm -f /tmp/python-rpm-files.$$ - exit 1 -fi -rm -f /tmp/python-rpm-files.$$ - -######## -# CLEAN -######## -%clean -[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT -rm -f mainpkg.files tools.files - -######## -# FILES -######## -%files -f mainpkg.files -%defattr(-,root,root) -%doc Misc/README Misc/cheatsheet Misc/Porting -%doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS -%{_mandir}/man1/python%{binsuffix}.1* - -%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} -%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ -%if %{include_sharedlib} -%{__prefix}/%{libdirname}/libpython* -%endif - -%files devel -%defattr(-,root,root) -%{__prefix}/include/python%{libvers}/*.h -%{__prefix}/%{libdirname}/python%{libvers}/config - -%files -f tools.files tools -%defattr(-,root,root) - -%if %{include_tkinter} -%files tkinter -%defattr(-,root,root) -%{__prefix}/%{libdirname}/python%{libvers}/tkinter -%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* -%endif - -%if %{include_docs} -%files docs -%defattr(-,root,root) -%{config_htmldir}/* -%endif diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4305,8 +4305,11 @@ slicelen); } - dest = (wchar_t *)PyMem_Malloc( - slicelen * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, slicelen); + if (dest == NULL) { + PyErr_NoMemory(); + return NULL; + } for (cur = start, i = 0; i < slicelen; cur += step, i++) { @@ -4986,7 +4989,7 @@ return PyUnicode_FromWideChar(ptr + start, len); } - dest = (wchar_t *)PyMem_Malloc(len * sizeof(wchar_t)); + dest = PyMem_New(wchar_t, len); if (dest == NULL) return PyErr_NoMemory(); for (cur = start, i = 0; i < len; cur += step, i++) { diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -76,14 +76,18 @@ if (src->format) { dst->format = PyMem_Malloc(strlen(src->format) + 1); - if (dst->format == NULL) + if (dst->format == NULL) { + PyErr_NoMemory(); return -1; + } strcpy(dst->format, src->format); } if (src->shape) { dst->shape = PyMem_Malloc(sizeof(Py_ssize_t) * src->ndim); - if (dst->shape == NULL) + if (dst->shape == NULL) { + PyErr_NoMemory(); return -1; + } memcpy(dst->shape, src->shape, sizeof(Py_ssize_t) * src->ndim); } @@ -380,7 +384,7 @@ union_size = 0; total_align = align ? align : 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, basedict->length + len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; @@ -398,7 +402,7 @@ union_size = 0; total_align = 1; stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; - stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); + stgdict->ffi_type_pointer.elements = PyMem_New(ffi_type *, len + 1); if (stgdict->ffi_type_pointer.elements == NULL) { PyErr_NoMemory(); return -1; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -126,11 +126,18 @@ static PyObject * fileio_close(fileio *self) { + PyObject *res; + PyObject *exc, *val, *tb; + int rc; _Py_IDENTIFIER(close); + res = _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_close, "O", self); if (!self->closefd) { self->fd = -1; - Py_RETURN_NONE; + return res; } + if (res == NULL) + PyErr_Fetch(&exc, &val, &tb); if (self->finalizing) { PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); if (r) @@ -138,12 +145,12 @@ else PyErr_Clear(); } - errno = internal_close(self); - if (errno < 0) - return NULL; - - return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, - &PyId_close, "O", self); + rc = internal_close(self); + if (res == NULL) + _PyErr_ChainExceptions(exc, val, tb); + if (rc < 0) + Py_CLEAR(res); + return res; } static PyObject * diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -254,7 +254,7 @@ /* assume no change in size, first */ n1 = n1 + 1; - buf = PyMem_Malloc(n1 * sizeof(wchar_t)); + buf = PyMem_New(wchar_t, n1); if (!buf) { PyErr_NoMemory(); goto exit; diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3838,10 +3838,11 @@ if (_ssl_locks == NULL) { _ssl_locks_count = CRYPTO_num_locks(); - _ssl_locks = (PyThread_type_lock *) - PyMem_Malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); - if (_ssl_locks == NULL) + _ssl_locks = PyMem_New(PyThread_type_lock, _ssl_locks_count); + if (_ssl_locks == NULL) { + PyErr_NoMemory(); return 0; + } memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); for (i = 0; i < _ssl_locks_count; i++) { diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -850,7 +850,7 @@ Py_ssize_t *dest; Py_ssize_t x, i; - dest = PyMem_Malloc(len * (sizeof *dest)); + dest = PyMem_New(Py_ssize_t, len); if (dest == NULL) { PyErr_NoMemory(); return NULL; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1516,7 +1516,7 @@ if (!PyArg_ParseTuple(args, "Un", &unicode, &buflen)) return NULL; - buffer = PyMem_Malloc(buflen * sizeof(wchar_t)); + buffer = PyMem_New(wchar_t, buflen); if (buffer == NULL) return PyErr_NoMemory(); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -34,7 +34,7 @@ #endif #define CHECK_SIZE(size, elemsize) \ - ((size_t)(size) <= Py_MAX((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) + ((size_t)(size) <= Py_MIN((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, making _tkinter correct for this API means to break earlier diff --git a/Modules/_winapi.c b/Modules/_winapi.c --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -535,13 +535,23 @@ "environment can only contain strings"); goto error; } + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ + if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(value) - 1) { + PyErr_SetString(PyExc_OverflowError, "environment too long"); + goto error; + } totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ } - buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4)); - if (! buffer) + buffer = PyMem_NEW(Py_UCS4, totalsize); + if (! buffer) { + PyErr_NoMemory(); goto error; + } p = buffer; end = buffer + totalsize; diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -228,13 +228,13 @@ if (PyObject_GetBuffer(arg, buf, PyBUF_SIMPLE) != 0) { PyErr_Format(PyExc_TypeError, "argument should be bytes, buffer or ASCII string, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); return 0; } if (!PyBuffer_IsContiguous(buf, 'C')) { PyErr_Format(PyExc_TypeError, "argument should be a contiguous buffer, " - "not %R", Py_TYPE(arg)); + "not '%.100s'", Py_TYPE(arg)->tp_name); PyBuffer_Release(buf); return 0; } diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -182,8 +182,10 @@ orgsize = PyBytes_GET_SIZE(buf->outobj); incsize = (esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize); - if (orgsize > PY_SSIZE_T_MAX - incsize) + if (orgsize > PY_SSIZE_T_MAX - incsize) { + PyErr_NoMemory(); return -1; + } if (_PyBytes_Resize(&buf->outobj, orgsize + incsize) == -1) return -1; @@ -194,11 +196,11 @@ return 0; } -#define REQUIRE_ENCODEBUFFER(buf, s) { \ - if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ +#define REQUIRE_ENCODEBUFFER(buf, s) do { \ + if ((s) < 0 || (s) > (buf)->outbuf_end - (buf)->outbuf) \ if (expand_encodebuffer(buf, s) == -1) \ goto errorexit; \ -} +} while(0) /** @@ -332,10 +334,11 @@ assert(PyBytes_Check(retstr)); retstrsize = PyBytes_GET_SIZE(retstr); - REQUIRE_ENCODEBUFFER(buf, retstrsize); - - memcpy(buf->outbuf, PyBytes_AS_STRING(retstr), retstrsize); - buf->outbuf += retstrsize; + if (retstrsize > 0) { + REQUIRE_ENCODEBUFFER(buf, retstrsize); + memcpy(buf->outbuf, PyBytes_AS_STRING(retstr), retstrsize); + buf->outbuf += retstrsize; + } newpos = PyLong_AsSsize_t(PyTuple_GET_ITEM(retobj, 1)); if (newpos < 0 && !PyErr_Occurred()) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -911,12 +911,12 @@ } #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) -static void* -stack_overflow(void *min_sp, void *max_sp, size_t *depth) +static Py_uintptr_t +stack_overflow(Py_uintptr_t min_sp, Py_uintptr_t max_sp, size_t *depth) { /* allocate 4096 bytes on the stack at each call */ unsigned char buffer[4096]; - void *sp = &buffer; + Py_uintptr_t sp = (Py_uintptr_t)&buffer; *depth += 1; if (sp < min_sp || max_sp < sp) return sp; @@ -929,7 +929,8 @@ faulthandler_stack_overflow(PyObject *self) { size_t depth, size; - char *sp = (char *)&depth, *stop; + Py_uintptr_t sp = (Py_uintptr_t)&depth; + Py_uintptr_t stop; depth = 0; stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE, diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -735,7 +735,7 @@ bufsz += wcslen(zip_path) + 1; bufsz += wcslen(exec_prefix) + 1; - buf = (wchar_t *)PyMem_Malloc(bufsz * sizeof(wchar_t)); + buf = PyMem_New(wchar_t, bufsz); if (buf == NULL) { Py_FatalError( "Not enough memory for dynamic PYTHONPATH"); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1638,7 +1638,7 @@ if(!buf_size) return FALSE; - buf = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); + buf = PyMem_New(wchar_t, buf_size+1); if (!buf) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -3627,7 +3627,7 @@ len = wcslen(path->wide); } /* The +5 is so we can append "\\*.*\0" */ - wnamebuf = PyMem_Malloc((len + 5) * sizeof(wchar_t)); + wnamebuf = PyMem_New(wchar_t, len + 5); if (!wnamebuf) { PyErr_NoMemory(); goto exit; @@ -3917,7 +3917,7 @@ Py_ARRAY_LENGTH(woutbuf), woutbuf, &wtemp); if (result > Py_ARRAY_LENGTH(woutbuf)) { - woutbufp = PyMem_Malloc(result * sizeof(wchar_t)); + woutbufp = PyMem_New(wchar_t, result); if (!woutbufp) return PyErr_NoMemory(); result = GetFullPathNameW(wpath, result, woutbufp, &wtemp); @@ -3997,7 +3997,7 @@ if(!buf_size) return win32_error_object("GetFinalPathNameByHandle", po); - target_path = (wchar_t *)PyMem_Malloc((buf_size+1)*sizeof(wchar_t)); + target_path = PyMem_New(wchar_t, buf_size+1); if(!target_path) return PyErr_NoMemory(); @@ -4082,7 +4082,7 @@ return NULL; } - mountpath = (wchar_t *)PyMem_Malloc(buflen * sizeof(wchar_t)); + mountpath = PyMem_New(wchar_t, buflen); if (mountpath == NULL) return PyErr_NoMemory(); @@ -6213,9 +6213,9 @@ #endif #ifdef __APPLE__ - groups = PyMem_Malloc(ngroups * sizeof(int)); -#else - groups = PyMem_Malloc(ngroups * sizeof(gid_t)); + groups = PyMem_New(int, ngroups); +#else + groups = PyMem_New(gid_t, ngroups); #endif if (groups == NULL) return PyErr_NoMemory(); @@ -6293,7 +6293,7 @@ /* groups will fit in existing array */ alt_grouplist = grouplist; } else { - alt_grouplist = PyMem_Malloc(n * sizeof(gid_t)); + alt_grouplist = PyMem_New(gid_t, n); if (alt_grouplist == NULL) { errno = EINVAL; return posix_error(); @@ -6319,7 +6319,7 @@ /* Avoid malloc(0) */ alt_grouplist = grouplist; } else { - alt_grouplist = PyMem_Malloc(n * sizeof(gid_t)); + alt_grouplist = PyMem_New(gid_t, n); if (alt_grouplist == NULL) { errno = EINVAL; return posix_error(); diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -928,7 +928,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - new_parser->handlers = PyMem_Malloc(sizeof(PyObject *) * i); + new_parser->handlers = PyMem_New(PyObject *, i); if (!new_parser->handlers) { Py_DECREF(new_parser); return PyErr_NoMemory(); @@ -1121,7 +1121,7 @@ for (i = 0; handler_info[i].name != NULL; i++) /* do nothing */; - self->handlers = PyMem_Malloc(sizeof(PyObject *) * i); + self->handlers = PyMem_New(PyObject *, i); if (!self->handlers) { Py_DECREF(self); return PyErr_NoMemory(); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4126,9 +4126,11 @@ /* MSDN says ERROR_MORE_DATA may occur because DNS allows longer names */ - name = PyMem_Malloc(size * sizeof(wchar_t)); - if (!name) + name = PyMem_New(wchar_t, size); + if (!name) { + PyErr_NoMemory(); return NULL; + } if (!GetComputerNameExW(ComputerNamePhysicalDnsHostname, name, &size)) diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -556,7 +556,7 @@ /* Overallocate at most 10 characters. */ space = (isize > 10 ? 10 : isize) + isize; osize = space; - output = PyMem_Malloc(space * sizeof(Py_UCS4)); + output = PyMem_New(Py_UCS4, space); if (!output) { PyErr_NoMemory(); return NULL; @@ -703,7 +703,7 @@ /* We allocate a buffer for the output. If we find that we made no changes, we still return the NFD result. */ - output = PyMem_Malloc(len * sizeof(Py_UCS4)); + output = PyMem_New(Py_UCS4, len); if (!output) { PyErr_NoMemory(); Py_DECREF(result); diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -233,7 +233,7 @@ Py_ssize_t len; len = PyUnicode_GET_LENGTH(prefix) + PyUnicode_GET_LENGTH(name) + 1; - p = buf = PyMem_Malloc(sizeof(Py_UCS4) * len); + p = buf = PyMem_New(Py_UCS4, len); if (buf == NULL) { PyErr_NoMemory(); return NULL; diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1832,7 +1832,8 @@ assert(ms); while (ms->n > 1) { Py_ssize_t n = ms->n - 2; - if (n > 0 && p[n-1].len <= p[n].len + p[n+1].len) { + if ((n > 0 && p[n-1].len <= p[n].len + p[n+1].len) || + (n > 1 && p[n-2].len <= p[n-1].len + p[n].len)) { if (p[n-1].len < p[n+1].len) --n; if (merge_at(ms, n) < 0) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1535,6 +1535,10 @@ /* in case the native representation is 2-bytes, we need to allocate a new normalized 4-byte version. */ length_wo_surrogates = _PyUnicode_WSTR_LENGTH(unicode) - num_surrogates; + if (length_wo_surrogates > PY_SSIZE_T_MAX / 4 - 1) { + PyErr_NoMemory(); + return -1; + } _PyUnicode_DATA_ANY(unicode) = PyObject_MALLOC(4 * (length_wo_surrogates + 1)); if (!_PyUnicode_DATA_ANY(unicode)) { PyErr_NoMemory(); @@ -2186,7 +2190,7 @@ } switch (kind) { case PyUnicode_2BYTE_KIND: - result = PyMem_Malloc(len * sizeof(Py_UCS2)); + result = PyMem_New(Py_UCS2, len); if (!result) return PyErr_NoMemory(); assert(skind == PyUnicode_1BYTE_KIND); @@ -2197,7 +2201,7 @@ result); return result; case PyUnicode_4BYTE_KIND: - result = PyMem_Malloc(len * sizeof(Py_UCS4)); + result = PyMem_New(Py_UCS4, len); if (!result) return PyErr_NoMemory(); if (skind == PyUnicode_2BYTE_KIND) { @@ -2239,11 +2243,7 @@ if (copy_null) targetlen++; if (!target) { - if (PY_SSIZE_T_MAX / sizeof(Py_UCS4) < targetlen) { - PyErr_NoMemory(); - return NULL; - } - target = PyMem_Malloc(targetlen * sizeof(Py_UCS4)); + target = PyMem_New(Py_UCS4, targetlen); if (!target) { PyErr_NoMemory(); return NULL; @@ -2852,12 +2852,7 @@ buflen = unicode_aswidechar(unicode, NULL, 0); if (buflen == -1) return NULL; - if (PY_SSIZE_T_MAX / sizeof(wchar_t) < buflen) { - PyErr_NoMemory(); - return NULL; - } - - buffer = PyMem_MALLOC(buflen * sizeof(wchar_t)); + buffer = PyMem_NEW(wchar_t, buflen); if (buffer == NULL) { PyErr_NoMemory(); return NULL; @@ -3550,10 +3545,7 @@ wstr = smallbuf; } else { - if (wlen > PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) - return PyErr_NoMemory(); - - wstr = PyMem_Malloc((wlen+1) * sizeof(wchar_t)); + wstr = PyMem_New(wchar_t, wlen+1); if (!wstr) return PyErr_NoMemory(); } @@ -3858,6 +3850,11 @@ #endif } else { + if ((size_t)_PyUnicode_LENGTH(unicode) > + PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) { + PyErr_NoMemory(); + return NULL; + } _PyUnicode_WSTR(unicode) = (wchar_t *) PyObject_MALLOC(sizeof(wchar_t) * (_PyUnicode_LENGTH(unicode) + 1)); if (!_PyUnicode_WSTR(unicode)) { diff --git a/PC/winreg.c b/PC/winreg.c --- a/PC/winreg.c +++ b/PC/winreg.c @@ -939,7 +939,7 @@ wchar_t *data = (wchar_t *)retDataBuf; int len = retDataSize / 2; int s = countStrings(data, len); - wchar_t **str = (wchar_t **)PyMem_Malloc(sizeof(wchar_t *)*s); + wchar_t **str = PyMem_New(wchar_t *, s); if (str == NULL) return PyErr_NoMemory(); @@ -1206,7 +1206,7 @@ ++retDataSize; bufDataSize = retDataSize; bufValueSize = retValueSize; - retValueBuf = (wchar_t *)PyMem_Malloc(sizeof(wchar_t) * retValueSize); + retValueBuf = PyMem_New(wchar_t, retValueSize); if (retValueBuf == NULL) return PyErr_NoMemory(); retDataBuf = (BYTE *)PyMem_Malloc(retDataSize); @@ -1277,7 +1277,7 @@ return PyErr_SetFromWindowsErrWithFunction(retValueSize, "ExpandEnvironmentStrings"); } - retValue = (wchar_t *)PyMem_Malloc(retValueSize * sizeof(wchar_t)); + retValue = PyMem_New(wchar_t, retValueSize); if (retValue == NULL) { return PyErr_NoMemory(); } diff --git a/Python/frozenmain.c b/Python/frozenmain.c --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -24,11 +24,13 @@ /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2 = NULL; - argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - goto error; + if (argc > 0) { + argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + goto error; + } } Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ @@ -68,7 +70,8 @@ #ifdef MS_WINDOWS PyInitFrozenExtensions(); #endif /* MS_WINDOWS */ - Py_SetProgramName(argv_copy[0]); + if (argc >= 1) + Py_SetProgramName(argv_copy[0]); Py_Initialize(); #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -290,7 +290,7 @@ static unsigned int * markblocks(unsigned char *code, Py_ssize_t len) { - unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int)); + unsigned int *blocks = PyMem_New(unsigned int, len); int i,j, opcode, blockcnt = 0; if (blocks == NULL) { @@ -398,7 +398,7 @@ goto exitUnchanged; /* Mapping to new jump targets after NOPs are removed */ - addrmap = (int *)PyMem_Malloc(codelen * sizeof(int)); + addrmap = PyMem_New(int, codelen); if (addrmap == NULL) { PyErr_NoMemory(); goto exitError; diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6283,7 +6283,11 @@ if test "$Py_DEBUG" = 'true' ; then # Optimization messes up debuggers, so turn it off for # debug builds. - OPT="-g -O0 -Wall $STRICT_PROTO" + if "$CC" -v --help 2>/dev/null |grep -- -Og > /dev/null; then + OPT="-g -Og -Wall $STRICT_PROTO" + else + OPT="-g -O0 -Wall $STRICT_PROTO" + fi else OPT="-g $WRAP -O3 -Wall $STRICT_PROTO" fi diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1119,7 +1119,11 @@ if test "$Py_DEBUG" = 'true' ; then # Optimization messes up debuggers, so turn it off for # debug builds. - OPT="-g -O0 -Wall $STRICT_PROTO" + if "$CC" -v --help 2>/dev/null |grep -- -Og > /dev/null; then + OPT="-g -Og -Wall $STRICT_PROTO" + else + OPT="-g -O0 -Wall $STRICT_PROTO" + fi else OPT="-g $WRAP -O3 -Wall $STRICT_PROTO" fi -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Feb 26 15:01:09 2015 From: python-checkins at python.org (larry.hastings) Date: Thu, 26 Feb 2015 14:01:09 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_final_release_date_for?= =?utf-8?q?_=28slightly_slipped=29_Python_3=2E4=2E3=2E?= Message-ID: <20150226140104.87101.73880@psf.io> https://hg.python.org/peps/rev/de5f2f496d69 changeset: 5708:de5f2f496d69 user: Larry Hastings date: Thu Feb 26 06:01:00 2015 -0800 summary: Update final release date for (slightly slipped) Python 3.4.3. files: pep-0101.txt | 4 ++-- pep-0429.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt --- a/pep-0101.txt +++ b/pep-0101.txt @@ -351,8 +351,8 @@ You should not see any files. I.e. you better not have any uncommitted changes in your working directory. - ___ Make sure you have virtualenv installed. The release script installs - Sphinx in a virtualenv when building the docs. + ___ Make sure you have virtualenv installed (for Python 2.7). The release + script installs Sphinx in a virtualenv when building the docs. For building the PDF docs, you also need a fairly complete installation of a recent TeX distribution such as texlive. diff --git a/pep-0429.txt b/pep-0429.txt --- a/pep-0429.txt +++ b/pep-0429.txt @@ -66,7 +66,7 @@ -------------- - 3.4.3 candidate 1: February 8, 2015 -- 3.4.3 final: February 22, 2015 +- 3.4.3 final: February 25, 2015 -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Feb 26 18:36:59 2015 From: python-checkins at python.org (chris.angelico) Date: Thu, 26 Feb 2015 17:36:59 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Apply_PEP_441_changes_from_Pa?= =?utf-8?q?ul_Moore?= Message-ID: <20150226173652.6728.1940@psf.io> https://hg.python.org/peps/rev/a7f743bfd565 changeset: 5709:a7f743bfd565 user: Chris Angelico date: Fri Feb 27 04:36:44 2015 +1100 summary: Apply PEP 441 changes from Paul Moore files: pep-0441.txt | 130 ++++++++++++++++++++++++++++---------- 1 files changed, 94 insertions(+), 36 deletions(-) diff --git a/pep-0441.txt b/pep-0441.txt --- a/pep-0441.txt +++ b/pep-0441.txt @@ -73,6 +73,7 @@ standard and is how self-extracting ZIP archives and the bdist_wininst installer format work. + Minimal Tooling: The zipapp Module ================================== @@ -82,47 +83,75 @@ -m zipapp``) for their creation and manipulation. More complete tools for managing Python Zip Applications are -encouraged as 3rd party applications on PyPI. Currently, pyyzer [5]_ -and pex [6]_ are two tools known to exist. +encouraged as 3rd party applications on PyPI. Currently, pyzzer [5]_ +and pex [6]_ are two such tools. Module Interface ---------------- The zipapp module will provide the following functions: -``pack(directory, target=None, interpreter=None, main=None)`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``create_archive(source, target=None, interpreter=None, main=None)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Writes an application archive called *target*, containing the contents -of *directory*. The *target* can be a filename, or a file-like object -(which must be open for writing in bytes mode), or None (which means -use the name of *directory* with ``.pyz`` appended). If *interpreter* -is specified, it will be written to the start of the archive as a -shebang line and the file will be made executable (if no interpreter -is specified, the shebang line will be omitted). If the directory -contains no ``__main__.py`` file, the function will construct a -``__main__.py`` which calls the function specified in the *main* -argument (which should be in the form ``'pkg.mod:fn'``). +Create an application archive from *source*. The source can be any +of the following: -It is an error to specify *main* if the directory contains a -``__main__.py``, or to omit *main* when there is no ``__main__.py`` -(as that will result in an archive which has no main function and so -cannot be executed). +* The name of a directory, in which case a new application archive + will be created from the content of that directory. +* The name of an existing application archive file, in which case the + file is copied to the target. The file name should include the + ``.pyz`` extension, if required. +* A file object open for reading in bytes mode. The content of the + file should be an application archive, and the file object is + assumed to be positioned at the start of the archive. + +The *target* argument determines where the resulting archive will be +written: + +* If it is the name of a file, the archive will be written to that + file. +* If it is an open file object, the archive will be written to that + file object, which must be open for writing in bytes mode. +* If the target is omitted (or None), the source must be a directory + and the target will be a file with the same name as the source, with + a ``.pyz`` extension added. + +The *interpreter* argument specifies the name of the Python +interpreter with which the archive will be executed. It is written as +a "shebang" line at the start of the archive. On Unix, this will be +interpreted by the OS, and on Windows it will be handled by the Python +launcher. Omitting the *interpreter* results in no shebang line being +written. If an interpreter is specified, and the target is a +filename, the executable bit of the target file will be set. + +The *main* argument specifies the name of a callable which will be +used as the main program for the archive. It can only be specified if +the source is a directory, and the source does not already contain a +``__main__.py`` file. The *main* argument should take the form +"pkg.module:callable" and the archive will be run by importing +"pkg.module" and executing the given callable with no arguments. It +is an error to omit *main* if the source is a directory and does not +contain a ``__main__.py`` file, as otherwise the resulting archive +would not be executable. + +If a file object is specified for *source* or *target*, it is the +caller's responsibility to close it after calling create_archive. + +When copying an existing archive, file objects supplied only need +``read`` and ``readline``, or ``write`` methods. When creating an +archive from a directory, if the target is a file object it will be +passed to the ``zipfile.ZipFile`` class, and must supply the methods +needed by that class. ``get_interpreter(archive)`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Returns the interpreter specified in the shebang line of the *archive*. -If there is no shebang, the function returns ``None``. +Returns the interpreter specified in the shebang line of the +*archive*. If there is no shebang, the function returns ``None``. +The *archive* argument can be a filename or a file-like object open +for reading in bytes mode. -``set_interpreter(archive, new_archive, interpreter=None)`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Modifies the *archive*'s shebang line to contain the specified -interpreter, and writes the updated archive to *new_archive*. If the -*interpreter* is ``None``, removes the shebang line. The -*new_archive* argument can be a filename, or a file-like object open -for writing in byte mode. Command Line Usage ------------------ @@ -130,22 +159,25 @@ The zipapp module can be run with the python ``-m`` flag. The command line interface is as follows:: - python -m zipapp [options] directory + python -m zipapp directory [options] - Create an archive from the contents of the given directory. By - default, an archive will be created with the same name as the - source directory, with a .pyz extension. + Create an archive from the given directory. An archive will + be created from the contents of that directory. The archive + will have the same name as the source directory with a .pyz + extension. The following options can be specified: -o archive / --output archive - The destination archive will have the specified name. + The destination archive will have the specified name. The + given name will be used as written, so should include the + ".pyz" extension. -p interpreter / --python interpreter The given interpreter will be written to the shebang line - of the archive. If this option is not given, the archive + of the archive. If this option is not given, the archive will have no shebang line. -m pkg.mod:fn / --main pkg.mod:fn @@ -155,10 +187,36 @@ which calls fn from the module pkg.mod. The behaviour of the command line interface matches that of -``zipapp.pack()``. +``zipapp.create_archive()``. + +In addition, it is possible to use the command line interface to work +with an existing archive:: + + python -m zipapp app.pyz --show + + Displays the shebang line of an archive. Output is of the + form + + Interpreter: /usr/bin/env + or + Interpreter: + + and is intended for diagnostic use, not for scripts. + + python -m zipapp app.pyz -o newapp.pyz [-p interpreter] + + Copy app.pyz to newapp.pyz, modifying the shebang line based + on the -p option (as for creating an archive, no -p option + means remove the shebang line). Specifying a destination is + mandatory. + + In-place modification of an archive is *not* supported, as the + risk of damaging archives is too great for a simple tool. As noted, the archives are standard zip files, and so can be unpacked -using any standard ZIP utility or Python's zipfile module. +using any standard ZIP utility or Python's zipfile module. For this +reason, no interfaces to list the contents of an archive, or unpack +them, are provided or needed. FAQ --- -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Feb 26 21:18:02 2015 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 26 Feb 2015 20:18:02 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_to_PEP_448_--_approved?= =?utf-8?q?_2_out_of_3=2C_rejected_*comprehension=2E?= Message-ID: <20150226201752.6736.32077@psf.io> https://hg.python.org/peps/rev/bf59e2ae3b3c changeset: 5710:bf59e2ae3b3c user: Guido van Rossum date: Thu Feb 26 12:17:47 2015 -0800 summary: Update to PEP 448 -- approved 2 out of 3, rejected *comprehension. files: pep-0448.txt | 115 ++++++++++++++++++++++---------------- 1 files changed, 65 insertions(+), 50 deletions(-) diff --git a/pep-0448.txt b/pep-0448.txt --- a/pep-0448.txt +++ b/pep-0448.txt @@ -4,11 +4,11 @@ Last-Modified: $Date$ Author: Joshua Landau Discussions-To: python-ideas at python.org -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 29-Jun-2013 -Python-Version: 3.4 +Python-Version: 3.5 Post-History: @@ -50,15 +50,9 @@ >>> {**{'x': 2}, 'x': 1} {'x': 1} -Unpacking is proposed to be allowed inside list, set, -and dictionary comprehensions:: - - >>> ranges = [range(i) for i in range(5)] - >>> [*item for item in ranges] - [0, 0, 1, 0, 1, 2, 0, 1, 2, 3] - - >>> {*item for item in ranges} - {0, 1, 2, 3} +This PEP does not include unpacking operators inside list, set and +dictionary comprehensions although this has not been ruled out for +future proposals. Rationale @@ -121,14 +115,6 @@ *my_tuple, *my_range]``. -The addition of unpacking to comprehensions is a logical extension. -It's usage will primarily be a neat replacement for ``[i for j in -list_of_lists for i in j]``, as the more readable -``[*l for l in list_of_lists]``. The iterable version, -``(*l for l in list_of_lists)``, replaces ``itertools.chain.from_iterable``. -Other uses are possible, but expected to occur rarely. - - Specification ============= @@ -145,7 +131,8 @@ positional argument given both positionally and by keyword ? a ``TypeError`` is raised. This remains true for duplicate arguments provided through multiple ``**`` unpackings, -e.g. ``f(**{'x': 2}, **{'x': 3})``. +e.g. ``f(**{'x': 2}, **{'x': 3})``, except that the error will be +detected at runtime. A function looks like this:: @@ -159,40 +146,17 @@ act as if the elements from unpacked items were inserted in order at the site of unpacking, much as happens in unpacking in a function-call. Dictionaries require ``**`` unpacking; all the others require ``*`` unpacking. -A dictionary's key remain in a right-to-left priority order, so + +The keys in a dictionary remain in a right-to-left priority order, so ``{**{'a': 1}, 'a': 2, **{'a': 3}}`` evaluates to ``{'a': 3}``. There is no restriction on the number or position of unpackings. -Comprehensions, by simple extension, will support unpacking. As before, -dictionaries require ``**`` unpacking, all the others require ``*`` -unpacking and key priorities are unchanged. - -For example:: - - {*[1, 2, 3], 4, 5, *{6, 7, 8}} - - (*e for e in [[1], [3, 4, 5], [2]]) - - {**dictionary for dictionary in (globals(), locals())} - - {**locals(), "override": None} - -Unbracketed comprehensions in function calls, such as ``f(x for x in it)``, -are already valid. These could be extended to:: - - f(*x for x in it) == f((*x for x in it)) - f(**x for x in it) == f({**x for x in it}) - -However, this is likely to be confusing and is not included in this -PEP. These will throw ``SyntaxError`` and comprehensions with explicit -brackets should be used instead. - Disadvantages ============= The allowable orders for arguments in a function call are more -complicated than before. The simplest explanation for the rules +complicated than before. The simplest explanation for the rules may be "positional arguments precede keyword arguments and ``**`` unpacking; ``*`` unpacking precedes ``**`` unpacking". @@ -200,24 +164,75 @@ ``elements = *iterable,`` causes ``elements`` to be a tuple. The reason for this may confuse people unfamiliar with the construct. +Concerns have been raised about the unexpected difference between +duplicate keys in dictionaries being allowed but duplicate keys +in function call syntax raising an error. Although this is already +the case with current syntax, this proposal might exacerbate the +issue. It remains to be seen how much of an issue this is in practice. + + +Variations +========== + +The PEP originally considered whether the ordering of argument types +in a function call (positional, keyword, ``*`` or ``**``) could become +less strict. This met little support so the idea was shelved. + +Earlier iterations of this PEP allowed unpacking operators inside +list, set, and dictionary comprehensions as a flattening operator +over iterables of containers:: + + >>> ranges = [range(i) for i in range(5)] + >>> [*item for item in ranges] + [0, 0, 1, 0, 1, 2, 0, 1, 2, 3] + + >>> {*item for item in ranges} + {0, 1, 2, 3} + +This was met with a mix of strong concerns about readability and mild +support. In order not to disadvantage the less controversial aspects +of the PEP, this was not accepted with the rest of the proposal. + +Unbracketed comprehensions in function calls, such as ``f(x for x in it)``, +are already valid. These could be extended to:: + + f(*x for x in it) == f((*x for x in it)) + f(**x for x in it) == f({**x for x in it}) + +However, it wasn't clear if this was the best behaviour or if it should +unpack into the arguments of the call to `f`. Since this is likely to be +confusing and is of only very marginal utility, it is not included in this +PEP. Instead, these will throw a ``SyntaxError`` and comprehensions with +explicit brackets should be used instead. + + +Approval +======== + +This PEP was accepted by Guido on February 25, 2015 [1]_. + Implementation ============== -An implementation for Python 3.5 is found at Issue 2292 on bug tracker [1]_. +An implementation for Python 3.5 is found at Issue 2292 on bug tracker [2]_. +This currently includes support for unpacking inside comprehensions, which +should be removed. References ========== -.. [1] Issue 2292, "Missing `*`-unpacking generalizations", Thomas Wouters +.. [1] PEP accepted, "PEP 448 review", Guido van Rossum + (https://mail.python.org/pipermail/python-dev/2015-February/138564.html) + +.. [2] Issue 2292, "Missing `*`-unpacking generalizations", Thomas Wouters (http://bugs.python.org/issue2292) -.. [2] Discussion on Python-ideas list, +.. [3] Discussion on Python-ideas list, "list / array comprehensions extension", Alexander Heger (http://mail.python.org/pipermail/python-ideas/2011-December/013097.html) - Copyright ========= -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Feb 26 23:19:23 2015 From: python-checkins at python.org (chris.angelico) Date: Thu, 26 Feb 2015 22:19:23 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Record_acceptances_of_PEPs_44?= =?utf-8?q?1_and_486=2C_including_trivial_fixes_for_each?= Message-ID: <20150226221922.53141.21152@psf.io> https://hg.python.org/peps/rev/1d3f1e41c8b8 changeset: 5711:1d3f1e41c8b8 user: Chris Angelico date: Fri Feb 27 09:19:06 2015 +1100 summary: Record acceptances of PEPs 441 and 486, including trivial fixes for each courtesy of Paul Moore files: pep-0441.txt | 7 ++++--- pep-0486.txt | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pep-0441.txt b/pep-0441.txt --- a/pep-0441.txt +++ b/pep-0441.txt @@ -5,11 +5,12 @@ Author: Daniel Holth , Paul Moore Discussions-To: https://mail.python.org/pipermail/python-dev/2015-February/138277.html -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 30 March 2013 Post-History: 30 March 2013, 1 April 2013, 16 February 2015 +Resolution: https://mail.python.org/pipermail/python-dev/2015-February/138578.html Improving Python ZIP Application Support ======================================== @@ -101,7 +102,7 @@ will be created from the content of that directory. * The name of an existing application archive file, in which case the file is copied to the target. The file name should include the - ``.pyz`` extension, if required. + ``.pyz`` or ``.pyzw`` extension, if required. * A file object open for reading in bytes mode. The content of the file should be an application archive, and the file object is assumed to be positioned at the start of the archive. @@ -172,7 +173,7 @@ The destination archive will have the specified name. The given name will be used as written, so should include the - ".pyz" extension. + ".pyz" or ".pyzw" extension. -p interpreter / --python interpreter diff --git a/pep-0486.txt b/pep-0486.txt --- a/pep-0486.txt +++ b/pep-0486.txt @@ -3,12 +3,13 @@ Version: $Revision$ Last-Modified: $Date$ Author: Paul Moore -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 12-Feb-2015 Python-Version: 3.5 -Post-History: +Post-History: 12-Feb-2015 +Resolution: https://mail.python.org/pipermail/python-dev/2015-February/138579.html Abstract @@ -51,7 +52,7 @@ python # Execute an installed module (these could use python -m, - # which is longer to type but is a little mopre similar to the + # which is longer to type but is a little more similar to the # launcher approach) pip install pytest py.test -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Feb 26 23:26:09 2015 From: python-checkins at python.org (steve.dower) Date: Thu, 26 Feb 2015 22:26:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2323465=3A_Implemen?= =?utf-8?q?t_PEP_486_-_Make_the_Python_Launcher_aware_of_virtual?= Message-ID: <20150226222609.14045.7506@psf.io> https://hg.python.org/cpython/rev/2eb99070a38f changeset: 94764:2eb99070a38f parent: 94756:7c6e3358221a user: Steve Dower date: Thu Feb 26 14:25:33 2015 -0800 summary: Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual environments (patch by Paul Moore) files: Doc/using/windows.rst | 20 ++++++++++++++ Doc/whatsnew/3.5.rst | 12 ++++++++ Misc/NEWS | 3 ++ PC/launcher.c | 42 ++++++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -404,6 +404,16 @@ Per-user installations of Python do not add the launcher to :envvar:`PATH` unless the option was selected on installation. +Virtual environments +^^^^^^^^^^^^^^^^^^^^ + +If the launcher is run with no explicit Python version specification, and a +virtual environment (created with the standard library :mod:`venv` module or +the external ``virtualenv`` tool) active, the launcher will run the virtual +environment's interpreter rather than the global one. To run the global +interpreter, either deactivate the virtual environment, or explicitly specify +the global Python version. + From a script ^^^^^^^^^^^^^ @@ -478,6 +488,16 @@ on Windows which you hope will be useful on Unix, you should use one of the shebang lines starting with ``/usr``. +Any of the above virtual commands can be suffixed with an explicit version +(either just the major version, or the major and minor version) - for example +``/usr/bin/python2.7`` - which will cause that specific version to be located +and used. + +The ``/usr/bin/env`` form of shebang line has one further special property. +Before looking for installed Python interpreters, this form will search the +executable :envvar:`PATH` for a Python executable. This corresponds to the +behaviour of the Unix ``env`` program, which performs a :envvar:`PATH` search. + Arguments in shebang lines -------------------------- diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -123,6 +123,18 @@ :pep:`475` -- Retry system calls failing with EINTR +PEP 486: Make the Python Launcher aware of virtual environments +--------------------------------------------------------------- + +:pep:`486` makes the Windows launcher (see :pep:`397`) aware of an active +virtual environment. When the default interpreter would be used and the +``VIRTUAL_ENV`` environment variable is set, the interpreter in the virtual +environment will be used. + +.. seealso:: + + :pep:`486` -- Make the Python Launcher aware of virtual environments + Other Language Changes ====================== diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,9 @@ Windows ------- +- Issue #23465: Implement PEP 486 - Make the Python Launcher aware of virtual + environments. Patch by Paul Moore. + - Issue #23437: Make user scripts directory versioned on Windows. Patch by Paul Moore. diff --git a/PC/launcher.c b/PC/launcher.c --- a/PC/launcher.c +++ b/PC/launcher.c @@ -384,6 +384,31 @@ } +static wchar_t * +find_python_by_venv() +{ + static wchar_t venv_python[MAX_PATH]; + wchar_t *virtual_env = get_env(L"VIRTUAL_ENV"); + DWORD attrs; + + /* Check for VIRTUAL_ENV environment variable */ + if (virtual_env == NULL || virtual_env[0] == L'\0') { + return NULL; + } + + /* Check for a python executable in the venv */ + debug(L"Checking for Python executable in virtual env '%ls'\n", virtual_env); + _snwprintf_s(venv_python, MAX_PATH, _TRUNCATE, + L"%ls\\Scripts\\%ls", virtual_env, PYTHON_EXECUTABLE); + attrs = GetFileAttributesW(venv_python); + if (attrs == INVALID_FILE_ATTRIBUTES) { + debug(L"Python executable %ls missing from virtual env\n", venv_python); + return NULL; + } + + return venv_python; +} + static wchar_t appdata_ini_path[MAX_PATH]; static wchar_t launcher_ini_path[MAX_PATH]; @@ -1309,6 +1334,7 @@ { wchar_t * wp; wchar_t * command; + wchar_t * executable; wchar_t * p; int rc = 0; size_t plen; @@ -1453,6 +1479,7 @@ if (ip == NULL) error(RC_NO_PYTHON, L"Requested Python version (%ls) not \ installed", &p[1]); + executable = ip->executable; command += wcslen(p); command = skip_whitespace(command); } @@ -1470,9 +1497,16 @@ #endif if (!valid) { - ip = locate_python(L""); - if (ip == NULL) - error(RC_NO_PYTHON, L"Can't find a default Python."); + /* Look for an active virtualenv */ + executable = find_python_by_venv(); + + /* If we didn't find one, look for the default Python */ + if (executable == NULL) { + ip = locate_python(L""); + if (ip == NULL) + error(RC_NO_PYTHON, L"Can't find a default Python."); + executable = ip->executable; + } if ((argc == 2) && (!_wcsicmp(p, L"-h") || !_wcsicmp(p, L"--help"))) { #if defined(_M_X64) BOOL canDo64bit = TRUE; @@ -1500,7 +1534,7 @@ fflush(stdout); } } - invoke_child(ip->executable, NULL, command); + invoke_child(executable, NULL, command); return rc; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 04:50:48 2015 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 27 Feb 2015 03:50:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_remove_duplica?= =?utf-8?q?te_3=2E4=2E3_tags?= Message-ID: <20150227035048.19168.12729@psf.io> https://hg.python.org/cpython/rev/ed27f53137ad changeset: 94765:ed27f53137ad branch: 3.4 parent: 94763:4ce53fdb6438 user: Benjamin Peterson date: Thu Feb 26 22:49:21 2015 -0500 summary: remove duplicate 3.4.3 tags files: .hgtags | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -143,6 +143,4 @@ 8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 -9b73f1c3e6012e556da7e2d40dd7a382d3726334 v3.4.3 -9b73f1c3e6012e556da7e2d40dd7a382d3726334 v3.4.3 b4cbecbc0781e89a309d03b60a1f75f8499250e6 v3.4.3 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 04:50:48 2015 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 27 Feb 2015 03:50:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20150227035048.15300.33978@psf.io> https://hg.python.org/cpython/rev/9b9887bd7734 changeset: 94766:9b9887bd7734 parent: 94764:2eb99070a38f parent: 94765:ed27f53137ad user: Benjamin Peterson date: Thu Feb 26 22:50:12 2015 -0500 summary: merge 3.4 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -143,4 +143,5 @@ 8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 +b4cbecbc0781e89a309d03b60a1f75f8499250e6 v3.4.3 5d4b6a57d5fd7564bf73f3db0e46fe5eeb00bcd8 v3.5.0a1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 04:50:51 2015 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 27 Feb 2015 03:50:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_unix_newlines?= Message-ID: <20150227035048.34510.74369@psf.io> https://hg.python.org/cpython/rev/dc55b5ce6b26 changeset: 94767:dc55b5ce6b26 user: Benjamin Peterson date: Thu Feb 26 22:50:43 2015 -0500 summary: unix newlines files: .hgtags | 292 ++++++++++++++++++++++---------------------- 1 files changed, 146 insertions(+), 146 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1,147 +1,147 @@ -64cc5439e10a6fdf984effaf0141e94fa4cc1004 v0.9.8 -78a7ed6953025e7ecdde9585099b01a6ae40b76a v0.9.9 -b15b8cc9b8d10e0352a0b8b7e8d51fa309db6df3 v1.0.1 -0326b5d61445ee3a8d3de28119f9652cb72d2e3f v1.0.2 -832615ec07646e310c85316b8ba6bc9b17ad3547 v1.1 -9895475d18c7b5f32adaf78f71886ae041e4d10c v1.1.1 -16eb4c51ee97169046340998e850a63c65225b0a v1.2b1 -b45c688756d04fb84d4a0d518fc3d7e3cb25fa8d v1.2b2 -9e82daf7605bad7976a9abc997cb5e0abe434078 v1.2b3 -065e31cf5862e27521cf5725b003aed211f091b2 v1.2b4 -e72257e655454d569468da8b1189e0ec336f3536 v1.2 -e63d83f8275853aaaa3d1972cb86564505e65583 v1.3b1 -7d743c865a9aa6bde8b603e32e0542031bba3c33 v1.3 -4fc85c82cc222554ae6b9c0b87776ed5f2b70c6e v1.4b1 -129f1299d4e97e884bbbbdd00baf101d178973e6 v1.4b2 -44a82ac654a4175569deed8e8a94b0cc8edee08d v1.4b3 -db49494c93dc73de06d5721c74eab533a947a92c v1.4 -062aed8a4ce2c91c81b80e29f02faff1cf5a761b v1.5a1 -c9498ac988372575cf7028b86395b900c9b0a840 v1.5a2 -dc5c968ec992aab3d40a7189df0c443d1c7a1a68 v1.5a3 -746654a0af680c7d9b814b210a026eb91bec9533 v1.5a4 -8ff58b5730f06be08fbbdc2bf592226f7a736201 v1.5b1 -eb78658d819fb0af09a8e6f9bedcb670805ed5f6 v1.5b2 -84461011a1a0ab402e352f06748f29fb5b5559e5 v1.5 -44aba4d26b01fbae0403efe654f9fd0347606732 v1.5.1 -fed63ccbe6dc3ac663bfe97a2f7006b1b28568f9 v1.5.2a1 -21d71f2e27248a0f4e393d0fc321ecf9b89321d2 v1.5.2a2 -f08c7a2a56f80741f5f192fd0ebe0b0967a203cf v1.5.2b1 -8fe7ec4b4fc1518fcac89e6bf674fbbce16150a9 v1.5.2b2 -39fb0dcc83dc375c1565ba65dbce0ed59b1359c9 v1.5.2c1 -61c91c7f101bab3149adfcd5646ae40e048de712 v1.5.2 -605eb9326ffe1fd1e43f40e2338d6652ab449fdf v1.6a1 -011bee8fd9f7f4da457ec71596484fb0882c0614 v1.6a2 -35c4fc1414a59888614b9be784a25f233ba67984 v2.0b1 -55bba197d4870cdae62aeca00e20240a756b84f8 v2.0b2 -e276329cce036a5f9e9d3451256dca5984e543dc v2.0c1 -2fa4e35083e02342ca014bf5bfba46aecb816c31 v2.0 -b60831eeab5a06dd3c5e8297a99e39297aa8794b v2.1a1 -b382f1f07ec6b2c95551658b30c6139eeb32077a v2.1a2 -d0c830db5e68edd4aaa3401216e610c9ff145826 v2.1b1 -b59a536ae1ef3774fd85c17f623e8926b7b6c095 v2.1b2 -d611276e9ad53b5d32d1e8065e1d811c32f7d96f v2.1c1 -ff065e674af6c9ab895bd9eff7d9e9039a376c7d v2.1c2 -020e95d8180d7943fe54701e1db0a7d7d87e2b1e v2.1 -08796a137f1ada2462f7a3177306df5f67a767e1 v2.2a3 -d054c29647f90bccb8345bd779bca1eecf2dd7f2 v2.3c1 -fce5c9e9abc722394cb2e909b7e2a39080d4448e v2.3c2 -92ca658fd420095b6284c9ce6e9082a80285ec9c v2.4a1 -055fc6955f3c6522bfeb7ed4c671c97d5baaaac2 v2.4a2 -186b72550e53533ef6175f6411f932c1298193d7 v2.4a3 -53cff04283855adf88ed0c0fd3698827ca843637 v2.4b1 -7e387a9dcc79954a77695adef8b593da35be1214 v2.4b2 -ff80d8bbef6e13426c8a85d7f9d837b8f8f89834 v2.4c1 -f31e18d313c7a4fc66914b2d27e130a0f72c0b69 v2.4 -cd3f783cd08a16781e236c0b9cb5717d1d995fa9 v3.0a1 -65e82140e281bf26f2e22eda05a7f9956c420f8b v3.0a2 -df15827f34881b9af0936350813ced5c123c8230 v3.0a3 -15f773f7300e372c56a21d59fe49ca26955a6477 v3.0a4 -e35935475153377d6727d64e6c52f72c3b84015b v3.0a5 -a335c4d643b1cfe14197a9ef195c9b2804f608fc v3.0b1 -16ec4bb14a68ea428acf09ebf0c92981da2646f3 v3.0b2 -509e30a7968e01be329ec121540b3e755fc4e566 v3.0b3 -507ede9c7f7f475dfafbd4a52c22d767d10a2bc0 v3.0rc1 -8fae465a39627b590385462e6095eb63af45240a v3.0rc2 -e83a60c69d53f5551a306e77a6d38e9b11485496 v3.0rc3 -bc1ce368986e45b1faf96f93995df46bcd75e7b8 v3.1a1 -ee430e5075db2adf8124e6b94916a89ca41d3171 v3.1a2 -b63020797f9678adaf4d2c3e26574a9eef2ef028 v3.1b1 -4353fd0843cb31b356adc50f93d220e2e7255ef2 v3.1rc1 -0b87e438e1b53e3f812cad963a7fdb65d198ba2f v3.1rc2 -a69a031ac1402dede8b1ef80096436bca6d371f3 v3.1 -35efb1054ec6ceca72017a587263cb6a9257340b v3.1.1rc1 -8b9c0f573ab29c41c6c5fdcca82a1fe0ff5355af v3.1.1 -149b8b87514d10416b598884db5f74651f625b38 v3.1.2rc1 -960efa327c5d9c18df995437b0ac550cb89c9f85 v3.1.2 -d18e9d71f369d8211f6ac87252c6d3211f9bd09f v3.1.3rc1 -a4f75773c0060cee38b0bb651a7aba6f56b0e996 v3.1.3 -32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1 -c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4 -ee26aca3219cf4bb0b93352e83edcc9cb28c7802 v3.1.5rc1 -75db2bc69fc9a3e4801e94e3e19801cb096208d8 v3.1.5rc2 -7395330e495ec3316862ca1f6ce0aaf7bdf6785b v3.1.5 -b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1 -56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2 -da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3 -d92a5b850f5e56808bedc01723906ed64c5e6e2e v3.2a4 -b635cea94195780c8716e236479af319bcc26253 v3.2b1 -e3af5f3a7904c0d5343ec9633ea66e7acfd23a66 v3.2b2 -865d5b24bf28ca41b536befc326407c03e74a4d5 v3.2rc1 -acf3e24dd0d0dfd1e20c907d696d3da965a8f56f v3.2rc2 -18c1f52896501c7ee13b038454a39acb45a87979 v3.2rc3 -a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 -8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 -cfa9364997c7f2e67b9cbb45c3a5fa3bba4e4999 v3.2.1rc1 -5df549718fb4841ff521fe051f6b54f290fad5d8 v3.2.1rc2 -ac1f7e5c05104d557d5acd922e95625ba5d1fe10 v3.2.1 -c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 -137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 -7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 -428f05cb7277e1d42bb9dd8d1af6b6270ebc6112 v3.2.3rc2 -3d0686d90f55a78f96d9403da2c52dc2411419d0 v3.2.3 -b2cb7bc1edb8493c0a78f9331eae3e8fba6a881d v3.2.4rc1 -1e10bdeabe3de02f038a63c001911561ac1d13a7 v3.2.4 -cef745775b6583446572cffad704100983db2bea v3.2.5 -51382a5598ec96119cb84594572901c9c964dc3c v3.2.6rc1 -0bd5f4f14de965ca8e44c6e3965fee106176cfc4 v3.2.6 -f1a9a6505731714f0e157453ff850e3b71615c45 v3.3.0a1 -2f69db52d6de306cdaef0a0cc00cc823fb350b01 v3.3.0a2 -0b53b70a40a00013505eb35e3660057b62be77be v3.3.0a3 -7c51388a3aa7ce76a8541bbbdfc05d2d259a162c v3.3.0a4 -e15c554cd43eb23bc0a528a4e8741da9bbec9607 v3.3.0b1 -4972a8f1b2aa3d7cdd64dc96aa7fa112fe1ea343 v3.3.0b2 -8bb5c7bc46ba43804480f3e328e1fa956672c885 v3.3.0rc1 -88a0792e8ba3e4916b24c7e7a522c277d326d66e v3.3.0rc2 -c191d21cefafb3832c45570e84854e309aa62eaa v3.3.0rc3 -bd8afb90ebf28ba4edc901d4a235f75e7bbc79fd v3.3.0 -92c2cfb924055ce68c4f78f836dcfe688437ceb8 v3.3.1rc1 -d9893d13c6289aa03d33559ec67f97dcbf5c9e3c v3.3.1 -d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2 -fd53c500f8b80f54f3ecedec9da2e8c7e52a6888 v3.3.3rc1 -d32442c0e60dfbd71234e807d3d1dedd227495a9 v3.3.3rc2 -c3896275c0f61b2510a6c7e6c458a750359a91b8 v3.3.3 -fa92f5f940c6c0d839d7f0611e4b717606504a3c v3.3.4rc1 -7ff62415e4263c432c8acf6e424224209211eadb v3.3.4 -9ec811df548ed154a9bf9815383a916d6df31b98 v3.3.5rc1 -ca5635efe090f78806188ac2758f9948596aa8b2 v3.3.5rc2 -62cf4e77f78564714e7ea3d4bf1479ca1fbd0758 v3.3.5 -51317c9786f54267975abf2e9c502e6aaaa4a249 v3.3.6rc1 -971fec30da1fc5bf2b9fb28e09812a5127014211 v3.3.6 -46535f65e7f3bcdcf176f36d34bc1fed719ffd2b v3.4.0a1 -9265a2168e2cb2a84785d8717792acc661e6b692 v3.4.0a2 -dd9cdf90a5073510877e9dd5112f8e6cf20d5e89 v3.4.0a3 -e245b0d7209bb6d0e19316e1e2af1aa9c2139104 v3.4.0a4 -3405dc9a6afaa0a06dd1f6f182ec5c998dce6f5f v3.4.0b1 -ba32913eb13ec545a46dd0ce18035b6c416f0d78 v3.4.0b2 -a97ce3ecc96af79bd2e1ac66ce48d9138e0ca749 v3.4.0b3 -5e088cea8660677969113741c1313d570d977e02 v3.4.0rc1 -a300712ed38c9a242b736c44e806caea25a6dc05 v3.4.0rc2 -8a81cdab3e9d521daaef989fade94b16455fc3b8 v3.4.0rc3 -04f714765c13824c3bc2835d7b008908862e083a v3.4.0 -c67a19e11a7191baf30f313bf55e2e0b6c6f574e v3.4.1rc1 -c0e311e010fcb5bae8d87ca22051cd0845ea0ca0 v3.4.1 -8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 -ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 -69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 +64cc5439e10a6fdf984effaf0141e94fa4cc1004 v0.9.8 +78a7ed6953025e7ecdde9585099b01a6ae40b76a v0.9.9 +b15b8cc9b8d10e0352a0b8b7e8d51fa309db6df3 v1.0.1 +0326b5d61445ee3a8d3de28119f9652cb72d2e3f v1.0.2 +832615ec07646e310c85316b8ba6bc9b17ad3547 v1.1 +9895475d18c7b5f32adaf78f71886ae041e4d10c v1.1.1 +16eb4c51ee97169046340998e850a63c65225b0a v1.2b1 +b45c688756d04fb84d4a0d518fc3d7e3cb25fa8d v1.2b2 +9e82daf7605bad7976a9abc997cb5e0abe434078 v1.2b3 +065e31cf5862e27521cf5725b003aed211f091b2 v1.2b4 +e72257e655454d569468da8b1189e0ec336f3536 v1.2 +e63d83f8275853aaaa3d1972cb86564505e65583 v1.3b1 +7d743c865a9aa6bde8b603e32e0542031bba3c33 v1.3 +4fc85c82cc222554ae6b9c0b87776ed5f2b70c6e v1.4b1 +129f1299d4e97e884bbbbdd00baf101d178973e6 v1.4b2 +44a82ac654a4175569deed8e8a94b0cc8edee08d v1.4b3 +db49494c93dc73de06d5721c74eab533a947a92c v1.4 +062aed8a4ce2c91c81b80e29f02faff1cf5a761b v1.5a1 +c9498ac988372575cf7028b86395b900c9b0a840 v1.5a2 +dc5c968ec992aab3d40a7189df0c443d1c7a1a68 v1.5a3 +746654a0af680c7d9b814b210a026eb91bec9533 v1.5a4 +8ff58b5730f06be08fbbdc2bf592226f7a736201 v1.5b1 +eb78658d819fb0af09a8e6f9bedcb670805ed5f6 v1.5b2 +84461011a1a0ab402e352f06748f29fb5b5559e5 v1.5 +44aba4d26b01fbae0403efe654f9fd0347606732 v1.5.1 +fed63ccbe6dc3ac663bfe97a2f7006b1b28568f9 v1.5.2a1 +21d71f2e27248a0f4e393d0fc321ecf9b89321d2 v1.5.2a2 +f08c7a2a56f80741f5f192fd0ebe0b0967a203cf v1.5.2b1 +8fe7ec4b4fc1518fcac89e6bf674fbbce16150a9 v1.5.2b2 +39fb0dcc83dc375c1565ba65dbce0ed59b1359c9 v1.5.2c1 +61c91c7f101bab3149adfcd5646ae40e048de712 v1.5.2 +605eb9326ffe1fd1e43f40e2338d6652ab449fdf v1.6a1 +011bee8fd9f7f4da457ec71596484fb0882c0614 v1.6a2 +35c4fc1414a59888614b9be784a25f233ba67984 v2.0b1 +55bba197d4870cdae62aeca00e20240a756b84f8 v2.0b2 +e276329cce036a5f9e9d3451256dca5984e543dc v2.0c1 +2fa4e35083e02342ca014bf5bfba46aecb816c31 v2.0 +b60831eeab5a06dd3c5e8297a99e39297aa8794b v2.1a1 +b382f1f07ec6b2c95551658b30c6139eeb32077a v2.1a2 +d0c830db5e68edd4aaa3401216e610c9ff145826 v2.1b1 +b59a536ae1ef3774fd85c17f623e8926b7b6c095 v2.1b2 +d611276e9ad53b5d32d1e8065e1d811c32f7d96f v2.1c1 +ff065e674af6c9ab895bd9eff7d9e9039a376c7d v2.1c2 +020e95d8180d7943fe54701e1db0a7d7d87e2b1e v2.1 +08796a137f1ada2462f7a3177306df5f67a767e1 v2.2a3 +d054c29647f90bccb8345bd779bca1eecf2dd7f2 v2.3c1 +fce5c9e9abc722394cb2e909b7e2a39080d4448e v2.3c2 +92ca658fd420095b6284c9ce6e9082a80285ec9c v2.4a1 +055fc6955f3c6522bfeb7ed4c671c97d5baaaac2 v2.4a2 +186b72550e53533ef6175f6411f932c1298193d7 v2.4a3 +53cff04283855adf88ed0c0fd3698827ca843637 v2.4b1 +7e387a9dcc79954a77695adef8b593da35be1214 v2.4b2 +ff80d8bbef6e13426c8a85d7f9d837b8f8f89834 v2.4c1 +f31e18d313c7a4fc66914b2d27e130a0f72c0b69 v2.4 +cd3f783cd08a16781e236c0b9cb5717d1d995fa9 v3.0a1 +65e82140e281bf26f2e22eda05a7f9956c420f8b v3.0a2 +df15827f34881b9af0936350813ced5c123c8230 v3.0a3 +15f773f7300e372c56a21d59fe49ca26955a6477 v3.0a4 +e35935475153377d6727d64e6c52f72c3b84015b v3.0a5 +a335c4d643b1cfe14197a9ef195c9b2804f608fc v3.0b1 +16ec4bb14a68ea428acf09ebf0c92981da2646f3 v3.0b2 +509e30a7968e01be329ec121540b3e755fc4e566 v3.0b3 +507ede9c7f7f475dfafbd4a52c22d767d10a2bc0 v3.0rc1 +8fae465a39627b590385462e6095eb63af45240a v3.0rc2 +e83a60c69d53f5551a306e77a6d38e9b11485496 v3.0rc3 +bc1ce368986e45b1faf96f93995df46bcd75e7b8 v3.1a1 +ee430e5075db2adf8124e6b94916a89ca41d3171 v3.1a2 +b63020797f9678adaf4d2c3e26574a9eef2ef028 v3.1b1 +4353fd0843cb31b356adc50f93d220e2e7255ef2 v3.1rc1 +0b87e438e1b53e3f812cad963a7fdb65d198ba2f v3.1rc2 +a69a031ac1402dede8b1ef80096436bca6d371f3 v3.1 +35efb1054ec6ceca72017a587263cb6a9257340b v3.1.1rc1 +8b9c0f573ab29c41c6c5fdcca82a1fe0ff5355af v3.1.1 +149b8b87514d10416b598884db5f74651f625b38 v3.1.2rc1 +960efa327c5d9c18df995437b0ac550cb89c9f85 v3.1.2 +d18e9d71f369d8211f6ac87252c6d3211f9bd09f v3.1.3rc1 +a4f75773c0060cee38b0bb651a7aba6f56b0e996 v3.1.3 +32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1 +c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4 +ee26aca3219cf4bb0b93352e83edcc9cb28c7802 v3.1.5rc1 +75db2bc69fc9a3e4801e94e3e19801cb096208d8 v3.1.5rc2 +7395330e495ec3316862ca1f6ce0aaf7bdf6785b v3.1.5 +b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1 +56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2 +da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3 +d92a5b850f5e56808bedc01723906ed64c5e6e2e v3.2a4 +b635cea94195780c8716e236479af319bcc26253 v3.2b1 +e3af5f3a7904c0d5343ec9633ea66e7acfd23a66 v3.2b2 +865d5b24bf28ca41b536befc326407c03e74a4d5 v3.2rc1 +acf3e24dd0d0dfd1e20c907d696d3da965a8f56f v3.2rc2 +18c1f52896501c7ee13b038454a39acb45a87979 v3.2rc3 +a222a015e28d8ae9af3899258dc6c15c3d40add0 v3.2 +8ffac2337a3323323d02153ac919fd1483176652 v3.2.1b1 +cfa9364997c7f2e67b9cbb45c3a5fa3bba4e4999 v3.2.1rc1 +5df549718fb4841ff521fe051f6b54f290fad5d8 v3.2.1rc2 +ac1f7e5c05104d557d5acd922e95625ba5d1fe10 v3.2.1 +c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 +137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 +7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 +428f05cb7277e1d42bb9dd8d1af6b6270ebc6112 v3.2.3rc2 +3d0686d90f55a78f96d9403da2c52dc2411419d0 v3.2.3 +b2cb7bc1edb8493c0a78f9331eae3e8fba6a881d v3.2.4rc1 +1e10bdeabe3de02f038a63c001911561ac1d13a7 v3.2.4 +cef745775b6583446572cffad704100983db2bea v3.2.5 +51382a5598ec96119cb84594572901c9c964dc3c v3.2.6rc1 +0bd5f4f14de965ca8e44c6e3965fee106176cfc4 v3.2.6 +f1a9a6505731714f0e157453ff850e3b71615c45 v3.3.0a1 +2f69db52d6de306cdaef0a0cc00cc823fb350b01 v3.3.0a2 +0b53b70a40a00013505eb35e3660057b62be77be v3.3.0a3 +7c51388a3aa7ce76a8541bbbdfc05d2d259a162c v3.3.0a4 +e15c554cd43eb23bc0a528a4e8741da9bbec9607 v3.3.0b1 +4972a8f1b2aa3d7cdd64dc96aa7fa112fe1ea343 v3.3.0b2 +8bb5c7bc46ba43804480f3e328e1fa956672c885 v3.3.0rc1 +88a0792e8ba3e4916b24c7e7a522c277d326d66e v3.3.0rc2 +c191d21cefafb3832c45570e84854e309aa62eaa v3.3.0rc3 +bd8afb90ebf28ba4edc901d4a235f75e7bbc79fd v3.3.0 +92c2cfb924055ce68c4f78f836dcfe688437ceb8 v3.3.1rc1 +d9893d13c6289aa03d33559ec67f97dcbf5c9e3c v3.3.1 +d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2 +fd53c500f8b80f54f3ecedec9da2e8c7e52a6888 v3.3.3rc1 +d32442c0e60dfbd71234e807d3d1dedd227495a9 v3.3.3rc2 +c3896275c0f61b2510a6c7e6c458a750359a91b8 v3.3.3 +fa92f5f940c6c0d839d7f0611e4b717606504a3c v3.3.4rc1 +7ff62415e4263c432c8acf6e424224209211eadb v3.3.4 +9ec811df548ed154a9bf9815383a916d6df31b98 v3.3.5rc1 +ca5635efe090f78806188ac2758f9948596aa8b2 v3.3.5rc2 +62cf4e77f78564714e7ea3d4bf1479ca1fbd0758 v3.3.5 +51317c9786f54267975abf2e9c502e6aaaa4a249 v3.3.6rc1 +971fec30da1fc5bf2b9fb28e09812a5127014211 v3.3.6 +46535f65e7f3bcdcf176f36d34bc1fed719ffd2b v3.4.0a1 +9265a2168e2cb2a84785d8717792acc661e6b692 v3.4.0a2 +dd9cdf90a5073510877e9dd5112f8e6cf20d5e89 v3.4.0a3 +e245b0d7209bb6d0e19316e1e2af1aa9c2139104 v3.4.0a4 +3405dc9a6afaa0a06dd1f6f182ec5c998dce6f5f v3.4.0b1 +ba32913eb13ec545a46dd0ce18035b6c416f0d78 v3.4.0b2 +a97ce3ecc96af79bd2e1ac66ce48d9138e0ca749 v3.4.0b3 +5e088cea8660677969113741c1313d570d977e02 v3.4.0rc1 +a300712ed38c9a242b736c44e806caea25a6dc05 v3.4.0rc2 +8a81cdab3e9d521daaef989fade94b16455fc3b8 v3.4.0rc3 +04f714765c13824c3bc2835d7b008908862e083a v3.4.0 +c67a19e11a7191baf30f313bf55e2e0b6c6f574e v3.4.1rc1 +c0e311e010fcb5bae8d87ca22051cd0845ea0ca0 v3.4.1 +8711a09513848cfc48c689d983495ee64f4668ca v3.4.2rc1 +ab2c023a9432f16652e89c404bbc84aa91bf55af v3.4.2 +69dd528ca6255a66c37cc5cf680e8357d108b036 v3.4.3rc1 b4cbecbc0781e89a309d03b60a1f75f8499250e6 v3.4.3 -5d4b6a57d5fd7564bf73f3db0e46fe5eeb00bcd8 v3.5.0a1 +5d4b6a57d5fd7564bf73f3db0e46fe5eeb00bcd8 v3.5.0a1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 08:21:41 2015 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 27 Feb 2015 07:21:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Bump_the_blocksize_up_from?= =?utf-8?q?_62_to_64_to_speed_up_the_modulo_calculation=2E?= Message-ID: <20150227072135.20303.29170@psf.io> https://hg.python.org/cpython/rev/430cab0c5cbf changeset: 94768:430cab0c5cbf user: Raymond Hettinger date: Thu Feb 26 23:21:29 2015 -0800 summary: Bump the blocksize up from 62 to 64 to speed up the modulo calculation. Remove the old comment suggesting that it was desireable to have blocksize+2 as a multiple of the cache line length. That would have made sense only if the block structure start point was always aligned to a cache line boundary. However, the memory allocations are 16 byte aligned, so we don't really have control over whether the struct spills across cache line boundaries. files: Lib/test/test_deque.py | 2 +- Modules/_collectionsmodule.c | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -542,7 +542,7 @@ @support.cpython_only def test_sizeof(self): - BLOCKLEN = 62 + BLOCKLEN = 64 basesize = support.calcobjsize('2P4nlP') blocksize = struct.calcsize('2P%dP' % BLOCKLEN) self.assertEqual(object.__sizeof__(deque()), basesize) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -10,14 +10,11 @@ /* The block length may be set to any number over 1. Larger numbers * reduce the number of calls to the memory allocator, give faster * indexing and rotation, and reduce the link::data overhead ratio. - * - * Ideally, the block length will be set to two less than some - * multiple of the cache-line length (so that the full block - * including the leftlink and rightlink will fit neatly into - * cache lines). + * Making the block length a power of two speeds-up the modulo + * calculation in deque_item(). */ -#define BLOCKLEN 62 +#define BLOCKLEN 64 #define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 08:51:20 2015 From: python-checkins at python.org (zach.ware) Date: Fri, 27 Feb 2015 07:51:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4?= Message-ID: <20150227074050.19140.93011@psf.io> https://hg.python.org/cpython/rev/344d57c521b9 changeset: 94770:344d57c521b9 parent: 94768:430cab0c5cbf parent: 94769:d0e15d9cdd4b user: Zachary Ware date: Fri Feb 27 01:40:41 2015 -0600 summary: Merge with 3.4 files: Doc/library/stdtypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2880,8 +2880,8 @@ .. method:: bytes.isupper() bytearray.isupper() - Return true if there is at least one lowercase alphabetic ASCII character - in the sequence and no uppercase ASCII characters, false otherwise. + Return true if there is at least one uppercase alphabetic ASCII character + in the sequence and no lowercase ASCII characters, false otherwise. For example:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 08:51:20 2015 From: python-checkins at python.org (zach.ware) Date: Fri, 27 Feb 2015 07:51:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_copy/paste?= =?utf-8?q?_error_in_bytes=2Eisupper=28=29_doc=2E?= Message-ID: <20150227074050.20315.91140@psf.io> https://hg.python.org/cpython/rev/d0e15d9cdd4b changeset: 94769:d0e15d9cdd4b branch: 3.4 parent: 94765:ed27f53137ad user: Zachary Ware date: Fri Feb 27 01:40:22 2015 -0600 summary: Fix copy/paste error in bytes.isupper() doc. Reported by Jon Colburn on docs at . files: Doc/library/stdtypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2880,8 +2880,8 @@ .. method:: bytes.isupper() bytearray.isupper() - Return true if there is at least one lowercase alphabetic ASCII character - in the sequence and no uppercase ASCII characters, false otherwise. + Return true if there is at least one uppercase alphabetic ASCII character + in the sequence and no lowercase ASCII characters, false otherwise. For example:: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 10:19:02 2015 From: python-checkins at python.org (victor.stinner) Date: Fri, 27 Feb 2015 09:19:02 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_478=3A_4_PEP_have_been_ac?= =?utf-8?q?cepted_for_python_3=2E5?= Message-ID: <20150227091831.53159.99118@psf.io> https://hg.python.org/peps/rev/7ca0d878a773 changeset: 5712:7ca0d878a773 user: Victor Stinner date: Fri Feb 27 10:18:27 2015 +0100 summary: PEP 478: 4 PEP have been accepted for python 3.5 files: pep-0478.txt | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pep-0478.txt b/pep-0478.txt --- a/pep-0478.txt +++ b/pep-0478.txt @@ -62,18 +62,19 @@ Accepted PEPs: +* PEP 441, improved Python zip application support +* PEP 448, additional unpacking generalizations * PEP 471, os.scandir() +* PEP 475, retrying system calls that fail with EINTR +* PEP 486, make the Python Launcher aware of virtual environments Proposed changes for 3.5: * PEP 431, improved support for time zone databases * PEP 432, simplifying Python's startup sequence * PEP 436, a build tool generating boilerplate for extension modules -* PEP 441, improved Python zip application support * PEP 447, support for __locallookup__ metaclass method -* PEP 448, additional unpacking generalizations * PEP 455, key transforming dictionary -* PEP 475, retrying system calls that fail with EINTR -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Fri Feb 27 11:11:27 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 27 Feb 2015 11:11:27 +0100 Subject: [Python-checkins] Daily reference leaks (2eb99070a38f): sum=-3 Message-ID: results for 2eb99070a38f on branch "default" -------------------------------------------- test_asyncio leaked [0, 3, 0] memory blocks, sum=3 test_collections leaked [-2, -4, 0] references, sum=-6 test_collections leaked [-1, -2, 0] memory blocks, sum=-3 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogqNNRjK', '-x'] From solipsis at pitrou.net Fri Feb 27 11:12:37 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 27 Feb 2015 11:12:37 +0100 Subject: [Python-checkins] Daily reference leaks (1bb9641713ec): sum=0 Message-ID: results for 1bb9641713ec on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogJNvady', '-x'] From python-checkins at python.org Fri Feb 27 13:02:19 2015 From: python-checkins at python.org (hynek.schlawack) Date: Fri, 27 Feb 2015 12:02:19 +0000 Subject: [Python-checkins] =?utf-8?q?devguide=3A_Not_an_expert_on_anything?= =?utf-8?q?_anymore_unfortunately?= Message-ID: <20150227120214.87123.94497@psf.io> https://hg.python.org/devguide/rev/f2a6631d8996 changeset: 730:f2a6631d8996 user: Hynek Schlawack date: Fri Feb 27 12:59:39 2015 +0100 summary: Not an expert on anything anymore unfortunately files: experts.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -197,7 +197,7 @@ selectors neologix, giampaolo.rodola shelve shlex -shutil tarek, hynek +shutil tarek signal site smtpd giampaolo.rodola @@ -289,7 +289,7 @@ FreeBSD HP-UX Linux -Mac OS X ronaldoussoren, ned.deily, hynek +Mac OS X ronaldoussoren, ned.deily NetBSD1 OS2/EMX aimacintyre Solaris/OpenIndiana jcea @@ -322,7 +322,7 @@ GUI i18n lemburg, eric.araujo import machinery brett.cannon, ncoghlan, eric.snow -io pitrou, benjamin.peterson, stutzbach, hynek +io pitrou, benjamin.peterson, stutzbach locale lemburg, loewis mathematics mark.dickinson, eric.smith, lemburg, stutzbach memory management tim.peters, lemburg -- Repository URL: https://hg.python.org/devguide From python-checkins at python.org Fri Feb 27 15:36:29 2015 From: python-checkins at python.org (brett.cannon) Date: Fri, 27 Feb 2015 14:36:29 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_syntax_error?= Message-ID: <20150227143516.34512.71809@psf.io> https://hg.python.org/peps/rev/fc626f4b1357 changeset: 5713:fc626f4b1357 user: Brett Cannon date: Fri Feb 27 09:34:48 2015 -0500 summary: Fix syntax error files: pep-0422.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0422.txt b/pep-0422.txt --- a/pep-0422.txt +++ b/pep-0422.txt @@ -295,6 +295,8 @@ implicitly, but the decorator model makes such code much easier to understand and implement. +:: + class BuildDict: def __autodecorate__(cls): cls = super().__autodecorate__() @@ -564,4 +566,3 @@ fill-column: 70 coding: utf-8 End: - -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Feb 27 15:36:29 2015 From: python-checkins at python.org (brett.cannon) Date: Fri, 27 Feb 2015 14:36:29 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_11_to_be_more_clea?= =?utf-8?q?r_about_what_is_required_to_gain_support_for_a?= Message-ID: <20150227143517.77530.87305@psf.io> https://hg.python.org/peps/rev/00f5ef44638e changeset: 5714:00f5ef44638e user: Brett Cannon date: Fri Feb 27 09:35:12 2015 -0500 summary: Update PEP 11 to be more clear about what is required to gain support for a platform for CPython files: pep-0011.txt | 76 ++++++++++++++++++++++++++++++---------- 1 files changed, 57 insertions(+), 19 deletions(-) diff --git a/pep-0011.txt b/pep-0011.txt --- a/pep-0011.txt +++ b/pep-0011.txt @@ -2,51 +2,88 @@ Title: Removing support for little used platforms Version: $Revision$ Last-Modified: $Date$ -Author: martin at v.loewis.de (Martin von L?wis) +Author: Martin von L?wis , + Brett Cannon Status: Active Type: Process Content-Type: text/x-rst Created: 07-Jul-2002 Post-History: 18-Aug-2007 + 16-May-2014 + 20-Feb-2015 Abstract -------- -This PEP documents operating systems (platforms) which are not -supported in Python anymore. For some of these systems, -supporting code might be still part of Python, but will be removed -in a future release - unless somebody steps forward as a volunteer -to maintain this code. +This PEP documents how an operating system (platform) becomes +supported in CPython and documents past support. Rationale --------- -Over time, the Python source code has collected various pieces of +Over time, the CPython source code has collected various pieces of platform-specific code, which, at some point in time, was considered necessary to use Python on a specific platform. Without access to this platform, it is not possible to determine whether this code is still needed. As a result, this code may -either break during the Python evolution, or it may become +either break during Python's evolution, or it may become unnecessary as the platforms evolve as well. The growing amount of these fragments poses the risk of unmaintainability: without having experts for a large number of platforms, it is not possible to determine whether a certain -change to the Python source code will work on all supported +change to the CPython source code will work on all supported platforms. -To reduce this risk, this PEP proposes a procedure to remove code -for platforms with no Python users. +To reduce this risk, this PEP specifies what is required for a +platform to be considered supported by Python as well as providing a +procedure to remove code for platforms with few or no Python +users. +Supporting platforms +-------------------- + +Gaining official platform support requires two things. First, a core +developer needs to volunteer to maintain platform-specific code. This +core developer can either already be a member of the Python +development team or be given contributor rights on the basis of +maintaining platform support (it is at the discretion of the Python +development team to decide if a person is ready to have such rights +even if it is just for supporting a specific platform). + +Second, a stable buildbot must be provided [2]_. This guarantees that +platform support will not be accidentally broken by a Python core +developer who does not have personal access to the platform. For a +buildbot to be considered stable it requires that the machine be +reliably up and functioning (but it is up to the Python core +developers to decide whether to promote a buildbot to being +considered stable). + +This policy does not disqualify supporting other platforms +indirectly. Patches which are not platform-specific but still done to +add platform support will be considered for inclusion. For example, +if platform-independent changes were necessary in the configure +script which were motivated to support a specific platform that could +be accepted. Patches which add platform-specific code such as the +name of a specific platform to the configure script will generally +not be accepted without the platform having official support. + +CPU architecture and compiler support are viewed in a similar manner +as platforms. For example, to consider the ARM architecture supported +a buildbot running on ARM would be required along with support from +the Python development team. In general it is not required to have +a CPU architecture run under every possible platform in order to be +considered supported. Unsupporting platforms ---------------------- -If a certain platform that currently has special code in it is -deemed to be without Python users, a note must be posted in this -PEP that this platform is no longer actively supported. This +If a certain platform that currently has special code in CPython is +deemed to be without enough Python users or lacks proper support from +the Python development team and/or a buildbot, a note must be posted +in this PEP that this platform is no longer actively supported. This note must include: - the name of the system @@ -62,15 +99,15 @@ condition (usually a preprocessor symbol) that will become unsupported. -At the same time, the Python source code must be changed to +At the same time, the CPython source code must be changed to produce a build-time error if somebody tries to install Python on this platform. On platforms using autoconf, configure must fail. This gives potential users of the platform a chance to step forward and offer maintenance. -Resupporting platforms ----------------------- +Re-supporting platforms +----------------------- If a user of a platform wants to see this platform supported again, he may volunteer to maintain the platform support. Such an @@ -87,7 +124,7 @@ support phase, where paid support is still available, and certain bug fixes are released (in particular security fixes). -Python's Windows support now follows this lifecycle. A new feature +CPython's Windows support now follows this lifecycle. A new feature release X.Y.0 will support all Windows releases whose extended support phase is not yet expired. Subsequent bug fix releases will support the same Windows releases as the original feature release (even if @@ -101,7 +138,7 @@ release is made. Developers of extension modules will generally need to use the same Visual Studio release; they are concerned both with the availability of the versions they need to use, and with keeping -the zoo of versions small. The Python source tree will keep +the zoo of versions small. The CPython source tree will keep unmaintained build files for older Visual Studio releases, for which patches will be accepted. Such build files will be removed from the source tree 3 years after the extended support for the compiler has @@ -223,6 +260,7 @@ ---------- .. [1] http://support.microsoft.com/lifecycle/ +.. [2] http://buildbot.python.org/3.x.stable/ Copyright --------- -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Feb 27 16:29:44 2015 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 27 Feb 2015 15:29:44 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_a_warning?= Message-ID: <20150227152905.34518.73572@psf.io> https://hg.python.org/peps/rev/b2d4457b9f07 changeset: 5715:b2d4457b9f07 user: Benjamin Peterson date: Fri Feb 27 10:29:03 2015 -0500 summary: a warning files: pep-0101.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt --- a/pep-0101.txt +++ b/pep-0101.txt @@ -436,7 +436,8 @@ the script Doc/tools/dailybuild.py to point to the right stable/development branches, and to install it and make the initial checkout. The Doc's version_switcher.js script also needs to be - updated. + updated. In general, please don't touch things in the toplevel + /srv/docs.python.org/ directory unless you know what you're doing. ___ Note both the documentation and downloads are behind a caching CDN. If you change archives after downloading them through the website, you'll -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Feb 27 17:47:48 2015 From: python-checkins at python.org (victor.stinner) Date: Fri, 27 Feb 2015 16:47:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNTI2?= =?utf-8?q?=3A_Fix_ResourceWarning_in_test=5Fhttplib=2E_Patch_written_by_A?= =?utf-8?q?lex_Shkop=2E?= Message-ID: <20150227164747.15324.77009@psf.io> https://hg.python.org/cpython/rev/056d71d7bb28 changeset: 94771:056d71d7bb28 branch: 3.4 parent: 94769:d0e15d9cdd4b user: Victor Stinner date: Fri Feb 27 17:47:23 2015 +0100 summary: Issue #23526: Fix ResourceWarning in test_httplib. Patch written by Alex Shkop. files: Lib/test/test_httplib.py | 3 +++ Misc/ACKS | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -840,6 +840,7 @@ context=context) h.request('GET', '/') resp = h.getresponse() + h.close() self.assertIn('nginx', resp.getheader('server')) @support.system_must_validate_cert @@ -851,6 +852,7 @@ h.request('GET', '/') resp = h.getresponse() content_type = resp.getheader('content-type') + h.close() self.assertIn('text/html', content_type) def test_networked_good_cert(self): @@ -865,6 +867,7 @@ h.request('GET', '/') resp = h.getresponse() server_string = resp.getheader('server') + h.close() self.assertIn('nginx', server_string) def test_networked_bad_cert(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1247,6 +1247,7 @@ Pete Shinners Michael Shiplett John W. Shipman +Alex Shkop Joel Shprentz Yue Shuaijie Terrel Shumway -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 17:47:48 2015 From: python-checkins at python.org (victor.stinner) Date: Fri, 27 Feb 2015 16:47:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28httplib=29?= Message-ID: <20150227164747.16410.60481@psf.io> https://hg.python.org/cpython/rev/2701e36e692f changeset: 94772:2701e36e692f parent: 94770:344d57c521b9 parent: 94771:056d71d7bb28 user: Victor Stinner date: Fri Feb 27 17:47:40 2015 +0100 summary: Merge 3.4 (httplib) files: Lib/test/test_httplib.py | 3 +++ Misc/ACKS | 1 + 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1113,6 +1113,7 @@ context=context) h.request('GET', '/') resp = h.getresponse() + h.close() self.assertIn('nginx', resp.getheader('server')) @support.system_must_validate_cert @@ -1124,6 +1125,7 @@ h.request('GET', '/') resp = h.getresponse() content_type = resp.getheader('content-type') + h.close() self.assertIn('text/html', content_type) def test_networked_good_cert(self): @@ -1138,6 +1140,7 @@ h.request('GET', '/') resp = h.getresponse() server_string = resp.getheader('server') + h.close() self.assertIn('nginx', server_string) def test_networked_bad_cert(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1270,6 +1270,7 @@ Pete Shinners Michael Shiplett John W. Shipman +Alex Shkop Joel Shprentz Yue Shuaijie Terrel Shumway -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 17:51:06 2015 From: python-checkins at python.org (victor.stinner) Date: Fri, 27 Feb 2015 16:51:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIzNTM3?= =?utf-8?q?=3A_Remove_2_unused_private_methods_of_asyncio=2EBaseSubprocess?= =?utf-8?q?Transport?= Message-ID: <20150227165105.10068.12440@psf.io> https://hg.python.org/cpython/rev/0b390b5a6729 changeset: 94773:0b390b5a6729 branch: 3.4 parent: 94771:056d71d7bb28 user: Victor Stinner date: Fri Feb 27 17:49:09 2015 +0100 summary: Issue #23537: Remove 2 unused private methods of asyncio.BaseSubprocessTransport Methods only raise NotImplementedError and are never used. files: Lib/asyncio/base_subprocess.py | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -79,12 +79,6 @@ def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): raise NotImplementedError - def _make_write_subprocess_pipe_proto(self, fd): - raise NotImplementedError - - def _make_read_subprocess_pipe_proto(self, fd): - raise NotImplementedError - def close(self): if self._closed: return -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 17:51:07 2015 From: python-checkins at python.org (victor.stinner) Date: Fri, 27 Feb 2015 16:51:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20150227165105.87115.27710@psf.io> https://hg.python.org/cpython/rev/3708585125b8 changeset: 94774:3708585125b8 parent: 94772:2701e36e692f parent: 94773:0b390b5a6729 user: Victor Stinner date: Fri Feb 27 17:49:19 2015 +0100 summary: Merge 3.4 (asyncio) files: Lib/asyncio/base_subprocess.py | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -79,12 +79,6 @@ def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): raise NotImplementedError - def _make_write_subprocess_pipe_proto(self, fd): - raise NotImplementedError - - def _make_read_subprocess_pipe_proto(self, fd): - raise NotImplementedError - def close(self): if self._closed: return -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 18:13:55 2015 From: python-checkins at python.org (brett.cannon) Date: Fri, 27 Feb 2015 17:13:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322834=3A_Drop_a_r?= =?utf-8?q?edundant_comment_and_use_errno_instead_of_an?= Message-ID: <20150227171340.20291.81829@psf.io> https://hg.python.org/cpython/rev/38c503c2c066 changeset: 94775:38c503c2c066 user: Brett Cannon date: Fri Feb 27 12:13:35 2015 -0500 summary: Issue #22834: Drop a redundant comment and use errno instead of an integer. Thanks to Serhiy Storchaka and Martin Panter for the suggestions. files: Lib/test/test_importlib/import_/test_path.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -3,6 +3,7 @@ importlib = util.import_importlib('importlib') machinery = util.import_importlib('importlib.machinery') +import errno import os import sys import tempfile @@ -167,8 +168,7 @@ with tempfile.TemporaryDirectory() as path: os.chdir(path) except OSError as exc: - if exc.errno == 22: - # issue #22834 + if exc.errno == errno.EINVAL: self.skipTest("platform does not allow the deletion of the cwd") raise with util.import_state(path=['']): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 18:23:58 2015 From: python-checkins at python.org (larry.hastings) Date: Fri, 27 Feb 2015 17:23:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjQu?= Message-ID: <20150227172117.87119.71314@psf.io> https://hg.python.org/cpython/rev/28ba862036cc changeset: 94777:28ba862036cc parent: 94775:38c503c2c066 parent: 94776:bcc877a28219 user: Larry Hastings date: Fri Feb 27 09:21:06 2015 -0800 summary: Merge from 3.4. files: Misc/NEWS | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -345,8 +345,6 @@ - Issue #23366: Fixed possible integer overflow in itertools.combinations. -- Issue #23366: Fixed possible integer overflow in itertools.combinations. - - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. @@ -376,7 +374,7 @@ __ne__() now works correctly. - Issue #19996: :class:`email.feedparser.FeedParser` now handles (malformed) - headers with no key rather than amusing the body has started. + headers with no key rather than assuming the body has started. - Issue #20188: Support Application-Layer Protocol Negotiation (ALPN) in the ssl module. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 18:23:59 2015 From: python-checkins at python.org (larry.hastings) Date: Fri, 27 Feb 2015 17:23:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_minor_erro?= =?utf-8?q?rs_in_Misc/NEWS=2E__=28Thanks_for_the_report=2C_Florian_Bruhin!?= =?utf-8?q?=29?= Message-ID: <20150227172116.34496.55001@psf.io> https://hg.python.org/cpython/rev/bcc877a28219 changeset: 94776:bcc877a28219 branch: 3.4 parent: 94773:0b390b5a6729 user: Larry Hastings date: Fri Feb 27 09:14:32 2015 -0800 summary: Fix minor errors in Misc/NEWS. (Thanks for the report, Florian Bruhin!) files: Misc/NEWS | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -119,8 +119,6 @@ - Issue #23366: Fixed possible integer overflow in itertools.combinations. -- Issue #23366: Fixed possible integer overflow in itertools.combinations. - - Issue #23369: Fixed possible integer overflow in _json.encode_basestring_ascii. @@ -142,7 +140,7 @@ __ne__() now works correctly. - Issue #19996: :class:`email.feedparser.FeedParser` now handles (malformed) - headers with no key rather than amusing the body has started. + headers with no key rather than assuming the body has started. - Issue #23248: Update ssl error codes from latest OpenSSL git master. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 20:08:58 2015 From: python-checkins at python.org (chris.angelico) Date: Fri, 27 Feb 2015 19:08:58 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Create_PEP_487_from_Martin_Te?= =?utf-8?q?ichmann=27s_submission?= Message-ID: <20150227190858.53135.37734@psf.io> https://hg.python.org/peps/rev/c45defff808a changeset: 5716:c45defff808a user: Chris Angelico date: Sat Feb 28 06:07:44 2015 +1100 summary: Create PEP 487 from Martin Teichmann's submission files: pep-0487.txt | 485 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 485 insertions(+), 0 deletions(-) diff --git a/pep-0487.txt b/pep-0487.txt new file mode 100644 --- /dev/null +++ b/pep-0487.txt @@ -0,0 +1,485 @@ +PEP: 487 +Title: Simpler customisation of class creation +Version: $Revision$ +Last-Modified: $Date$ +Author: Martin Teichmann , +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 27-Feb-2015 +Python-Version: 3.5 +Post-History: 27-Feb-2015 +Replaces: 422 + + +Abstract +======== + +Currently, customising class creation requires the use of a custom metaclass. +This custom metaclass then persists for the entire lifecycle of the class, +creating the potential for spurious metaclass conflicts. + +This PEP proposes to instead support a wide range of customisation +scenarios through a new ``namespace`` parameter in the class header, and +a new ``__init_subclass__`` hook in the class body. + +The new mechanism should be easier to understand and use than +implementing a custom metaclass, and thus should provide a gentler +introduction to the full power Python's metaclass machinery. + + +Connection to other PEP +======================= + +This is a competing proposal to PEP 422 by Nick Coughlan and Daniel Urban. +It shares both most of the PEP text and proposed code, but has major +differences in how to achieve its goals. + +Background +========== + +For an already created class ``cls``, the term "metaclass" has a clear +meaning: it is the value of ``type(cls)``. + +*During* class creation, it has another meaning: it is also used to refer to +the metaclass hint that may be provided as part of the class definition. +While in many cases these two meanings end up referring to one and the same +object, there are two situations where that is not the case: + +* If the metaclass hint refers to an instance of ``type``, then it is + considered as a candidate metaclass along with the metaclasses of all of + the parents of the class being defined. If a more appropriate metaclass is + found amongst the candidates, then it will be used instead of the one + given in the metaclass hint. +* Otherwise, an explicit metaclass hint is assumed to be a factory function + and is called directly to create the class object. In this case, the final + metaclass will be determined by the factory function definition. In the + typical case (where the factory functions just calls ``type``, or, in + Python 3.3 or later, ``types.new_class``) the actual metaclass is then + determined based on the parent classes. + +It is notable that only the actual metaclass is inherited - a factory +function used as a metaclass hook sees only the class currently being +defined, and is not invoked for any subclasses. + +In Python 3, the metaclass hint is provided using the ``metaclass=Meta`` +keyword syntax in the class header. This allows the ``__prepare__`` method +on the metaclass to be used to create the ``locals()`` namespace used during +execution of the class body (for example, specifying the use of +``collections.OrderedDict`` instead of a regular ``dict``). + +In Python 2, there was no ``__prepare__`` method (that API was added for +Python 3 by PEP 3115). Instead, a class body could set the ``__metaclass__`` +attribute, and the class creation process would extract that value from the +class namespace to use as the metaclass hint. There is `published code`_ that +makes use of this feature. + +Another new feature in Python 3 is the zero-argument form of the ``super()`` +builtin, introduced by PEP 3135. This feature uses an implicit ``__class__`` +reference to the class being defined to replace the "by name" references +required in Python 2. Just as code invoked during execution of a Python 2 +metaclass could not call methods that referenced the class by name (as the +name had not yet been bound in the containing scope), similarly, Python 3 +metaclasses cannot call methods that rely on the implicit ``__class__`` +reference (as it is not populated until after the metaclass has returned +control to the class creation machinery). + +Finally, when a class uses a custom metaclass, it can pose additional +challenges to the use of multiple inheritance, as a new class cannot +inherit from parent classes with unrelated metaclasses. This means that +it is impossible to add a metaclass to an already published class: such +an addition is a backwards incompatible change due to the risk of metaclass +conflicts. + + +Proposal +======== + +This PEP proposes that a new mechanism to customise class creation be +added to Python 3.5 that meets the following criteria: + +1. Integrates nicely with class inheritance structures (including mixins and + multiple inheritance), +2. Integrates nicely with the implicit ``__class__`` reference and + zero-argument ``super()`` syntax introduced by PEP 3135, +3. Can be added to an existing base class without a significant risk of + introducing backwards compatibility problems, and +4. Restores the ability for class namespaces to have some influence on the + class creation process (above and beyond populating the namespace itself), + but potentially without the full flexibility of the Python 2 style + ``__metaclass__`` hook. + +Those goals can be achieved by adding two functionalities: + +1. A ``__init_subclass__`` hook that initializes all subclasses of a + given class, and +2. A new keyword parameter ``namespace`` to the class creation statement, + that gives an initialization of the namespace. + +As an example, the first proposal looks as follows:: + + class SpamBase: + # this is implicitly a @classmethod + def __init_subclass__(cls, ns, **kwargs): + # This is invoked after a subclass is created, but before + # explicit decorators are called. + # The usual super() mechanisms are used to correctly support + # multiple inheritance. + # ns is the classes namespace + # **kwargs are the keyword arguments to the subclasses' + # class creation statement + super().__init_subclass__(cls, ns, **kwargs) + + class Spam(SpamBase): + pass + # the new hook is called on Spam + +To simplify the cooperative multiple inheritance case, ``object`` will gain +a default implementation of the hook that does nothing:: + + class object: + def __init_subclass__(cls, ns): + pass + +Note that this method has no keyword arguments, meaning that all +methods which are more specialized have to process all keyword +arguments. + +This general proposal is not a new idea (it was first suggested for +inclusion in the language definition `more than 10 years ago`_, and a +similar mechanism has long been supported by `Zope's ExtensionClass`_), +but the situation has changed sufficiently in recent years that +the idea is worth reconsidering for inclusion. + +The second part of the proposal is to have a ``namespace`` keyword +argument to the class declaration statement. If present, its value +will be called without arguments to initialize a subclasses +namespace, very much like a metaclass ``__prepare__`` method would +do. + +In addition, the introduction of the metaclass ``__prepare__`` method +in PEP 3115 allows a further enhancement that was not possible in +Python 2: this PEP also proposes that ``type.__prepare__`` be updated +to accept a factory function as a ``namespace`` keyword-only argument. +If present, the value provided as the ``namespace`` argument will be +called without arguments to create the result of ``type.__prepare__`` +instead of using a freshly created dictionary instance. For example, +the following will use an ordered dictionary as the class namespace:: + + class OrderedBase(namespace=collections.OrderedDict): + pass + + class Ordered(OrderedBase): + # cls.__dict__ is still a read-only proxy to the class namespace, + # but the underlying storage is an OrderedDict instance + + +.. note:: + + This PEP, along with the existing ability to use __prepare__ to share a + single namespace amongst multiple class objects, highlights a possible + issue with the attribute lookup caching: when the underlying mapping is + updated by other means, the attribute lookup cache is not invalidated + correctly (this is a key part of the reason class ``__dict__`` attributes + produce a read-only view of the underlying storage). + + Since the optimisation provided by that cache is highly desirable, + the use of a preexisting namespace as the class namespace may need to + be declared as officially unsupported (since the observed behaviour is + rather strange when the caches get out of sync). + + +Key Benefits +============ + + +Easier use of custom namespaces for a class +------------------------------------------- + +Currently, to use a different type (such as ``collections.OrderedDict``) for +a class namespace, or to use a pre-populated namespace, it is necessary to +write and use a custom metaclass. With this PEP, using a custom namespace +becomes as simple as specifying an appropriate factory function in the +class header. + + +Easier inheritance of definition time behaviour +----------------------------------------------- + +Understanding Python's metaclasses requires a deep understanding of +the type system and the class construction process. This is legitimately +seen as challenging, due to the need to keep multiple moving parts (the code, +the metaclass hint, the actual metaclass, the class object, instances of the +class object) clearly distinct in your mind. Even when you know the rules, +it's still easy to make a mistake if you're not being extremely careful. + +Understanding the proposed implicit class initialization hook only requires +ordinary method inheritance, which isn't quite as daunting a task. The new +hook provides a more gradual path towards understanding all of the phases +involved in the class definition process. + + +Reduced chance of metaclass conflicts +------------------------------------- + +One of the big issues that makes library authors reluctant to use metaclasses +(even when they would be appropriate) is the risk of metaclass conflicts. +These occur whenever two unrelated metaclasses are used by the desired +parents of a class definition. This risk also makes it very difficult to +*add* a metaclass to a class that has previously been published without one. + +By contrast, adding an ``__init_subclass__`` method to an existing type poses +a similar level of risk to adding an ``__init__`` method: technically, there +is a risk of breaking poorly implemented subclasses, but when that occurs, +it is recognised as a bug in the subclass rather than the library author +breaching backwards compatibility guarantees. + + +Integrates cleanly with \PEP 3135 +--------------------------------- + +Given that the method is called on already existing classes, the new +hook will be able to freely invoke class methods that rely on the +implicit ``__class__`` reference introduced by PEP 3135, including +methods that use the zero argument form of ``super()``. + + +Replaces many use cases for dynamic setting of ``__metaclass__`` +---------------------------------------------------------------- + +For use cases that don't involve completely replacing the defined +class, Python 2 code that dynamically set ``__metaclass__`` can now +dynamically set ``__init_subclass__`` instead. For more advanced use +cases, introduction of an explicit metaclass (possibly made available +as a required base class) will still be necessary in order to support +Python 3. + + +A path of introduction into Python +================================== + +Most of the benefits of this PEP can already be implemented using +a simple metaclass. For the ``__init_subclass__`` hook this works +all the way down to python 2.7, while the namespace needs python 3.0 +to work. Such a class has been `uploaded to PyPI`_. + +The only drawback of such a metaclass are the mentioned problems with +metaclasses and multiple inheritance. Two classes using such a +metaclass can only be combined, if they use exactly the same such +metaclass. This fact calls for the inclusion of such a class into the +standard library, let's call it ``SubclassMeta``, with a base class +using it called ``SublassInit``. Once all users use this standard +library metaclass, classes from different packages can easily be +combined. + +But still such classes cannot be easily combined with other classes +using other metaclasses. Authors of metaclasses should bear that in +mind and inherit from the standard metaclass if it seems useful +for users of the metaclass to add more functionality. Ultimately, +if the need for combining with other metaclasses is strong enough, +the proposed functionality may be introduced into python's ``type``. + +Those arguments strongly hint to the following procedure to include +the proposed functionality into python: + +1. The metaclass implementing this proposal is put onto PyPI, so that + it can be used and scrutinized. +2. Once the code is properly mature, it can be added to the python + standard library. There should be a new module called + ``metaclass`` which collects tools for metaclass authors, as well + as a documentation of the best practices of how to write + metaclasses. +3. If the need of combining this metaclass with other metaclasses is + strong enough, it may be included into python itself. + + +New Ways of Using Classes +========================= + +This proposal has many usecases like the following. In the examples, +we still inherit from the ``SubclassInit`` base class. This would +become unnecessary once this PEP is included in Python directly. + +Subclass registration +--------------------- + +Especially when writing a plugin system, one likes to register new +subclasses of a plugin baseclass. This can be done as follows:: + + class PluginBase(SubclassInit): + subclasses = [] + + def __init_subclass__(cls, ns, **kwargs): + super().__init_subclass__(ns, **kwargs) + cls.subclasses.append(cls) + +One should note that this also works nicely as a mixin class. + +Trait descriptors +----------------- + +There are many designs of python descriptors in the wild which, for +example, check boundaries of values. Often those "traits" need some support +of a metaclass to work. This is how this would look like with this +PEP:: + + class Trait: + def __get__(self, instance, owner): + return instance.__dict__[self.key] + + def __set__(self, instance, value): + instance.__dict__[self.key] = value + + class Int(Trait): + def __set__(self, instance, value): + # some boundary check code here + super().__set__(instance, value) + + class HasTraits(SubclassInit): + def __init_subclass__(cls, ns, **kwargs): + super().__init_subclass__(ns, **kwargs) + for k, v in ns.items(): + if isinstance(v, Trait): + v.key = k + +The new ``namespace`` keyword in the class header enables a number of +interesting options for controlling the way a class is initialised, +including some aspects of the object models of both Javascript and Ruby. + + +Order preserving classes +------------------------ + +:: + + class OrderedClassBase(namespace=collections.OrderedDict): + pass + + class OrderedClass(OrderedClassBase): + a = 1 + b = 2 + c = 3 + + +Prepopulated namespaces +----------------------- + +:: + + seed_data = dict(a=1, b=2, c=3) + class PrepopulatedClass(namespace=seed_data.copy): + pass + + +Cloning a prototype class +------------------------- + +:: + + class NewClass(namespace=Prototype.__dict__.copy): + pass + + +Rejected Design Options +======================= + + +Calling the hook on the class itself +------------------------------------ + +Adding an ``__autodecorate__`` hook that would be called on the class +itself was the proposed idea of PEP 422. Most examples work the same +way or even better if the hook is called on the subclass. In general, +it is much easier to explicitly call the hook on the class in which it +is defined (to opt-in to such a behavior) than to opt-out, meaning +that one does not want the hook to be called on the class it is +defined in. + +This becomes most evident if the class in question is designed as a +mixin: it is very unlikely that the code of the mixin is to be +executed for the mixin class itself, as it is not supposed to be a +complete class on its own. + +The original proposal also made major changes in the class +initialization process, rendering it impossible to back-port the +proposal to older python versions. + + +Other variants of calling the hook +---------------------------------- + +Other names for the hook were presented, namely ``__decorate__`` or +``__autodecorate__``. This proposal opts for ``__init_subclass__`` as +it is very close to the ``__init__`` method, just for the subclass, +while it is not very close to decorators, as it does not return the +class. + + +Requiring an explicit decorator on ``__init_subclass__`` +-------------------------------------------------------- + +One could require the explicit use of ``@classmethod`` on the +``__init_subclass__`` decorator. It was made implicit since there's no +sensible interpretation for leaving it out, and that case would need +to be detected anyway in order to give a useful error message. + +This decision was reinforced after noticing that the user experience of +defining ``__prepare__`` and forgetting the ``@classmethod`` method +decorator is singularly incomprehensible (particularly since PEP 3115 +documents it as an ordinary method, and the current documentation doesn't +explicitly say anything one way or the other). + + +Passing in the namespace directly rather than a factory function +---------------------------------------------------------------- + +At one point, PEP 422 proposed that the class namespace be passed +directly as a keyword argument, rather than passing a factory function. +However, this encourages an unsupported behaviour (that is, passing the +same namespace to multiple classes, or retaining direct write access +to a mapping used as a class namespace), so the API was switched to +the factory function version. + + +Possible Extensions +=================== + +Some extensions to this PEP are imaginable, which are postponed to a +later pep: + +* A ``__new_subclass__`` method could be defined which acts like a + ``__new__`` for classes. This would be very close to + ``__autodecorate__`` in PEP 422. +* ``__subclasshook__`` could be made a classmethod in a class instead + of a method in the metaclass. + +References +========== + +.. _published code: + http://mail.python.org/pipermail/python-dev/2012-June/119878.html + +.. _more than 10 years ago: + http://mail.python.org/pipermail/python-dev/2001-November/018651.html + +.. _Zope's ExtensionClass: + http://docs.zope.org/zope_secrets/extensionclass.html + +.. _uploaded to PyPI: + https://pypi.python.org/pypi/metaclass + +Copyright +========= + +This document has been placed in the public domain. + + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Feb 27 21:10:46 2015 From: python-checkins at python.org (brett.cannon) Date: Fri, 27 Feb 2015 20:10:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4_for_porting_HOWTO_tweaks?= Message-ID: <20150227201044.10064.79937@psf.io> https://hg.python.org/cpython/rev/d5c9dd8dd5da changeset: 94779:d5c9dd8dd5da parent: 94777:28ba862036cc parent: 94778:b7945565e150 user: Brett Cannon date: Fri Feb 27 15:10:38 2015 -0500 summary: Merge with 3.4 for porting HOWTO tweaks files: Doc/howto/pyporting.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -169,8 +169,9 @@ division or continue using ``/`` and expect a float The reason that ``/`` isn't simply translated to ``//`` automatically is that if -an object defines its own ``__div__`` method but not ``__floordiv__`` then your -code would begin to fail. +an object defines a ``__truediv__`` method but not ``__floordiv__`` then your +code would begin to fail (e.g. a user-defined class that uses ``/`` to +signify some operation but not ``//`` for the same thing or at all). Text versus binary data +++++++++++++++++++++++ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 21:10:46 2015 From: python-checkins at python.org (brett.cannon) Date: Fri, 27 Feb 2015 20:10:46 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_the_clarif?= =?utf-8?q?ication_as_to_why_division_cannot_be_ported_automatically?= Message-ID: <20150227201044.15302.86634@psf.io> https://hg.python.org/cpython/rev/b7945565e150 changeset: 94778:b7945565e150 branch: 3.4 parent: 94776:bcc877a28219 user: Brett Cannon date: Fri Feb 27 15:10:03 2015 -0500 summary: Fix the clarification as to why division cannot be ported automatically files: Doc/howto/pyporting.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -169,8 +169,9 @@ division or continue using ``/`` and expect a float The reason that ``/`` isn't simply translated to ``//`` automatically is that if -an object defines its own ``__div__`` method but not ``__floordiv__`` then your -code would begin to fail. +an object defines a ``__truediv__`` method but not ``__floordiv__`` then your +code would begin to fail (e.g. a user-defined class that uses ``/`` to +signify some operation but not ``//`` for the same thing or at all). Text versus binary data +++++++++++++++++++++++ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Feb 27 21:43:00 2015 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 27 Feb 2015 20:43:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Since_the_index_is_always_?= =?utf-8?q?non-negative=2C_use_faster_unsigned_division_and_modulo=2E?= Message-ID: <20150227204300.10080.58755@psf.io> https://hg.python.org/cpython/rev/91a1613e161c changeset: 94780:91a1613e161c user: Raymond Hettinger date: Fri Feb 27 12:42:54 2015 -0800 summary: Since the index is always non-negative, use faster unsigned division and modulo. files: Modules/_collectionsmodule.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -142,7 +142,7 @@ static PyTypeObject deque_type; -/* XXX Todo: +/* XXX Todo: If aligned memory allocations become available, make the deque object 64 byte aligned so that all of the fields can be retrieved or updated in a single cache line. @@ -780,7 +780,9 @@ b = deque->rightblock; } else { i += deque->leftindex; - n = i / BLOCKLEN; + assert(i >= 0); + n = (Py_ssize_t)((unsigned) i / BLOCKLEN); + i = (Py_ssize_t)((unsigned) i % BLOCKLEN); i %= BLOCKLEN; if (index < (Py_SIZE(deque) >> 1)) { b = deque->leftblock; @@ -1848,7 +1850,7 @@ (hash = ((PyASCIIObject *) key)->hash) == -1) { hash = PyObject_Hash(key); - if (hash == -1) + if (hash == -1) goto done; } -- Repository URL: https://hg.python.org/cpython From tjreedy at udel.edu Fri Feb 27 22:17:09 2015 From: tjreedy at udel.edu (Terry Reedy) Date: Fri, 27 Feb 2015 16:17:09 -0500 Subject: [Python-checkins] cpython: Since the index is always non-negative, use faster unsigned division and modulo. In-Reply-To: <20150227204300.10080.58755@psf.io> References: <20150227204300.10080.58755@psf.io> Message-ID: <54F0DED5.9080300@udel.edu> On 2/27/2015 3:43 PM, raymond.hettinger wrote: > https://hg.python.org/cpython/rev/91a1613e161c > changeset: 94780:91a1613e161c > user: Raymond Hettinger > date: Fri Feb 27 12:42:54 2015 -0800 > summary: > Since the index is always non-negative, use faster unsigned division and modulo. > - n = i / BLOCKLEN; > + assert(i >= 0); > + n = (Py_ssize_t)((unsigned) i / BLOCKLEN); > + i = (Py_ssize_t)((unsigned) i % BLOCKLEN); > i %= BLOCKLEN; Should this last line be removed after being replaced by the line above? I believe it is now a time-wasting no-op after the addition. Terry From python-checkins at python.org Sat Feb 28 02:00:47 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 28 Feb 2015 01:00:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Line_missed_in_last_checki?= =?utf-8?q?n?= Message-ID: <20150228010045.39363.54226@psf.io> https://hg.python.org/cpython/rev/de6d278c432a changeset: 94781:de6d278c432a user: Raymond Hettinger date: Fri Feb 27 16:59:29 2015 -0800 summary: Line missed in last checkin files: Modules/_collectionsmodule.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -783,7 +783,6 @@ assert(i >= 0); n = (Py_ssize_t)((unsigned) i / BLOCKLEN); i = (Py_ssize_t)((unsigned) i % BLOCKLEN); - i %= BLOCKLEN; if (index < (Py_SIZE(deque) >> 1)) { b = deque->leftblock; while (n--) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 11:46:46 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 28 Feb 2015 10:46:46 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIxNjE5?= =?utf-8?q?=3A_Popen_objects_no_longer_leave_a_zombie_after_exit_in_the_wi?= =?utf-8?q?th?= Message-ID: <20150228104644.77540.79683@psf.io> https://hg.python.org/cpython/rev/b5e9ddbdd4a7 changeset: 94782:b5e9ddbdd4a7 branch: 3.4 parent: 94778:b7945565e150 user: Serhiy Storchaka date: Sat Feb 28 12:43:08 2015 +0200 summary: Issue #21619: Popen objects no longer leave a zombie after exit in the with statement if the pipe was broken. Patch by Martin Panter. files: Lib/subprocess.py | 10 ++++++---- Lib/test/test_subprocess.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -896,10 +896,12 @@ self.stdout.close() if self.stderr: self.stderr.close() - if self.stdin: - self.stdin.close() - # Wait for the process to terminate, to avoid zombies. - self.wait() + try: # Flushing a BufferedWriter may raise an error + if self.stdin: + self.stdin.close() + finally: + # Wait for the process to terminate, to avoid zombies. + self.wait() def __del__(self, _maxsize=sys.maxsize): if not self._child_created: diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -2521,6 +2521,21 @@ stderr=subprocess.PIPE) as proc: pass + def test_broken_pipe_cleanup(self): + """Broken pipe error should not prevent wait() (Issue 21619)""" + proc = subprocess.Popen([sys.executable, "-c", + "import sys;" + "sys.stdin.close();" + "sys.stdout.close();" # Signals that input pipe is closed + ], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + proc.stdout.read() # Make sure subprocess has closed its input + proc.stdin.write(b"buffered data") + self.assertIsNone(proc.returncode) + self.assertRaises(BrokenPipeError, proc.__exit__, None, None, None) + self.assertEqual(0, proc.returncode) + self.assertTrue(proc.stdin.closed) + self.assertTrue(proc.stdout.closed) + def test_main(): unit_tests = (ProcessTestCase, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #21619: Popen objects no longer leave a zombie after exit in the with + statement if the pipe was broken. Patch by Martin Panter. + - Issue #6639: Module-level turtle functions no longer raise TclError after closing the window. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 11:46:45 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 28 Feb 2015 10:46:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2321619=3A_Popen_objects_no_longer_leave_a_zombie?= =?utf-8?q?_after_exit_in_the_with?= Message-ID: <20150228104645.34504.36322@psf.io> https://hg.python.org/cpython/rev/cdac249808a8 changeset: 94783:cdac249808a8 parent: 94781:de6d278c432a parent: 94782:b5e9ddbdd4a7 user: Serhiy Storchaka date: Sat Feb 28 12:45:00 2015 +0200 summary: Issue #21619: Popen objects no longer leave a zombie after exit in the with statement if the pipe was broken. Patch by Martin Panter. files: Lib/subprocess.py | 10 ++++++---- Lib/test/test_subprocess.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -892,10 +892,12 @@ self.stdout.close() if self.stderr: self.stderr.close() - if self.stdin: - self.stdin.close() - # Wait for the process to terminate, to avoid zombies. - self.wait() + try: # Flushing a BufferedWriter may raise an error + if self.stdin: + self.stdin.close() + finally: + # Wait for the process to terminate, to avoid zombies. + self.wait() def __del__(self, _maxsize=sys.maxsize): if not self._child_created: diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -2502,6 +2502,21 @@ stderr=subprocess.PIPE) as proc: pass + def test_broken_pipe_cleanup(self): + """Broken pipe error should not prevent wait() (Issue 21619)""" + proc = subprocess.Popen([sys.executable, "-c", + "import sys;" + "sys.stdin.close();" + "sys.stdout.close();" # Signals that input pipe is closed + ], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + proc.stdout.read() # Make sure subprocess has closed its input + proc.stdin.write(b"buffered data") + self.assertIsNone(proc.returncode) + self.assertRaises(BrokenPipeError, proc.__exit__, None, None, None) + self.assertEqual(0, proc.returncode) + self.assertTrue(proc.stdin.closed) + self.assertTrue(proc.stdout.closed) + def test_main(): unit_tests = (ProcessTestCase, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #21619: Popen objects no longer leave a zombie after exit in the with + statement if the pipe was broken. Patch by Martin Panter. + - Issue #15955: Add an option to limit the output size in bz2.decompress(). Patch by Nikolaus Rath. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 12:28:54 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 28 Feb 2015 11:28:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fixed_a_test_f?= =?utf-8?q?or_issue_=2321619_on_Windows=2E?= Message-ID: <20150228112854.10080.94425@psf.io> https://hg.python.org/cpython/rev/1b4d916329e7 changeset: 94784:1b4d916329e7 branch: 3.4 parent: 94782:b5e9ddbdd4a7 user: Serhiy Storchaka date: Sat Feb 28 13:27:54 2015 +0200 summary: Fixed a test for issue #21619 on Windows. On Windows an OSError with errno=EINVAL is raised. files: Lib/test/test_subprocess.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -2531,7 +2531,7 @@ proc.stdout.read() # Make sure subprocess has closed its input proc.stdin.write(b"buffered data") self.assertIsNone(proc.returncode) - self.assertRaises(BrokenPipeError, proc.__exit__, None, None, None) + self.assertRaises(OSError, proc.__exit__, None, None, None) self.assertEqual(0, proc.returncode) self.assertTrue(proc.stdin.closed) self.assertTrue(proc.stdout.closed) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 12:28:54 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 28 Feb 2015 11:28:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Fixed_a_test_for_issue_=2321619_on_Windows=2E?= Message-ID: <20150228112854.16424.33924@psf.io> https://hg.python.org/cpython/rev/eae459e35cb9 changeset: 94785:eae459e35cb9 parent: 94783:cdac249808a8 parent: 94784:1b4d916329e7 user: Serhiy Storchaka date: Sat Feb 28 13:28:19 2015 +0200 summary: Fixed a test for issue #21619 on Windows. On Windows an OSError with errno=EINVAL is raised. files: Lib/test/test_subprocess.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -2512,7 +2512,7 @@ proc.stdout.read() # Make sure subprocess has closed its input proc.stdin.write(b"buffered data") self.assertIsNone(proc.returncode) - self.assertRaises(BrokenPipeError, proc.__exit__, None, None, None) + self.assertRaises(OSError, proc.__exit__, None, None, None) self.assertEqual(0, proc.returncode) self.assertTrue(proc.stdin.closed) self.assertTrue(proc.stdout.closed) -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sat Feb 28 14:12:30 2015 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 28 Feb 2015 14:12:30 +0100 Subject: [Python-checkins] Daily reference leaks (91a1613e161c): sum=6 Message-ID: results for 91a1613e161c on branch "default" -------------------------------------------- test_asyncio leaked [0, 3, 0] memory blocks, sum=3 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogvsWBR0', '-x'] From python-checkins at python.org Sat Feb 28 16:41:37 2015 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 28 Feb 2015 15:41:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Convert_one_more_division_?= =?utf-8?q?to_unsigned_arithmetic_to_speed-up_deque=5Fitem=28=29=2E?= Message-ID: <20150228154136.53159.51639@psf.io> https://hg.python.org/cpython/rev/5942fd9ab335 changeset: 94786:5942fd9ab335 user: Raymond Hettinger date: Sat Feb 28 07:41:30 2015 -0800 summary: Convert one more division to unsigned arithmetic to speed-up deque_item(). files: Modules/_collectionsmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -788,7 +788,9 @@ while (n--) b = b->rightlink; } else { - n = (deque->leftindex + Py_SIZE(deque) - 1) / BLOCKLEN - n; + n = (Py_ssize_t)( + ((unsigned)(deque->leftindex + Py_SIZE(deque) - 1)) + / BLOCKLEN - n); b = deque->rightblock; while (n--) b = b->leftlink; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 16:46:08 2015 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 28 Feb 2015 15:46:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogRml4ZXMgIzIzNTIx?= =?utf-8?q?=3A_Corrected_pure_python_implementation_of_timedelta_division?= =?utf-8?q?=2E?= Message-ID: <20150228154608.19168.90440@psf.io> https://hg.python.org/cpython/rev/8fe15bf68522 changeset: 94787:8fe15bf68522 branch: 3.4 parent: 94784:1b4d916329e7 user: Alexander Belopolsky date: Sat Feb 28 10:41:57 2015 -0500 summary: Fixes #23521: Corrected pure python implementation of timedelta division. * Eliminated OverflowError from timedelta * float for some floats; * Corrected rounding in timedlta true division. files: Lib/datetime.py | 26 +++++++++++++++++-- Lib/test/datetimetester.py | 34 ++++++++++++++++++++++++++ Misc/NEWS | 4 +++ 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/Lib/datetime.py b/Lib/datetime.py --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -280,6 +280,25 @@ raise TypeError("can't compare '%s' to '%s'" % ( type(x).__name__, type(y).__name__)) +def _divide_and_round(a, b): + """divide a by b and round result to the nearest integer + + When the ratio is exactly half-way between two integers, + the even integer is returned. + """ + # Based on the reference implementation for divmod_near + # in Objects/longobject.c. + q, r = divmod(a, b) + # round up if either r / b > 0.5, or r / b == 0.5 and q is odd. + # The expression r / b > 0.5 is equivalent to 2 * r > b if b is + # positive, 2 * r < b if b negative. + r *= 2 + greater_than_half = r > b if b > 0 else r < b + if greater_than_half or r == b and q % 2 == 1: + q += 1 + + return q + class timedelta: """Represent the difference between two datetime objects. @@ -506,8 +525,9 @@ self._seconds * other, self._microseconds * other) if isinstance(other, float): + usec = self._to_microseconds() a, b = other.as_integer_ratio() - return self * a / b + return timedelta(0, 0, _divide_and_round(usec * a, b)) return NotImplemented __rmul__ = __mul__ @@ -532,10 +552,10 @@ if isinstance(other, timedelta): return usec / other._to_microseconds() if isinstance(other, int): - return timedelta(0, 0, usec / other) + return timedelta(0, 0, _divide_and_round(usec, other)) if isinstance(other, float): a, b = other.as_integer_ratio() - return timedelta(0, 0, b * usec / a) + return timedelta(0, 0, _divide_and_round(b * usec, a)) def __mod__(self, other): if isinstance(other, timedelta): diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -50,6 +50,33 @@ self.assertEqual(datetime.MINYEAR, 1) self.assertEqual(datetime.MAXYEAR, 9999) + def test_divide_and_round(self): + if '_Fast' in str(self): + return + dar = datetime_module._divide_and_round + + self.assertEqual(dar(-10, -3), 3) + self.assertEqual(dar(5, -2), -2) + + # four cases: (2 signs of a) x (2 signs of b) + self.assertEqual(dar(7, 3), 2) + self.assertEqual(dar(-7, 3), -2) + self.assertEqual(dar(7, -3), -2) + self.assertEqual(dar(-7, -3), 2) + + # ties to even - eight cases: + # (2 signs of a) x (2 signs of b) x (even / odd quotient) + self.assertEqual(dar(10, 4), 2) + self.assertEqual(dar(-10, 4), -2) + self.assertEqual(dar(10, -4), -2) + self.assertEqual(dar(-10, -4), 2) + + self.assertEqual(dar(6, 4), 2) + self.assertEqual(dar(-6, 4), -2) + self.assertEqual(dar(6, -4), -2) + self.assertEqual(dar(-6, -4), 2) + + ############################################################################# # tzinfo tests @@ -382,6 +409,10 @@ eq((-3*us) * 0.5, -2*us) eq((-5*us) * 0.5, -2*us) + # Issue #23521 + eq(td(seconds=1) * 0.123456, td(microseconds=123456)) + eq(td(seconds=1) * 0.6112295, td(microseconds=611229)) + # Division by int and float eq((3*us) / 2, 2*us) eq((5*us) / 2, 2*us) @@ -396,6 +427,9 @@ for i in range(-10, 10): eq((i*us/-3)//us, round(i/-3)) + # Issue #23521 + eq(td(seconds=1) / (1 / 0.6112295), td(microseconds=611229)) + # Issue #11576 eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998), td(0, 0, 1)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ Library ------- +- Issue #23521: Corrected pure python implementation of timedelta division. + + * Eliminated OverflowError from timedelta * float for some floats; + * Corrected rounding in timedlta true division. - Issue #21619: Popen objects no longer leave a zombie after exit in the with statement if the pipe was broken. Patch by Martin Panter. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 16:46:09 2015 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 28 Feb 2015 15:46:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20150228154609.16424.91781@psf.io> https://hg.python.org/cpython/rev/85b2aa520c84 changeset: 94789:85b2aa520c84 parent: 94788:d783132d72bc parent: 94786:5942fd9ab335 user: Alexander Belopolsky date: Sat Feb 28 10:46:00 2015 -0500 summary: merge files: Modules/_collectionsmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -788,7 +788,9 @@ while (n--) b = b->rightlink; } else { - n = (deque->leftindex + Py_SIZE(deque) - 1) / BLOCKLEN - n; + n = (Py_ssize_t)( + ((unsigned)(deque->leftindex + Py_SIZE(deque) - 1)) + / BLOCKLEN - n); b = deque->rightblock; while (n--) b = b->leftlink; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 16:46:09 2015 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 28 Feb 2015 15:46:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Fixes_=2323521=3A_Corrected_pure_python_implementation_o?= =?utf-8?q?f_timedelta_division=2E?= Message-ID: <20150228154609.87101.15910@psf.io> https://hg.python.org/cpython/rev/d783132d72bc changeset: 94788:d783132d72bc parent: 94785:eae459e35cb9 parent: 94787:8fe15bf68522 user: Alexander Belopolsky date: Sat Feb 28 10:44:47 2015 -0500 summary: Fixes #23521: Corrected pure python implementation of timedelta division. * Eliminated OverflowError from timedelta * float for some floats; * Corrected rounding in timedlta true division. files: Lib/datetime.py | 26 +++++++++++++++++-- Lib/test/datetimetester.py | 34 ++++++++++++++++++++++++++ Misc/NEWS | 4 +++ 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/Lib/datetime.py b/Lib/datetime.py --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -297,6 +297,25 @@ raise TypeError("can't compare '%s' to '%s'" % ( type(x).__name__, type(y).__name__)) +def _divide_and_round(a, b): + """divide a by b and round result to the nearest integer + + When the ratio is exactly half-way between two integers, + the even integer is returned. + """ + # Based on the reference implementation for divmod_near + # in Objects/longobject.c. + q, r = divmod(a, b) + # round up if either r / b > 0.5, or r / b == 0.5 and q is odd. + # The expression r / b > 0.5 is equivalent to 2 * r > b if b is + # positive, 2 * r < b if b negative. + r *= 2 + greater_than_half = r > b if b > 0 else r < b + if greater_than_half or r == b and q % 2 == 1: + q += 1 + + return q + class timedelta: """Represent the difference between two datetime objects. @@ -515,8 +534,9 @@ self._seconds * other, self._microseconds * other) if isinstance(other, float): + usec = self._to_microseconds() a, b = other.as_integer_ratio() - return self * a / b + return timedelta(0, 0, _divide_and_round(usec * a, b)) return NotImplemented __rmul__ = __mul__ @@ -541,10 +561,10 @@ if isinstance(other, timedelta): return usec / other._to_microseconds() if isinstance(other, int): - return timedelta(0, 0, usec / other) + return timedelta(0, 0, _divide_and_round(usec, other)) if isinstance(other, float): a, b = other.as_integer_ratio() - return timedelta(0, 0, b * usec / a) + return timedelta(0, 0, _divide_and_round(b * usec, a)) def __mod__(self, other): if isinstance(other, timedelta): diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -62,6 +62,33 @@ 'tzinfo']) self.assertEqual(names - allowed, set([])) + def test_divide_and_round(self): + if '_Fast' in str(self): + return + dar = datetime_module._divide_and_round + + self.assertEqual(dar(-10, -3), 3) + self.assertEqual(dar(5, -2), -2) + + # four cases: (2 signs of a) x (2 signs of b) + self.assertEqual(dar(7, 3), 2) + self.assertEqual(dar(-7, 3), -2) + self.assertEqual(dar(7, -3), -2) + self.assertEqual(dar(-7, -3), 2) + + # ties to even - eight cases: + # (2 signs of a) x (2 signs of b) x (even / odd quotient) + self.assertEqual(dar(10, 4), 2) + self.assertEqual(dar(-10, 4), -2) + self.assertEqual(dar(10, -4), -2) + self.assertEqual(dar(-10, -4), 2) + + self.assertEqual(dar(6, 4), 2) + self.assertEqual(dar(-6, 4), -2) + self.assertEqual(dar(6, -4), -2) + self.assertEqual(dar(-6, -4), 2) + + ############################################################################# # tzinfo tests @@ -394,6 +421,10 @@ eq((-3*us) * 0.5, -2*us) eq((-5*us) * 0.5, -2*us) + # Issue #23521 + eq(td(seconds=1) * 0.123456, td(microseconds=123456)) + eq(td(seconds=1) * 0.6112295, td(microseconds=611229)) + # Division by int and float eq((3*us) / 2, 2*us) eq((5*us) / 2, 2*us) @@ -408,6 +439,9 @@ for i in range(-10, 10): eq((i*us/-3)//us, round(i/-3)) + # Issue #23521 + eq(td(seconds=1) / (1 / 0.6112295), td(microseconds=611229)) + # Issue #11576 eq(td(999999999, 86399, 999999) - td(999999999, 86399, 999998), td(0, 0, 1)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ Library ------- +- Issue #23521: Corrected pure python implementation of timedelta division. + + * Eliminated OverflowError from timedelta * float for some floats; + * Corrected rounding in timedlta true division. - Issue #21619: Popen objects no longer leave a zombie after exit in the with statement if the pipe was broken. Patch by Martin Panter. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Feb 28 23:43:41 2015 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 28 Feb 2015 22:43:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319980=3A_Improved?= =?utf-8?q?_help=28=29_for_non-recognized_strings=2E__help=28=27=27=29_now?= Message-ID: <20150228224341.20295.84728@psf.io> https://hg.python.org/cpython/rev/4a1fe339dcf6 changeset: 94790:4a1fe339dcf6 user: Serhiy Storchaka date: Sun Mar 01 00:42:54 2015 +0200 summary: Issue #19980: Improved help() for non-recognized strings. help('') now shows the help on str. help('help') now shows the help on help(). Original patch by Mark Lawrence. files: Lib/pydoc.py | 14 ++++++++++---- Lib/test/test_pydoc.py | 5 ++++- Misc/ACKS | 1 + Misc/NEWS | 5 +++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1577,7 +1577,10 @@ if isinstance(thing, str): object = locate(thing, forceload) if not object: - raise ImportError('no Python documentation found for %r' % thing) + raise ImportError('''\ +No Python documentation found for %r. +Use help() to get the interactive help utility. +Use help(str) for help on the str class.''' % thing) return object, thing else: name = getattr(thing, '__name__', None) @@ -1848,7 +1851,10 @@ break request = replace(request, '"', '', "'", '').strip() if request.lower() in ('q', 'quit'): break - self.help(request) + if request == 'help': + self.intro() + else: + self.help(request) def getline(self, prompt): """Read one line, using input() when appropriate.""" @@ -1862,8 +1868,7 @@ def help(self, request): if type(request) is type(''): request = request.strip() - if request == 'help': self.intro() - elif request == 'keywords': self.listkeywords() + if request == 'keywords': self.listkeywords() elif request == 'symbols': self.listsymbols() elif request == 'topics': self.listtopics() elif request == 'modules': self.listmodules() @@ -1876,6 +1881,7 @@ elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) elif request: doc(request, 'Help on %s:', output=self._output) + else: doc(str, 'Help on %s:', output=self._output) elif isinstance(request, Helper): self() else: doc(request, 'Help on %s:', output=self._output) self.output.write('\n') diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -256,7 +256,10 @@ for s in expected_data_docstrings) # output pattern for missing module -missing_pattern = "no Python documentation found for '%s'" +missing_pattern = '''\ +No Python documentation found for %r. +Use help() to get the interactive help utility. +Use help(str) for help on the str class.'''.replace('\n', os.linesep) # output pattern for module with bad imports badimport_pattern = "problem in %s - ImportError: No module named %r" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -789,6 +789,7 @@ Simon Law Julia Lawall Chris Lawrence +Mark Lawrence Brian Leair Mathieu Leduc-Hamel Amandine Lee diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,11 @@ Library ------- + +- Issue #19980: Improved help() for non-recognized strings. help('') now + shows the help on str. help('help') now shows the help on help(). + Original patch by Mark Lawrence. + - Issue #23521: Corrected pure python implementation of timedelta division. * Eliminated OverflowError from timedelta * float for some floats; -- Repository URL: https://hg.python.org/cpython