From 0cc4e53d1d0af3e6b96b35858ffa4c11cd51e6ce Mon Sep 17 00:00:00 2001 From: R David Murray Date: Fri, 16 Mar 2012 22:06:08 -0400 Subject: #11780: document that email.encoders throw TypeError on multipart messages. --- Doc/library/email.encoders.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst index 5421b9f..3c32c3b 100644 --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -18,6 +18,10 @@ exactly one argument, the message object to encode. They usually extract the payload, encode it, and reset the payload to this newly encoded value. They should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. +Note that these functions are not meaningful for a multipart message. They +must be applied to individual subparts instead, and will throw a +:exc:`TypeError` if passed a message whose type is multipart. + Here are the encoding functions provided: -- cgit v0.12 From bee24df3a77a4d54817e410018556a2671d59996 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Fri, 16 Mar 2012 22:11:22 -0400 Subject: #11780: s/throw/raise/ --- Doc/library/email.encoders.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst index 3c32c3b..81d3096 100644 --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -19,7 +19,7 @@ payload, encode it, and reset the payload to this newly encoded value. They should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. Note that these functions are not meaningful for a multipart message. They -must be applied to individual subparts instead, and will throw a +must be applied to individual subparts instead, and will raise a :exc:`TypeError` if passed a message whose type is multipart. Here are the encoding functions provided: -- cgit v0.12 From e3d73544ad74eeb72e3e51794329b6bfa683ac55 Mon Sep 17 00:00:00 2001 From: Senthil Kumaran Date: Sat, 17 Mar 2012 00:37:38 -0700 Subject: explain json.dumps for non-string keys in dicts. closes issue6566. Patch contributed Kirubakaran Athmanathan --- Doc/library/json.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 546a09d..6d4497f 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -170,6 +170,14 @@ Basic Usage :class:`unicode` instance. The other arguments have the same meaning as in :func:`dump`. + .. note:: + + Keys in key/value pairs of JSON are always of the type :class:`str`. When + a dictionary is converted into JSON, all the keys of the dictionary are + coerced to strings. As a result of this, if a dictionary is convered + into JSON and then back into a dictionary, the dictionary may not equal + the original one. That is, ``loads(dumps(x)) != x`` if x has non-string + keys. .. function:: load(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]]) -- cgit v0.12 From f354f8e369e1e903d489e6dbac01f94d905dc022 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 17 Mar 2012 16:58:05 +0100 Subject: Closes #14306: clarify expensiveness of try-except and update code snippet --- Doc/faq/design.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 962b4ef..25c72db 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -297,8 +297,9 @@ use the ``join()`` function from the string module, which allows you to write :: How fast are exceptions? ------------------------ -A try/except block is extremely efficient. Actually catching an exception is -expensive. In versions of Python prior to 2.0 it was common to use this idiom:: +A try/except block is extremely efficient if no exceptions are raised. Actually +catching an exception is expensive. In versions of Python prior to 2.0 it was +common to use this idiom:: try: value = mydict[key] @@ -309,11 +310,10 @@ expensive. In versions of Python prior to 2.0 it was common to use this idiom:: This only made sense when you expected the dict to have the key almost all the time. If that wasn't the case, you coded it like this:: - if mydict.has_key(key): + if key in mydict: value = mydict[key] else: - mydict[key] = getvalue(key) - value = mydict[key] + value = mydict[key] = getvalue(key) .. note:: -- cgit v0.12 From ce54617260790a523c246a1f4080b8e82386cd20 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 17 Mar 2012 17:25:47 +0100 Subject: Closes #14342: remove out-of-date section about avoiding recursion errors. --- Doc/library/re.rst | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index e3bac50..c2ac332 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1077,28 +1077,6 @@ The equivalent regular expression would be :: (\S+) - (\d+) errors, (\d+) warnings -Avoiding recursion -^^^^^^^^^^^^^^^^^^ - -If you create regular expressions that require the engine to perform a lot of -recursion, you may encounter a :exc:`RuntimeError` exception with the message -``maximum recursion limit`` exceeded. For example, :: - - >>> s = 'Begin ' + 1000*'a very long string ' + 'end' - >>> re.match('Begin (\w| )*? end', s).end() - Traceback (most recent call last): - File "", line 1, in ? - File "/usr/local/lib/python2.5/re.py", line 132, in match - return _compile(pattern, flags).match(string) - RuntimeError: maximum recursion limit exceeded - -You can often restructure your regular expression to avoid recursion. - -Starting with Python 2.3, simple uses of the ``*?`` pattern are special-cased to -avoid recursion. Thus, the above regular expression can avoid recursion by -being recast as ``Begin [a-zA-Z0-9_ ]*?end``. As a further benefit, such -regular expressions will run faster than their recursive equivalents. - .. _search-vs-match: search() vs. match() -- cgit v0.12 From 5a607b06d6f50c6b36523ef7362ef7cea6431acd Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 17 Mar 2012 17:26:27 +0100 Subject: Closes #14343: avoid shadowing builtin input() in example code. --- Doc/library/re.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index c2ac332..cd0d204 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1123,7 +1123,7 @@ creates a phonebook. First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax: - >>> input = """Ross McFluff: 834.345.1254 155 Elm Street + >>> text = """Ross McFluff: 834.345.1254 155 Elm Street ... ... Ronald Heathmore: 892.345.3428 436 Finley Avenue ... Frank Burger: 925.541.7625 662 South Dogwood Way @@ -1137,7 +1137,7 @@ into a list with each nonempty line having its own entry: .. doctest:: :options: +NORMALIZE_WHITESPACE - >>> entries = re.split("\n+", input) + >>> entries = re.split("\n+", text) >>> entries ['Ross McFluff: 834.345.1254 155 Elm Street', 'Ronald Heathmore: 892.345.3428 436 Finley Avenue', -- cgit v0.12 From 94a105705f3c1a4eef912fbc11980cc59969a335 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 17 Mar 2012 17:31:32 +0100 Subject: Closes #14250: regex.flags has not only explicit flags but also those from the pattern --- Doc/library/re.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index cd0d204..d64604f 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -766,8 +766,8 @@ Regular Expression Objects .. attribute:: RegexObject.flags - The flags argument used when the RE object was compiled, or ``0`` if no flags - were provided. + The regex matching flags. This is a combination of the flags given to + :func:`.compile` and any ``(?...)`` inline flags in the pattern. .. attribute:: RegexObject.groups -- cgit v0.12 From b07b730e067650f8460d16b6a6f3b648ae70da33 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Sat, 17 Mar 2012 10:25:27 -0700 Subject: Issue #14346: Fix some typos in the Mac/README file. (Patch by Dionysios Kalofonos) --- Mac/README | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mac/README b/Mac/README index 522903a..6c0eb6f 100644 --- a/Mac/README +++ b/Mac/README @@ -70,7 +70,7 @@ flag to configure:: $ make $ make install -This flag can be used a framework build of python, but also with a classic +This flag can be used with a framework build of python, but also with a classic unix build. Either way you will have to build python on Mac OS X 10.4 (or later) with Xcode 2.1 (or later). You also have to install the 10.4u SDK when installing Xcode. @@ -221,8 +221,8 @@ How do I create a binary distribution? Go to the directory "Mac/OSX/BuildScript". There you'll find a script "build-installer.py" that does all the work. This will download and build -a number of 3th-party libaries, configures and builds a framework Python, -installs it, creates the installer pacakge files and then packs this in a +a number of 3rd-party libaries, configures and builds a framework Python, +installs it, creates the installer package files and then packs this in a DMG image. The script will build a universal binary, you'll therefore have to run this @@ -258,8 +258,8 @@ architectures. Temporarily move ``/usr/local`` aside to finish the build. Uninstalling a framework install, including the binary installer ================================================================ -Uninstalling a framework can be done by manually removing all bits that got installed, -that's true for both installations from source and installations using the binary installer. +Uninstalling a framework can be done by manually removing all bits that got installed. +That's true for both installations from source and installations using the binary installer. Sadly enough OSX does not have a central uninstaller. The main bit of a framework install is the framework itself, installed in -- cgit v0.12 From 5c2689a00c60fc0584baa1597998d40b2d6cfbed Mon Sep 17 00:00:00 2001 From: R David Murray Date: Sat, 17 Mar 2012 16:44:16 -0400 Subject: #14333: fix test_queue so it can be run via standard unittest test discovery. --- Lib/test/test_queue.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py index 0b38e7e..f821db6 100644 --- a/Lib/test/test_queue.py +++ b/Lib/test/test_queue.py @@ -79,7 +79,7 @@ class BlockingTestMixin: self.fail("trigger thread ended but event never set") -class BaseQueueTest(unittest.TestCase, BlockingTestMixin): +class BaseQueueTest(BlockingTestMixin): def setUp(self): self.cum = 0 self.cumlock = threading.Lock() @@ -191,13 +191,13 @@ class BaseQueueTest(unittest.TestCase, BlockingTestMixin): self.simple_queue_test(q) -class QueueTest(BaseQueueTest): +class QueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.Queue -class LifoQueueTest(BaseQueueTest): +class LifoQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.LifoQueue -class PriorityQueueTest(BaseQueueTest): +class PriorityQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.PriorityQueue -- cgit v0.12 From 2875b5b2946add659ad7ca1df2a77e5d4a7101c8 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 17 Mar 2012 18:16:58 -0400 Subject: Update Docs and NEWS for 2.6.8rc2. --- Lib/pydoc_topics.py | 2 +- Misc/NEWS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc_topics.py b/Lib/pydoc_topics.py index 6e7900e..1392d28 100644 --- a/Lib/pydoc_topics.py +++ b/Lib/pydoc_topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Thu Feb 23 10:54:32 2012 +# Autogenerated by Sphinx on Sat Mar 17 14:18:25 2012 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\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to 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\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack 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\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 is recursively defined as\nfollows.\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 object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets. (This rule is relaxed as of\n Python 1.5; in earlier versions, the object had to be a tuple.\n Since strings are sequences, an assignment like ``a, b = "xy"`` is\n now legal as long as the string has the right length.)\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`` statement in the\n current code block: the name is bound to the object in the current\n local namespace.\n\n * Otherwise: the name is bound to the object in the current global\n namespace.\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 square\n brackets: The object must be an iterable with the same number of\n 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\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the 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 a plain integer. If it is negative, the\n sequence\'s length is added to it. The resulting value must be a\n nonnegative integer less than the sequence\'s length, and the\n sequence is asked to assign the assigned object to its item with\n that index. If the index is out of range, ``IndexError`` is raised\n (assignment to a subscripted sequence cannot add new items to a\n 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* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to (small) integers. If either\n 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\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\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is 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': 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 in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', diff --git a/Misc/NEWS b/Misc/NEWS index 5337e40..a8e813d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ Python News What's New in Python 2.6.8 rc 2? ================================ -*Release date: 2012-XX-XX* +*Release date: 2012-03-17* Library ------- -- cgit v0.12 From bd371a4cbb0cdf4fb2b726134747c3ea062c5321 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 17 Mar 2012 18:19:15 -0400 Subject: Bump to 2.6.8rc2 --- Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/RPM/python-2.6.spec | 2 +- README | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 8cf5c88..955e650 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 6 #define PY_MICRO_VERSION 8 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "2.6.8rc1" +#define PY_VERSION "2.6.8rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository) */ diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py index 279e17a..141b377 100644 --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -22,5 +22,5 @@ __revision__ = "$Id$" # #--start constants-- -__version__ = "2.6.8rc1" +__version__ = "2.6.8rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py index c656bc2..4acb814 100644 --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1 +1 @@ -IDLE_VERSION = "2.6.8rc1" +IDLE_VERSION = "2.6.8rc2" diff --git a/Misc/RPM/python-2.6.spec b/Misc/RPM/python-2.6.spec index 69132d5..41471bb 100644 --- a/Misc/RPM/python-2.6.spec +++ b/Misc/RPM/python-2.6.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 2.6.8rc1 +%define version 2.6.8rc2 %define libvers 2.6 #--end constants-- %define release 1pydotorg diff --git a/README b/README index c796141..5656285 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 2.6.8 rc 1 +This is Python version 2.6.8 rc 2 ================================= Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -- cgit v0.12 From b1abc08a29e15dfb448cb22053defec608739f77 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 17 Mar 2012 18:19:42 -0400 Subject: Added tag v2.6.8rc2 for changeset 1d1b7b9fad48 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 7b61eac..215ca08 100644 --- a/.hgtags +++ b/.hgtags @@ -139,3 +139,4 @@ e189dc8fd66154ef46d9cd22584d56669b544ca3 v2.6.6rc2 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6 caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 +1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 -- cgit v0.12 From 9636e462d825a9d2980474e1d57e88efd19111f7 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 17 Mar 2012 18:34:05 -0400 Subject: Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 215ca08..90582bf 100644 --- a/.hgtags +++ b/.hgtags @@ -140,3 +140,4 @@ e189dc8fd66154ef46d9cd22584d56669b544ca3 v2.6.6rc2 caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 +bd9e1a02e3e329fa7b6da06113090a401909c4ea v2.6.8rc2 -- cgit v0.12 From 222ac8c98f4885e6bb9ae4d05bf98bf5a47affc1 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 18 Mar 2012 07:31:17 +0100 Subject: Remove duplicate hgtags entries for 2.6.8rc{1,2}. --- .hgtags | 2 -- 1 file changed, 2 deletions(-) diff --git a/.hgtags b/.hgtags index 90582bf..bf95bf6 100644 --- a/.hgtags +++ b/.hgtags @@ -138,6 +138,4 @@ c1dc9e7986a2a8e1070ec7bee748520febef382e v2.6.6rc1 e189dc8fd66154ef46d9cd22584d56669b544ca3 v2.6.6rc2 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6 caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 -5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 -bd9e1a02e3e329fa7b6da06113090a401909c4ea v2.6.8rc2 -- cgit v0.12 From 28b22d0d15ea3b816f11f6c577150c9fbbeccbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Sun, 18 Mar 2012 23:46:56 +0100 Subject: Add 2.7.3rc2 uuid --- Tools/msi/uuids.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py index 94d8800..cf5bfd2 100644 --- a/Tools/msi/uuids.py +++ b/Tools/msi/uuids.py @@ -56,6 +56,7 @@ product_codes = { '2.7.2121':'{B2E1F06E-F719-4786-972A-488A336EB2A0}', # 2.7.2rc1 '2.7.2150':'{2E295B5B-1AD4-4d36-97C2-A316084722CF}', # 2.7.2 '2.7.3121':'{1ACB88BF-1425-4f11-B664-6C89A3D7699C}', # 2.7.3rc1 + '2.7.3122':'{B12311BE-6364-4b2a-A49A-551EEE10F3E4}', # 2.7.3rc2 '2.7.3150':'{C0C31BCC-56FB-42a7-8766-D29E1BD74C7C}', # 2.7.3 '2.7.4121':'{47F45F45-72D7-4e54-AF41-26767EDE95CF}', # 2.7.4rc1 '2.7.4150':'{84ADC96C-B7E0-4938-9D6E-2B640D5DA224}', # 2.7.4 -- cgit v0.12 From fcdf04becc33add8bdc791466c7e96847f5335fc Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 18 Mar 2012 16:07:10 -0700 Subject: Fixes Issue #14331: Use significantly less stack space when importing modules by allocating path buffers on the heap instead of the stack. --- Misc/NEWS | 3 ++ Python/import.c | 126 ++++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 471051f..0e12494 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ What's New in Python 2.7.4 Core and Builtins ----------------- +- Issue #14331: Use significantly less stack space when importing modules by + allocating path buffers on the heap instead of the stack. + - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not passed strings. Also fix segfaults in the __getattribute__ and __setattr__ methods of old-style classes. diff --git a/Python/import.c b/Python/import.c index 127b807..4d8a610 100644 --- a/Python/import.c +++ b/Python/import.c @@ -996,7 +996,7 @@ load_source_module(char *name, char *pathname, FILE *fp) { struct stat st; FILE *fpc; - char buf[MAXPATHLEN+1]; + char *buf; char *cpathname; PyCodeObject *co; PyObject *m; @@ -1015,6 +1015,10 @@ load_source_module(char *name, char *pathname, FILE *fp) */ st.st_mtime &= 0xFFFFFFFF; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } cpathname = make_compiled_pathname(pathname, buf, (size_t)MAXPATHLEN + 1); if (cpathname != NULL && @@ -1022,9 +1026,9 @@ load_source_module(char *name, char *pathname, FILE *fp) co = read_compiled_module(cpathname, fpc); fclose(fpc); if (co == NULL) - return NULL; + goto error_exit; if (update_compiled_module(co, pathname) < 0) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # precompiled from %s\n", name, cpathname); @@ -1033,7 +1037,7 @@ load_source_module(char *name, char *pathname, FILE *fp) else { co = parse_source_module(pathname, fp); if (co == NULL) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # from %s\n", name, pathname); @@ -1046,7 +1050,12 @@ load_source_module(char *name, char *pathname, FILE *fp) m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname); Py_DECREF(co); + PyMem_FREE(buf); return m; + +error_exit: + PyMem_FREE(buf); + return NULL; } @@ -1066,7 +1075,7 @@ load_package(char *name, char *pathname) PyObject *file = NULL; PyObject *path = NULL; int err; - char buf[MAXPATHLEN+1]; + char *buf = NULL; FILE *fp = NULL; struct filedescr *fdp; @@ -1088,8 +1097,13 @@ load_package(char *name, char *pathname) err = PyDict_SetItemString(d, "__path__", path); if (err != 0) goto error; + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } buf[0] = '\0'; - fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL); + fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL); if (fdp == NULL) { if (PyErr_ExceptionMatches(PyExc_ImportError)) { PyErr_Clear(); @@ -1107,6 +1121,8 @@ load_package(char *name, char *pathname) error: m = NULL; cleanup: + if (buf) + PyMem_FREE(buf); Py_XDECREF(path); Py_XDECREF(file); return m; @@ -1235,7 +1251,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, static struct filedescr fd_frozen = {"", "", PY_FROZEN}; static struct filedescr fd_builtin = {"", "", C_BUILTIN}; static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; - char name[MAXPATHLEN+1]; + char *name; #if defined(PYOS_OS2) size_t saved_len; size_t saved_namelen; @@ -1249,6 +1265,10 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, "module name is too long"); return NULL; } + name = PyMem_MALLOC(MAXPATHLEN+1); + if (name == NULL) { + return PyErr_NoMemory(); + } strcpy(name, subname); /* sys.meta_path import hook */ @@ -1260,7 +1280,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, PyErr_SetString(PyExc_RuntimeError, "sys.meta_path must be a list of " "import hooks"); - return NULL; + goto error_exit; } Py_INCREF(meta_path); /* zap guard */ npath = PyList_Size(meta_path); @@ -1273,12 +1293,13 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, path : Py_None); if (loader == NULL) { Py_DECREF(meta_path); - return NULL; /* true error */ + goto error_exit; /* true error */ } if (loader != Py_None) { /* a loader was found */ *p_loader = loader; Py_DECREF(meta_path); + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1292,7 +1313,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) { PyErr_SetString(PyExc_ImportError, "full frozen module name too long"); - return NULL; + goto error_exit; } strcpy(buf, PyString_AsString(path)); strcat(buf, "."); @@ -1300,19 +1321,22 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, strcpy(name, buf); if (find_frozen(name) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } PyErr_Format(PyExc_ImportError, "No frozen submodule named %.200s", name); - return NULL; + goto error_exit; } if (path == NULL) { if (is_builtin(name)) { strcpy(buf, name); + PyMem_FREE(name); return &fd_builtin; } if ((find_frozen(name)) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } @@ -1320,6 +1344,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); if (fp != NULL) { *p_fp = fp; + PyMem_FREE(name); return fdp; } #endif @@ -1328,7 +1353,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (path == NULL || !PyList_Check(path)) { PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list of directory names"); - return NULL; + goto error_exit; } path_hooks = PySys_GetObject("path_hooks"); @@ -1336,14 +1361,14 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, PyErr_SetString(PyExc_RuntimeError, "sys.path_hooks must be a list of " "import hooks"); - return NULL; + goto error_exit; } path_importer_cache = PySys_GetObject("path_importer_cache"); if (path_importer_cache == NULL || !PyDict_Check(path_importer_cache)) { PyErr_SetString(PyExc_RuntimeError, "sys.path_importer_cache must be a dict"); - return NULL; + goto error_exit; } npath = PyList_Size(path); @@ -1352,13 +1377,13 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, PyObject *copy = NULL; PyObject *v = PyList_GetItem(path, i); if (!v) - return NULL; + goto error_exit; #ifdef Py_USING_UNICODE if (PyUnicode_Check(v)) { copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v), PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL); if (copy == NULL) - return NULL; + goto error_exit; v = copy; } else @@ -1384,7 +1409,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, path_hooks, v); if (importer == NULL) { Py_XDECREF(copy); - return NULL; + goto error_exit; } /* Note: importer is a borrowed reference */ if (importer != Py_None) { @@ -1394,10 +1419,11 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, "s", fullname); Py_XDECREF(copy); if (loader == NULL) - return NULL; /* error */ + goto error_exit; /* error */ if (loader != Py_None) { /* a loader was found */ *p_loader = loader; + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1421,6 +1447,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, case_ok(buf, len, namelen, name)) { /* case matches */ if (find_init_module(buf)) { /* and has __init__.py */ Py_XDECREF(copy); + PyMem_FREE(name); return &fd_package; } else { @@ -1431,7 +1458,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (PyErr_Warn(PyExc_ImportWarning, warnstr)) { Py_XDECREF(copy); - return NULL; + goto error_exit; } } } @@ -1506,10 +1533,15 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (fp == NULL) { PyErr_Format(PyExc_ImportError, "No module named %.200s", name); - return NULL; + goto error_exit; } *p_fp = fp; + PyMem_FREE(name); return fdp; + +error_exit: + PyMem_FREE(name); + return NULL; } /* Helpers for main.c @@ -2116,7 +2148,7 @@ static PyObject * import_module_level(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) { - char buf[MAXPATHLEN+1]; + char *buf; Py_ssize_t buflen = 0; PyObject *parent, *head, *next, *tail; @@ -2130,14 +2162,18 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, return NULL; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } parent = get_parent(globals, buf, &buflen, level); if (parent == NULL) - return NULL; + goto error_exit; head = load_next(parent, level < 0 ? Py_None : parent, &name, buf, &buflen); if (head == NULL) - return NULL; + goto error_exit; tail = head; Py_INCREF(tail); @@ -2146,7 +2182,7 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, Py_DECREF(tail); if (next == NULL) { Py_DECREF(head); - return NULL; + goto error_exit; } tail = next; } @@ -2158,7 +2194,7 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, Py_DECREF(head); PyErr_SetString(PyExc_ValueError, "Empty module name"); - return NULL; + goto error_exit; } if (fromlist != NULL) { @@ -2168,16 +2204,22 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, if (fromlist == NULL) { Py_DECREF(tail); + PyMem_FREE(buf); return head; } Py_DECREF(head); if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) { Py_DECREF(tail); - return NULL; + goto error_exit; } + PyMem_FREE(buf); return tail; + +error_exit: + PyMem_FREE(buf); + return NULL; } PyObject * @@ -2567,7 +2609,7 @@ import_submodule(PyObject *mod, char *subname, char *fullname) } else { PyObject *path, *loader = NULL; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; @@ -2582,11 +2624,16 @@ import_submodule(PyObject *mod, char *subname, char *fullname) } } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); if (fdp == NULL) { + PyMem_FREE(buf); if (!PyErr_ExceptionMatches(PyExc_ImportError)) return NULL; PyErr_Clear(); @@ -2601,6 +2648,7 @@ import_submodule(PyObject *mod, char *subname, char *fullname) Py_XDECREF(m); m = NULL; } + PyMem_FREE(buf); } return m; @@ -2618,7 +2666,7 @@ PyImport_ReloadModule(PyObject *m) PyObject *modules = PyImport_GetModuleDict(); PyObject *path = NULL, *loader = NULL, *existing_m = NULL; char *name, *subname; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; PyObject *newm; @@ -2678,6 +2726,11 @@ PyImport_ReloadModule(PyObject *m) if (path == NULL) PyErr_Clear(); } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + Py_XDECREF(path); + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); @@ -2685,6 +2738,7 @@ PyImport_ReloadModule(PyObject *m) if (fdp == NULL) { Py_XDECREF(loader); imp_modules_reloading_clear(); + PyMem_FREE(buf); return NULL; } @@ -2702,6 +2756,7 @@ PyImport_ReloadModule(PyObject *m) PyDict_SetItemString(modules, name, m); } imp_modules_reloading_clear(); + PyMem_FREE(buf); return newm; } @@ -2832,19 +2887,27 @@ call_find_module(char *name, PyObject *path) extern int fclose(FILE *); PyObject *fob, *ret; struct filedescr *fdp; - char pathname[MAXPATHLEN+1]; + char *pathname; FILE *fp = NULL; + pathname = PyMem_MALLOC(MAXPATHLEN+1); + if (pathname == NULL) { + return PyErr_NoMemory(); + } pathname[0] = '\0'; if (path == Py_None) path = NULL; fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); - if (fdp == NULL) + if (fdp == NULL) { + PyMem_FREE(pathname); return NULL; + } if (fp != NULL) { fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose); - if (fob == NULL) + if (fob == NULL) { + PyMem_FREE(pathname); return NULL; + } } else { fob = Py_None; @@ -2853,6 +2916,7 @@ call_find_module(char *name, PyObject *path) ret = Py_BuildValue("Os(ssi)", fob, pathname, fdp->suffix, fdp->mode, fdp->type); Py_DECREF(fob); + PyMem_FREE(pathname); return ret; } -- cgit v0.12