diff -r befd56673c80 -r 65c3af0d283b Doc/c-api/import.rst --- a/Doc/c-api/import.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/c-api/import.rst Sat May 19 17:01:25 2012 -0400 @@ -30,13 +30,13 @@ .. c:function:: PyObject* PyImport_ImportModuleNoBlock(const char *name) - This function is a deprecated alias of :c:func:`PyImport_ImportModule`. - - .. versionchanged:: 3.3 - This function used to fail immediately when the import lock was held - by another thread. In Python 3.3 though, the locking scheme switched - to per-module locks for most purposes, so this function's special - behaviour isn't needed anymore. + This version of :c:func:`PyImport_ImportModule` does not block. It's intended + to be used in C functions that import other modules to execute a function. + The import may block if another thread holds the import lock. The function + :c:func:`PyImport_ImportModuleNoBlock` never blocks. It first tries to fetch + the module from sys.modules and falls back to :c:func:`PyImport_ImportModule` + unless the lock is held, in which case the function will raise an + :exc:`ImportError`. .. c:function:: PyObject* PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist) diff -r befd56673c80 -r 65c3af0d283b Doc/library/__future__.rst --- a/Doc/library/__future__.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/__future__.rst Sat May 19 17:01:25 2012 -0400 @@ -75,7 +75,7 @@ | division | 2.2.0a2 | 3.0 | :pep:`238`: | | | | | *Changing the Division Operator* | +------------------+-------------+--------------+---------------------------------------------+ -| absolute_import | 2.5.0a1 | 3.0 | :pep:`328`: | +| absolute_import | 2.5.0a1 | 2.7 | :pep:`328`: | | | | | *Imports: Multi-Line and Absolute/Relative* | +------------------+-------------+--------------+---------------------------------------------+ | with_statement | 2.5.0a1 | 2.6 | :pep:`343`: | diff -r befd56673c80 -r 65c3af0d283b Doc/library/functions.rst --- a/Doc/library/functions.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/functions.rst Sat May 19 17:01:25 2012 -0400 @@ -1324,12 +1324,10 @@ Accordingly, :func:`super` is undefined for implicit lookups using statements or operators such as ``super()[name]``. - Also note that, aside from the zero argument form, :func:`super` is not - limited to use inside methods. The two argument form specifies the - arguments exactly and makes the appropriate references. The zero - argument form only works inside a class definition, as the compiler fills - in the necessary details to correctly retrieve the class being defined, - as well as accessing the current instance for ordinary methods. + Also note that :func:`super` is not limited to use inside methods. The two + argument form specifies the arguments exactly and makes the appropriate + references. The zero argument form automatically searches the stack frame + for the class (``__class__``) and the first argument. For practical suggestions on how to design cooperative classes using :func:`super`, see `guide to using super() diff -r befd56673c80 -r 65c3af0d283b Doc/library/imp.rst --- a/Doc/library/imp.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/imp.rst Sat May 19 17:01:25 2012 -0400 @@ -107,6 +107,37 @@ in ``sys.modules``. +.. function:: lock_held() + + Return ``True`` if the import lock is currently held, else ``False``. On + platforms without threads, always return ``False``. + + On platforms with threads, a thread executing an import holds an internal lock + until the import is complete. This lock blocks other threads from doing an + import until the original import completes, which in turn prevents other threads + from seeing incomplete module objects constructed by the original thread while + in the process of completing its import (and the imports, if any, triggered by + that). + + +.. function:: acquire_lock() + + Acquire the interpreter's import lock for the current thread. This lock should + be used by import hooks to ensure thread-safety when importing modules. + + Once a thread has acquired the import lock, the same thread may acquire it + again without blocking; the thread must release it once for each time it has + acquired it. + + On platforms without threads, this function does nothing. + + +.. function:: release_lock() + + Release the interpreter's import lock. On platforms without threads, this + function does nothing. + + .. function:: reload(module) Reload a previously imported *module*. The argument must be a module object, so @@ -204,49 +235,6 @@ magic number, as returned by :func:`get_magic`. -The following functions help interact with the import system's internal -locking mechanism. Locking semantics of imports are an implementation -detail which may vary from release to release. However, Python ensures -that circular imports work without any deadlocks. - -.. versionchanged:: 3.3 - In Python 3.3, the locking scheme has changed to per-module locks for - the most part. A global import lock is kept for some critical tasks, - such as initializing the per-module locks. - - -.. function:: lock_held() - - Return ``True`` if the global import lock is currently held, else - ``False``. On platforms without threads, always return ``False``. - - On platforms with threads, a thread executing an import first holds a - global import lock, then sets up a per-module lock for the rest of the - import. This blocks other threads from importing the same module until - the original import completes, preventing other threads from seeing - incomplete module objects constructed by the original thread. An - exception is made for circular imports, which by construction have to - expose an incomplete module object at some point. - -.. function:: acquire_lock() - - Acquire the interpreter's global import lock for the current thread. - This lock should be used by import hooks to ensure thread-safety when - importing modules. - - Once a thread has acquired the import lock, the same thread may acquire it - again without blocking; the thread must release it once for each time it has - acquired it. - - On platforms without threads, this function does nothing. - - -.. function:: release_lock() - - Release the interpreter's global import lock. On platforms without - threads, this function does nothing. - - The following constants with integer values, defined in this module, are used to indicate the search result of :func:`find_module`. diff -r befd56673c80 -r 65c3af0d283b Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/multiprocessing.rst Sat May 19 17:01:25 2012 -0400 @@ -120,7 +120,9 @@ print(q.get()) # prints "[42, None, 'hello']" p.join() - Queues are thread and process safe. + Queues are thread and process safe, but note that they must never + be instantiated as a side effect of importing a module: this can lead + to a deadlock! (see :ref:`threaded-imports`) **Pipes** diff -r befd56673c80 -r 65c3af0d283b Doc/library/textwrap.rst --- a/Doc/library/textwrap.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/textwrap.rst Sat May 19 17:01:25 2012 -0400 @@ -107,15 +107,6 @@ expanded to spaces using the :meth:`expandtabs` method of *text*. - .. attribute:: tabsize - - (default: ``8``) If :attr:`expand_tabs` is true, then all tab characters - in *text* will be expanded to zero or more spaces, depending on the - current column and the given tab size. - - .. versionadded:: 3.3 - - .. attribute:: replace_whitespace (default: ``True``) If true, each whitespace character (as defined by diff -r befd56673c80 -r 65c3af0d283b Doc/library/threading.rst --- a/Doc/library/threading.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/threading.rst Sat May 19 17:01:25 2012 -0400 @@ -426,12 +426,15 @@ Acquire a lock, blocking or non-blocking. - When invoked with the *blocking* argument set to ``True`` (the default), - block until the lock is unlocked, then set it to locked and return ``True``. + When invoked without arguments, block until the lock is unlocked, then set it to + locked, and return true. - When invoked with the *blocking* argument set to ``False``, do not block. - If a call with *blocking* set to ``True`` would block, return ``False`` - immediately; otherwise, set the lock to locked and return ``True``. + When invoked with the *blocking* argument set to true, do the same thing as when + called without arguments, and return true. + + When invoked with the *blocking* argument set to false, do not block. If a call + without an argument would block, return false immediately; otherwise, do the + same thing as when called without arguments, and return true. When invoked with the floating-point *timeout* argument set to a positive value, block for at most the number of seconds specified by *timeout* @@ -996,3 +999,27 @@ Currently, :class:`Lock`, :class:`RLock`, :class:`Condition`, :class:`Semaphore`, and :class:`BoundedSemaphore` objects may be used as :keyword:`with` statement context managers. + + +.. _threaded-imports: + +Importing in threaded code +-------------------------- + +While the import machinery is thread-safe, there are two key restrictions on +threaded imports due to inherent limitations in the way that thread-safety is +provided: + +* Firstly, other than in the main module, an import should not have the + side effect of spawning a new thread and then waiting for that thread in + any way. Failing to abide by this restriction can lead to a deadlock if + the spawned thread directly or indirectly attempts to import a module. +* Secondly, all import attempts must be completed before the interpreter + starts shutting itself down. This can be most easily achieved by only + performing imports from non-daemon threads created through the threading + module. Daemon threads and threads created directly with the thread + module will require some other form of synchronization to ensure they do + not attempt imports after system shutdown has commenced. Failure to + abide by this restriction will lead to intermittent exceptions and + crashes during interpreter shutdown (as the late imports attempt to + access machinery which is no longer in a valid state). diff -r befd56673c80 -r 65c3af0d283b Doc/library/time.rst --- a/Doc/library/time.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/time.rst Sat May 19 17:01:25 2012 -0400 @@ -62,9 +62,9 @@ the units in which their value or argument is expressed. E.g. on most Unix systems, the clock "ticks" only 50 or 100 times a second. -* On the other hand, the precision of :func:`.time` and :func:`sleep` is better +* On the other hand, the precision of :func:`time` and :func:`sleep` is better than their Unix equivalents: times are expressed as floating point numbers, - :func:`.time` returns the most accurate time available (using Unix + :func:`time` returns the most accurate time available (using Unix :c:func:`gettimeofday` where available), and :func:`sleep` will accept a time with a nonzero fraction (Unix :c:func:`select` is used to implement this, where available). @@ -256,7 +256,7 @@ Convert a time expressed in seconds since the epoch to a string representing local time. If *secs* is not provided or :const:`None`, the current time as - returned by :func:`.time` is used. ``ctime(secs)`` is equivalent to + returned by :func:`time` is used. ``ctime(secs)`` is equivalent to ``asctime(localtime(secs))``. Locale information is not used by :func:`ctime`. @@ -284,7 +284,7 @@ Convert a time expressed in seconds since the epoch to a :class:`struct_time` in UTC in which the dst flag is always zero. If *secs* is not provided or - :const:`None`, the current time as returned by :func:`.time` is used. Fractions + :const:`None`, the current time as returned by :func:`time` is used. Fractions of a second are ignored. See above for a description of the :class:`struct_time` object. See :func:`calendar.timegm` for the inverse of this function. @@ -293,7 +293,7 @@ .. function:: localtime([secs]) Like :func:`gmtime` but converts to local time. If *secs* is not provided or - :const:`None`, the current time as returned by :func:`.time` is used. The dst + :const:`None`, the current time as returned by :func:`time` is used. The dst flag is set to ``1`` when DST applies to the given time. @@ -302,7 +302,7 @@ This is the inverse function of :func:`localtime`. Its argument is the :class:`struct_time` or full 9-tuple (since the dst flag is needed; use ``-1`` as the dst flag if it is unknown) which expresses the time in *local* time, not - UTC. It returns a floating point number, for compatibility with :func:`.time`. + UTC. It returns a floating point number, for compatibility with :func:`time`. If the input value cannot be represented as a valid time, either :exc:`OverflowError` or :exc:`ValueError` will be raised (which depends on whether the invalid value is caught by Python or the underlying C libraries). diff -r befd56673c80 -r 65c3af0d283b Doc/library/types.rst --- a/Doc/library/types.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/library/types.rst Sat May 19 17:01:25 2012 -0400 @@ -1,5 +1,5 @@ -:mod:`types` --- Dynamic type creation and names for built-in types -=================================================================== +:mod:`types` --- Names for built-in types +========================================= .. module:: types :synopsis: Names for built-in types. @@ -8,69 +8,20 @@ -------------- -This module defines utility function to assist in dynamic creation of -new types. +This module defines names for some object types that are used by the standard +Python interpreter, but not exposed as builtins like :class:`int` or +:class:`str` are. Also, it does not include some of the types that arise +transparently during processing such as the ``listiterator`` type. -It also defines names for some object types that are used by the standard -Python interpreter, but not exposed as builtins like :class:`int` or -:class:`str` are. +Typical use is for :func:`isinstance` or :func:`issubclass` checks. - -Dynamic Type Creation ---------------------- - -.. function:: new_class(name, bases=(), kwds=None, exec_body=None) - - Creates a class object dynamically using the appropriate metaclass. - - The arguments are the components that make up a class definition: the - class name, the base classes (in order), the keyword arguments (such as - ``metaclass``) and the callback function to populate the class namespace. - - The *exec_body* callback should accept the class namespace as its sole - argument and update the namespace directly with the class contents. - -.. function:: prepare_class(name, bases=(), kwds=None) - - Calculates the appropriate metaclass and creates the class namespace. - - The arguments are the components that make up a class definition: the - class name, the base classes (in order) and the keyword arguments (such as - ``metaclass``). - - The return value is a 3-tuple: ``metaclass, namespace, kwds`` - - *metaclass* is the appropriate metaclass - *namespace* is the prepared class namespace - *kwds* is an updated copy of the passed in *kwds* argument with any - ``'metaclass'`` entry removed. If no *kwds* argument is passed in, this - will be an empty dict. - - -.. seealso:: - - :pep:`3115` - Metaclasses in Python 3000 - Introduced the ``__prepare__`` namespace hook - - -Standard Interpreter Types --------------------------- - -This module provides names for many of the types that are required to -implement a Python interpreter. It deliberately avoids including some of -the types that arise only incidentally during processing such as the -``listiterator`` type. - -Typical use is of these names is for :func:`isinstance` or -:func:`issubclass` checks. - -Standard names are defined for the following types: +The module defines the following names: .. data:: FunctionType LambdaType - The type of user-defined functions and functions created by - :keyword:`lambda` expressions. + The type of user-defined functions and functions created by :keyword:`lambda` + expressions. .. data:: GeneratorType diff -r befd56673c80 -r 65c3af0d283b Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/reference/datamodel.rst Sat May 19 17:01:25 2012 -0400 @@ -1550,115 +1550,53 @@ Customizing class creation -------------------------- -By default, classes are constructed using :func:`type`. The class body is -executed in a new namespace and the class name is bound locally to the -result of ``type(name, bases, namespace)``. +By default, classes are constructed using :func:`type`. A class definition is +read into a separate namespace and the value of class name is bound to the +result of ``type(name, bases, dict)``. -The class creation process can be customised by passing the ``metaclass`` -keyword argument in the class definition line, or by inheriting from an -existing class that included such an argument. In the following example, -both ``MyClass`` and ``MySubclass`` are instances of ``Meta``:: +When the class definition is read, if a callable ``metaclass`` keyword argument +is passed after the bases in the class definition, the callable given will be +called instead of :func:`type`. If other keyword arguments are passed, they +will also be passed to the metaclass. This allows classes or functions to be +written which monitor or alter the class creation process: - class Meta(type): - pass +* Modifying the class dictionary prior to the class being created. - class MyClass(metaclass=Meta): - pass +* Returning an instance of another class -- essentially performing the role of a + factory function. - class MySubclass(MyClass): - pass +These steps will have to be performed in the metaclass's :meth:`__new__` method +-- :meth:`type.__new__` can then be called from this method to create a class +with different properties. This example adds a new element to the class +dictionary before creating the class:: -Any other keyword arguments that are specified in the class definition are -passed through to all metaclass operations described below. + class metacls(type): + def __new__(mcs, name, bases, dict): + dict['foo'] = 'metacls was here' + return type.__new__(mcs, name, bases, dict) -When a class definition is executed, the following steps occur: +You can of course also override other class methods (or add new methods); for +example defining a custom :meth:`__call__` method in the metaclass allows custom +behavior when the class is called, e.g. not always creating a new instance. -* the appropriate metaclass is determined -* the class namespace is prepared -* the class body is executed -* the class object is created +If the metaclass has a :meth:`__prepare__` attribute (usually implemented as a +class or static method), it is called before the class body is evaluated with +the name of the class and a tuple of its bases for arguments. It should return +an object that supports the mapping interface that will be used to store the +namespace of the class. The default is a plain dictionary. This could be used, +for example, to keep track of the order that class attributes are declared in by +returning an ordered dictionary. -Determining the appropriate metaclass -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The appropriate metaclass is determined by the following precedence rules: -The appropriate metaclass for a class definition is determined as follows: +* If the ``metaclass`` keyword argument is passed with the bases, it is used. -* if no bases and no explicit metaclass are given, then :func:`type` is used -* if an explicit metaclass is given and it is *not* an instance of - :func:`type`, then it is used directly as the metaclass -* if an instance of :func:`type` is given as the explicit metaclass, or - bases are defined, then the most derived metaclass is used +* Otherwise, if there is at least one base class, its metaclass is used. -The most derived metaclass is selected from the explicitly specified -metaclass (if any) and the metaclasses (i.e. ``type(cls)``) of all specified -base classes. The most derived metaclass is one which is a subtype of *all* -of these candidate metaclasses. If none of the candidate metaclasses meets -that criterion, then the class definition will fail with ``TypeError``. - - -Preparing the class namespace -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Once the appropriate metaclass has been identified, then the class namespace -is prepared. If the metaclass has a ``__prepare__`` attribute, it is called -as ``namespace = metaclass.__prepare__(name, bases, **kwds)`` (where the -additional keyword arguments, if any, come from the class definition). - -If the metaclass has no ``__prepare__`` attribute, then the class namespace -is initialised as an empty :func:`dict` instance. - -.. seealso:: - - :pep:`3115` - Metaclasses in Python 3000 - Introduced the ``__prepare__`` namespace hook - - -Executing the class body -^^^^^^^^^^^^^^^^^^^^^^^^ - -The class body is executed (approximately) as -``exec(body, globals(), namespace)``. The key difference from a normal -call to :func:`exec` is that lexical scoping allows the class body (including -any methods) to reference names from the current and outer scopes when the -class definition occurs inside a function. - -However, even when the class definition occurs inside the function, methods -defined inside the class still cannot see names defined at the class scope. -Class variables must be accessed through the first parameter of instance or -class methods, and cannot be accessed at all from static methods. - - -Creating the class object -^^^^^^^^^^^^^^^^^^^^^^^^^ - -Once the class namespace has been populated by executing the class body, -the class object is created by calling -``metaclass(name, bases, namespace, **kwds)`` (the additional keywords -passed here are the same as those passed to ``__prepate__``). - -This class object is the one that will be referenced by the zero-argument -form of :func:`super`. ``__class__`` is an implicit closure reference -created by the compiler if any methods in a class body refer to either -``__class__`` or ``super``. This allows the zero argument form of -:func:`super` to correctly identify the class being defined based on -lexical scoping, while the class or instance that was used to make the -current call is identified based on the first argument passed to the method. - -After the class object is created, any class decorators included in the -function definition are invoked and the resulting object is bound in the -local namespace to the name of the class. - -.. seealso:: - - :pep:`3135` - New super - Describes the implicit ``__class__`` closure reference - - -Metaclass example -^^^^^^^^^^^^^^^^^ +* Otherwise, the default metaclass (:class:`type`) is used. The potential uses for metaclasses are boundless. Some ideas that have been -explored include logging, interface checking, automatic delegation, automatic +explored including logging, interface checking, automatic delegation, automatic property creation, proxies, frameworks, and automatic resource locking/synchronization. @@ -1671,9 +1609,9 @@ def __prepare__(metacls, name, bases, **kwds): return collections.OrderedDict() - def __new__(cls, name, bases, namespace, **kwds): - result = type.__new__(cls, name, bases, dict(namespace)) - result.members = tuple(namespace) + def __new__(cls, name, bases, classdict): + result = type.__new__(cls, name, bases, dict(classdict)) + result.members = tuple(classdict) return result class A(metaclass=OrderedClass): diff -r befd56673c80 -r 65c3af0d283b Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst Sun May 20 02:34:13 2012 +1000 +++ b/Doc/whatsnew/3.3.rst Sat May 19 17:01:25 2012 -0400 @@ -573,23 +573,6 @@ .. XXX mention new error messages for passing wrong number of arguments to functions -A Finer-Grained Import Lock -=========================== - -Previous versions of CPython have always relied on a global import lock. -This led to unexpected annoyances, such as deadlocks when importing a module -would trigger code execution in a different thread as a side-effect. -Clumsy workarounds were sometimes employed, such as the -:c:func:`PyImport_ImportModuleNoBlock` C API function. - -In Python 3.3, importing a module takes a per-module lock. This correctly -serializes importation of a given module from multiple threads (preventing -the exposure of incompletely initialized modules), while eliminating the -aforementioned annoyances. - -(contributed by Antoine Pitrou in :issue:`9260`.) - - New and Improved Modules ======================== @@ -1239,10 +1222,6 @@ (:issue:`14386`) -The new functions `types.new_class` and `types.prepare_class` provide support -for PEP 3115 compliant dynamic type creation. (:issue:`14588`) - - urllib ------ @@ -1281,10 +1260,6 @@ * repeating a single ASCII letter and getting a substring of a ASCII strings is 4 times faster -* UTF-8 and UTF-16 decoding is now 2x to 4x faster. - - (contributed by Serhiy Storchaka, :issue:`14624` and :issue:`14738`.) - Build and C API Changes ======================= diff -r befd56673c80 -r 65c3af0d283b Lib/__future__.py --- a/Lib/__future__.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/__future__.py Sat May 19 17:01:25 2012 -0400 @@ -114,7 +114,7 @@ CO_FUTURE_DIVISION) absolute_import = _Feature((2, 5, 0, "alpha", 1), - (3, 0, 0, "alpha", 0), + (2, 7, 0, "alpha", 0), CO_FUTURE_ABSOLUTE_IMPORT) with_statement = _Feature((2, 5, 0, "alpha", 1), diff -r befd56673c80 -r 65c3af0d283b Lib/http/client.py --- a/Lib/http/client.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/http/client.py Sat May 19 17:01:25 2012 -0400 @@ -1076,7 +1076,7 @@ self.putrequest(method, url, **skips) - if body is not None and ('content-length' not in header_names): + if body and ('content-length' not in header_names): self._set_content_length(body) for hdr, value in headers.items(): self.putheader(hdr, value) diff -r befd56673c80 -r 65c3af0d283b Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/importlib/_bootstrap.py Sat May 19 17:01:25 2012 -0400 @@ -159,145 +159,6 @@ return type(_io)(name) -# Module-level locking ######################################################## - -# A dict mapping module names to weakrefs of _ModuleLock instances -_module_locks = {} -# A dict mapping thread ids to _ModuleLock instances -_blocking_on = {} - - -class _DeadlockError(RuntimeError): - pass - - -class _ModuleLock: - """A recursive lock implementation which is able to detect deadlocks - (e.g. thread 1 trying to take locks A then B, and thread 2 trying to - take locks B then A). - """ - - def __init__(self, name): - self.lock = _thread.allocate_lock() - self.wakeup = _thread.allocate_lock() - self.name = name - self.owner = None - self.count = 0 - self.waiters = 0 - - def has_deadlock(self): - # Deadlock avoidance for concurrent circular imports. - me = _thread.get_ident() - tid = self.owner - while True: - lock = _blocking_on.get(tid) - if lock is None: - return False - tid = lock.owner - if tid == me: - return True - - def acquire(self): - """ - Acquire the module lock. If a potential deadlock is detected, - a _DeadlockError is raised. - Otherwise, the lock is always acquired and True is returned. - """ - tid = _thread.get_ident() - _blocking_on[tid] = self - try: - while True: - with self.lock: - if self.count == 0 or self.owner == tid: - self.owner = tid - self.count += 1 - return True - if self.has_deadlock(): - raise _DeadlockError("deadlock detected by %r" % self) - if self.wakeup.acquire(False): - self.waiters += 1 - # Wait for a release() call - self.wakeup.acquire() - self.wakeup.release() - finally: - del _blocking_on[tid] - - def release(self): - tid = _thread.get_ident() - with self.lock: - if self.owner != tid: - raise RuntimeError("cannot release un-acquired lock") - assert self.count > 0 - self.count -= 1 - if self.count == 0: - self.owner = None - if self.waiters: - self.waiters -= 1 - self.wakeup.release() - - def __repr__(self): - return "_ModuleLock(%r) at %d" % (self.name, id(self)) - - -class _DummyModuleLock: - """A simple _ModuleLock equivalent for Python builds without - multi-threading support.""" - - def __init__(self, name): - self.name = name - self.count = 0 - - def acquire(self): - self.count += 1 - return True - - def release(self): - if self.count == 0: - raise RuntimeError("cannot release un-acquired lock") - self.count -= 1 - - def __repr__(self): - return "_DummyModuleLock(%r) at %d" % (self.name, id(self)) - - -# The following two functions are for consumption by Python/import.c. - -def _get_module_lock(name): - """Get or create the module lock for a given module name. - - Should only be called with the import lock taken.""" - lock = None - if name in _module_locks: - lock = _module_locks[name]() - if lock is None: - if _thread is None: - lock = _DummyModuleLock(name) - else: - lock = _ModuleLock(name) - def cb(_): - del _module_locks[name] - _module_locks[name] = _weakref.ref(lock, cb) - return lock - -def _lock_unlock_module(name): - """Release the global import lock, and acquires then release the - module lock for a given module name. - This is used to ensure a module is completely initialized, in the - event it is being imported by another thread. - - Should only be called with the import lock taken.""" - lock = _get_module_lock(name) - _imp.release_lock() - try: - lock.acquire() - except _DeadlockError: - # Concurrent circular import, we'll accept a partially initialized - # module object. - pass - else: - lock.release() - - # Finder/loader utility code ################################################## _PYCACHE = '__pycache__' @@ -403,15 +264,12 @@ else: module.__package__ = fullname.rpartition('.')[0] try: - module.__initializing__ = True # If __package__ was not set above, __import__() will do it later. return fxn(self, module, *args, **kwargs) except: if not is_reload: del sys.modules[fullname] raise - finally: - module.__initializing__ = False _wrap(module_for_loader_wrapper, fxn) return module_for_loader_wrapper @@ -1074,8 +932,7 @@ if not sys.meta_path: _warnings.warn('sys.meta_path is empty', ImportWarning) for finder in sys.meta_path: - with _ImportLockContext(): - loader = finder.find_module(name, path) + loader = finder.find_module(name, path) if loader is not None: # The parent import may have already imported this module. if name not in sys.modules: @@ -1105,7 +962,8 @@ _ERR_MSG = 'No module named {!r}' -def _find_and_load_unlocked(name, import_): +def _find_and_load(name, import_): + """Find and load the module.""" path = None parent = name.rpartition('.')[0] if parent: @@ -1151,19 +1009,6 @@ return module -def _find_and_load(name, import_): - """Find and load the module, and release the import lock.""" - try: - lock = _get_module_lock(name) - finally: - _imp.release_lock() - lock.acquire() - try: - return _find_and_load_unlocked(name, import_) - finally: - lock.release() - - def _gcd_import(name, package=None, level=0): """Import and return the module based on its name, the package the call is being made from, and the level adjustment. @@ -1176,17 +1021,17 @@ _sanity_check(name, package, level) if level > 0: name = _resolve_name(name, package, level) - _imp.acquire_lock() - if name not in sys.modules: + with _ImportLockContext(): + try: + module = sys.modules[name] + if module is None: + message = ("import of {} halted; " + "None in sys.modules".format(name)) + raise ImportError(message, name=name) + return module + except KeyError: + pass # Don't want to chain the exception return _find_and_load(name, _gcd_import) - module = sys.modules[name] - if module is None: - _imp.release_lock() - message = ("import of {} halted; " - "None in sys.modules".format(name)) - raise ImportError(message, name=name) - _lock_unlock_module(name) - return module def _handle_fromlist(module, fromlist, import_): @@ -1304,17 +1149,7 @@ continue else: raise ImportError('importlib requires posix or nt') - - try: - thread_module = BuiltinImporter.load_module('_thread') - except ImportError: - # Python was built without threads - thread_module = None - weakref_module = BuiltinImporter.load_module('_weakref') - setattr(self_module, '_os', os_module) - setattr(self_module, '_thread', thread_module) - setattr(self_module, '_weakref', weakref_module) setattr(self_module, 'path_sep', path_sep) setattr(self_module, 'path_separators', set(path_separators)) # Constants diff -r befd56673c80 -r 65c3af0d283b Lib/importlib/test/test_locks.py --- a/Lib/importlib/test/test_locks.py Sun May 20 02:34:13 2012 +1000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -from importlib import _bootstrap -import time -import unittest -import weakref - -from test import support - -try: - import threading -except ImportError: - threading = None -else: - from test import lock_tests - - -LockType = _bootstrap._ModuleLock -DeadlockError = _bootstrap._DeadlockError - - -if threading is not None: - class ModuleLockAsRLockTests(lock_tests.RLockTests): - locktype = staticmethod(lambda: LockType("some_lock")) - - # _is_owned() unsupported - test__is_owned = None - # acquire(blocking=False) unsupported - test_try_acquire = None - test_try_acquire_contended = None - # `with` unsupported - test_with = None - # acquire(timeout=...) unsupported - test_timeout = None - # _release_save() unsupported - test_release_save_unacquired = None - -else: - class ModuleLockAsRLockTests(unittest.TestCase): - pass - - -@unittest.skipUnless(threading, "threads needed for this test") -class DeadlockAvoidanceTests(unittest.TestCase): - - def run_deadlock_avoidance_test(self, create_deadlock): - NLOCKS = 10 - locks = [LockType(str(i)) for i in range(NLOCKS)] - pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)] - if create_deadlock: - NTHREADS = NLOCKS - else: - NTHREADS = NLOCKS - 1 - barrier = threading.Barrier(NTHREADS) - results = [] - def _acquire(lock): - """Try to acquire the lock. Return True on success, False on deadlock.""" - try: - lock.acquire() - except DeadlockError: - return False - else: - return True - def f(): - a, b = pairs.pop() - ra = _acquire(a) - barrier.wait() - rb = _acquire(b) - results.append((ra, rb)) - if rb: - b.release() - if ra: - a.release() - lock_tests.Bunch(f, NTHREADS).wait_for_finished() - self.assertEqual(len(results), NTHREADS) - return results - - def test_deadlock(self): - results = self.run_deadlock_avoidance_test(True) - # One of the threads detected a potential deadlock on its second - # acquire() call. - self.assertEqual(results.count((True, False)), 1) - self.assertEqual(results.count((True, True)), len(results) - 1) - - def test_no_deadlock(self): - results = self.run_deadlock_avoidance_test(False) - self.assertEqual(results.count((True, False)), 0) - self.assertEqual(results.count((True, True)), len(results)) - - -class LifetimeTests(unittest.TestCase): - - def test_lock_lifetime(self): - name = "xyzzy" - self.assertNotIn(name, _bootstrap._module_locks) - lock = _bootstrap._get_module_lock(name) - self.assertIn(name, _bootstrap._module_locks) - wr = weakref.ref(lock) - del lock - support.gc_collect() - self.assertNotIn(name, _bootstrap._module_locks) - self.assertIs(wr(), None) - - def test_all_locks(self): - support.gc_collect() - self.assertEqual(0, len(_bootstrap._module_locks)) - - -@support.reap_threads -def test_main(): - support.run_unittest(ModuleLockAsRLockTests, - DeadlockAvoidanceTests, - LifetimeTests) - - -if __name__ == '__main__': - test_main() diff -r befd56673c80 -r 65c3af0d283b Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/multiprocessing/forking.py Sat May 19 17:01:25 2012 -0400 @@ -324,8 +324,7 @@ return [sys.executable, '--multiprocessing-fork'] else: prog = 'from multiprocessing.forking import main; main()' - opts = util._args_from_interpreter_flags() - return [_python_exe] + opts + ['-c', prog, '--multiprocessing-fork'] + return [_python_exe, '-c', prog, '--multiprocessing-fork'] def main(): diff -r befd56673c80 -r 65c3af0d283b Lib/multiprocessing/util.py --- a/Lib/multiprocessing/util.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/multiprocessing/util.py Sat May 19 17:01:25 2012 -0400 @@ -7,14 +7,12 @@ # Licensed to PSF under a Contributor Agreement. # -import sys import functools import itertools import weakref import atexit import threading # we want threading to install it's # cleanup function before multiprocessing does -from subprocess import _args_from_interpreter_flags from multiprocessing.process import current_process, active_children diff -r befd56673c80 -r 65c3af0d283b Lib/packaging/command/build_ext.py --- a/Lib/packaging/command/build_ext.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/packaging/command/build_ext.py Sat May 19 17:01:25 2012 -0400 @@ -375,10 +375,6 @@ # Next, compile the source code to object files. - # XXX not honouring 'define_macros' or 'undef_macros' -- the - # CCompiler API needs to change to accommodate this, and I - # want to do one thing at a time! - # Two possible sources for extra compiler arguments: # - 'extra_compile_args' in Extension object # - CFLAGS environment variable (not particularly @@ -389,7 +385,7 @@ # command-line args. Hence we combine them in order: extra_args = ext.extra_compile_args or [] - macros = ext.define_macros[:] + macros = [(macro, '1') for macro in ext.define_macros] for undef in ext.undef_macros: macros.append((undef,)) diff -r befd56673c80 -r 65c3af0d283b Lib/packaging/command/install_data.py --- a/Lib/packaging/command/install_data.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/packaging/command/install_data.py Sat May 19 17:01:25 2012 -0400 @@ -3,6 +3,7 @@ # Contributed by Bastian Kleineidam import os +from functools import partial from shutil import Error from sysconfig import get_paths, format_value from packaging import logger @@ -27,24 +28,24 @@ def initialize_options(self): self.install_dir = None + self.distinfo_dir = None self.outfiles = [] self.data_files_out = [] self.root = None self.force = False self.data_files = self.distribution.data_files self.warn_dir = True + self.extra_dist_info = [] def finalize_options(self): self.set_undefined_options('install_dist', ('install_data', 'install_dir'), 'root', 'force') + self.set_undefined_options('install_distinfo', + 'distinfo_dir') def run(self): - self.mkpath(self.install_dir) - for _file in self.data_files.items(): - destination = convert_path(self.expand_categories(_file[1])) - dir_dest = os.path.abspath(os.path.dirname(destination)) - + def do_copy(_file, dir_dest, destination): self.mkpath(dir_dest) try: out = self.copy_file(_file[0], dir_dest)[0] @@ -55,9 +56,20 @@ self.outfiles.append(out) self.data_files_out.append((_file[0], destination)) + self.mkpath(self.install_dir) + for _file in self.data_files.items(): + destination = convert_path(self.expand_categories(_file[1])) + dir_dest = os.path.abspath(os.path.dirname(destination)) + copy = partial(do_copy, _file, dir_dest, destination) + if destination.startswith(self.distinfo_dir): + self.extra_dist_info.append(copy) + else: + copy() + def expand_categories(self, path_with_categories): local_vars = get_paths() local_vars['distribution.name'] = self.distribution.metadata['Name'] + local_vars['dist-info'] = self.distinfo_dir expanded_path = format_value(path_with_categories, local_vars) expanded_path = format_value(expanded_path, local_vars) if '{' in expanded_path and '}' in expanded_path: diff -r befd56673c80 -r 65c3af0d283b Lib/packaging/command/install_distinfo.py --- a/Lib/packaging/command/install_distinfo.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/packaging/command/install_distinfo.py Sat May 19 17:01:25 2012 -0400 @@ -36,6 +36,7 @@ def initialize_options(self): self.install_dir = None + self.install_base = None self.installer = None self.requested = None self.no_record = None @@ -44,7 +45,7 @@ def finalize_options(self): self.set_undefined_options('install_dist', - 'installer', 'requested', 'no_record') + 'installer', 'requested', 'no_record', 'install_base') self.set_undefined_options('install_lib', 'install_dir') @@ -63,26 +64,46 @@ basename = metadata.get_fullname(filesafe=True) + ".dist-info" - self.install_dir = os.path.join(self.install_dir, basename) - + self.distinfo_dir = os.path.join(self.install_dir, basename) + + @staticmethod + def pep376path(fpath, install_base, install_dir): + """Return PEP-376 path (but always with platform path separators)""" + # install_base is 'prefix' from PEP-376 + install_base = install_base.rstrip(os.path.sep) + os.path.sep + # install_dir is 'base location' from PEP-376 + install_dir = install_dir.rstrip(os.path.sep) + os.path.sep + install_dir_in_base = install_dir.startswith(install_base) + if fpath.startswith(install_dir) or \ + fpath.startswith(install_base) and install_dir_in_base: + rpath = os.path.relpath(fpath, install_dir) + else: + rpath = os.path.abspath(fpath) + return rpath + def run(self): - target = self.install_dir + target = self.distinfo_dir if os.path.isdir(target) and not os.path.islink(target): if not self.dry_run: rmtree(target) elif os.path.exists(target): - self.execute(os.unlink, (self.install_dir,), + self.execute(os.unlink, (self.distinfo_dir,), "removing " + target) self.execute(os.makedirs, (target,), "creating " + target) + + if not self.dry_run: + install_data = self.get_finalized_command('install_data') + while install_data.extra_dist_info: + install_data.extra_dist_info.pop()() - metadata_path = os.path.join(self.install_dir, 'METADATA') + metadata_path = os.path.join(self.distinfo_dir, 'METADATA') self.execute(self.distribution.metadata.write, (metadata_path,), "creating " + metadata_path) self.outfiles.append(metadata_path) - installer_path = os.path.join(self.install_dir, 'INSTALLER') + installer_path = os.path.join(self.distinfo_dir, 'INSTALLER') logger.info('creating %s', installer_path) if not self.dry_run: with open(installer_path, 'w') as f: @@ -90,7 +111,7 @@ self.outfiles.append(installer_path) if self.requested: - requested_path = os.path.join(self.install_dir, 'REQUESTED') + requested_path = os.path.join(self.distinfo_dir, 'REQUESTED') logger.info('creating %s', requested_path) if not self.dry_run: open(requested_path, 'wb').close() @@ -99,7 +120,7 @@ if not self.no_resources: install_data = self.get_finalized_command('install_data') if install_data.get_resources_out() != []: - resources_path = os.path.join(self.install_dir, + resources_path = os.path.join(self.distinfo_dir, 'RESOURCES') logger.info('creating %s', resources_path) if not self.dry_run: @@ -113,7 +134,7 @@ self.outfiles.append(resources_path) if not self.no_record: - record_path = os.path.join(self.install_dir, 'RECORD') + record_path = os.path.join(self.distinfo_dir, 'RECORD') logger.info('creating %s', record_path) if not self.dry_run: with open(record_path, 'w', encoding='utf-8') as f: @@ -121,22 +142,23 @@ lineterminator='\n', quotechar='"') - install = self.get_finalized_command('install_dist') + install = self.get_finalized_command('install_dist') for fpath in install.get_outputs(): + rpath = self.pep376path(fpath, self.install_base, self.install_dir) if fpath.endswith('.pyc') or fpath.endswith('.pyo'): # do not put size and md5 hash, as in PEP-376 - writer.writerow((fpath, '', '')) + writer.writerow((rpath, '', '')) else: size = os.path.getsize(fpath) with open(fpath, 'rb') as fp: hash = hashlib.md5() hash.update(fp.read()) md5sum = hash.hexdigest() - writer.writerow((fpath, md5sum, size)) + writer.writerow((rpath, md5sum, size)) # add the RECORD file itself - writer.writerow((record_path, '', '')) + writer.writerow((self.pep376path(record_path, self.install_base, self.install_dir), '', '')) self.outfiles.append(record_path) def get_outputs(self): diff -r befd56673c80 -r 65c3af0d283b Lib/packaging/database.py --- a/Lib/packaging/database.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/packaging/database.py Sat May 19 17:01:25 2012 -0400 @@ -244,11 +244,6 @@ 'dist-info file %r does not belong to the %r %s ' 'distribution' % (path, self.name, self.version)) - # The file must be relative - if path not in DIST_FILES: - raise PackagingError('invalid path for a dist-info file: %r' % - path) - path = os.path.join(self.path, path) return open(path, open_flags) diff -r befd56673c80 -r 65c3af0d283b Lib/packaging/tests/test_command_install_data.py --- a/Lib/packaging/tests/test_command_install_data.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/packaging/tests/test_command_install_data.py Sat May 19 17:01:25 2012 -0400 @@ -95,10 +95,12 @@ scripts_dir = self.mkdtemp() project_dir, dist = self.create_dist( name='Spamlib', version='0.1', - data_files={'spamd': '{scripts}/spamd'}) + data_files={'spamd': '{scripts}/spamd', + 'entry_points.txt': '{dist-info}/entry_points.txt'}) os.chdir(project_dir) self.write_file('spamd', '# Python script') + self.write_file('entry_points.txt', '[entry_points]\nham = eggs:cheese') sysconfig._SCHEMES.set(_get_default_scheme(), 'scripts', scripts_dir) sys.path.insert(0, install_dir) packaging.database.disable_cache() @@ -119,18 +121,21 @@ cmd = install_distinfo(dist) cmd.ensure_finalized() dist.command_obj['install_distinfo'] = cmd - cmd.run() + cmd.run() # first a few sanity checks self.assertEqual(os.listdir(scripts_dir), ['spamd']) - self.assertEqual(os.listdir(install_dir), ['Spamlib-0.1.dist-info']) + self.assertEqual(os.listdir(install_dir), ['Spamlib-0.1.dist-info']) # now the real test fn = os.path.join(install_dir, 'Spamlib-0.1.dist-info', 'RESOURCES') with open(fn, encoding='utf-8') as fp: content = fp.read().strip() - expected = 'spamd,%s' % os.path.join(scripts_dir, 'spamd') + expected = 'spamd,%s\nentry_points.txt,%s' % (os.path.join(scripts_dir, 'spamd'), + os.path.join(install_dir, + 'Spamlib-0.1.dist-info', + 'entry_points.txt')) self.assertEqual(content, expected) # just to be sure, we also test that get_file works here, even though diff -r befd56673c80 -r 65c3af0d283b Lib/pyclbr.py --- a/Lib/pyclbr.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/pyclbr.py Sat May 19 17:01:25 2012 -0400 @@ -130,8 +130,6 @@ parent = _readmodule(package, path, inpackage) if inpackage is not None: package = "%s.%s" % (inpackage, package) - if not '__path__' in parent: - raise ImportError('No package named {}'.format(package)) return _readmodule(submodule, parent['__path__'], package) # Search the path for the module diff -r befd56673c80 -r 65c3af0d283b Lib/pydoc.py --- a/Lib/pydoc.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/pydoc.py Sat May 19 17:01:25 2012 -0400 @@ -167,7 +167,7 @@ if name in {'__builtins__', '__doc__', '__file__', '__path__', '__module__', '__name__', '__slots__', '__package__', '__cached__', '__author__', '__credits__', '__date__', - '__version__', '__qualname__', '__initializing__'}: + '__version__', '__qualname__'}: return 0 # Private names are hidden, but special names are displayed. if name.startswith('__') and name.endswith('__'): return 1 diff -r befd56673c80 -r 65c3af0d283b Lib/subprocess.py --- a/Lib/subprocess.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/subprocess.py Sat May 19 17:01:25 2012 -0400 @@ -475,37 +475,6 @@ 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. - -def _args_from_interpreter_flags(): - """Return a list of command-line arguments reproducing the current - settings in sys.flags and sys.warnoptions.""" - flag_opt_map = { - 'debug': 'd', - # 'inspect': 'i', - # 'interactive': 'i', - 'optimize': 'O', - 'dont_write_bytecode': 'B', - 'no_user_site': 's', - 'no_site': 'S', - 'ignore_environment': 'E', - 'verbose': 'v', - 'bytes_warning': 'b', - 'quiet': 'q', - 'hash_randomization': 'R', - } - args = [] - for flag, opt in flag_opt_map.items(): - v = getattr(sys.flags, flag) - if v > 0: - args.append('-' + opt * v) - for opt in sys.warnoptions: - args.append('-W' + opt) - return args - - def call(*popenargs, timeout=None, **kwargs): """Run command with arguments. Wait for command to complete or timeout, then return the returncode attribute. diff -r befd56673c80 -r 65c3af0d283b Lib/tarfile.py --- a/Lib/tarfile.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/tarfile.py Sat May 19 17:01:25 2012 -0400 @@ -245,8 +245,8 @@ the high bit set. So we calculate two checksums, unsigned and signed. """ - unsigned_chksum = 256 + sum(struct.unpack_from("148B8x356B", buf)) - signed_chksum = 256 + sum(struct.unpack_from("148b8x356b", buf)) + unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512])) + signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512])) return unsigned_chksum, signed_chksum def copyfileobj(src, dst, length=None): diff -r befd56673c80 -r 65c3af0d283b Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/lock_tests.py Sat May 19 17:01:25 2012 -0400 @@ -247,6 +247,7 @@ # Cannot release an unacquired lock lock = self.locktype() self.assertRaises(RuntimeError, lock.release) + self.assertRaises(RuntimeError, lock._release_save) lock.acquire() lock.acquire() lock.release() @@ -254,17 +255,6 @@ lock.release() lock.release() self.assertRaises(RuntimeError, lock.release) - - def test_release_save_unacquired(self): - # Cannot _release_save an unacquired lock - lock = self.locktype() - self.assertRaises(RuntimeError, lock._release_save) - lock.acquire() - lock.acquire() - lock.release() - lock.acquire() - lock.release() - lock.release() self.assertRaises(RuntimeError, lock._release_save) def test_different_thread(self): diff -r befd56673c80 -r 65c3af0d283b Lib/test/support.py --- a/Lib/test/support.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/support.py Sat May 19 17:01:25 2012 -0400 @@ -1596,7 +1596,24 @@ def args_from_interpreter_flags(): """Return a list of command-line arguments reproducing the current settings in sys.flags and sys.warnoptions.""" - return subprocess._args_from_interpreter_flags() + flag_opt_map = { + 'bytes_warning': 'b', + 'dont_write_bytecode': 'B', + 'hash_randomization': 'R', + 'ignore_environment': 'E', + 'no_user_site': 's', + 'no_site': 'S', + 'optimize': 'O', + 'verbose': 'v', + } + args = [] + for flag, opt in flag_opt_map.items(): + v = getattr(sys.flags, flag) + if v > 0: + args.append('-' + opt * v) + for opt in sys.warnoptions: + args.append('-W' + opt) + return args #============================================================ # Support for assertions about logging. diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_httplib.py Sat May 19 17:01:25 2012 -0400 @@ -99,34 +99,6 @@ conn.request('POST', '/', body, headers) self.assertEqual(conn._buffer.count[header.lower()], 1) - def test_content_length_0(self): - - class ContentLengthChecker(list): - def __init__(self): - list.__init__(self) - self.content_length = None - def append(self, item): - kv = item.split(b':', 1) - if len(kv) > 1 and kv[0].lower() == b'content-length': - self.content_length = kv[1].strip() - list.append(self, item) - - # POST with empty body - conn = client.HTTPConnection('example.com') - conn.sock = FakeSocket(None) - conn._buffer = ContentLengthChecker() - conn.request('POST', '/', '') - self.assertEqual(conn._buffer.content_length, b'0', - 'Header Content-Length not set') - - # PUT request with empty body - conn = client.HTTPConnection('example.com') - conn.sock = FakeSocket(None) - conn._buffer = ContentLengthChecker() - conn.request('PUT', '/', '') - self.assertEqual(conn._buffer.content_length, b'0', - 'Header Content-Length not set') - def test_putheader(self): conn = client.HTTPConnection('example.com') conn.sock = FakeSocket(None) diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_multiprocessing.py Sat May 19 17:01:25 2012 -0400 @@ -2814,41 +2814,8 @@ with self.assertRaises(ValueError): multiprocessing.connection.Listener('/var/test.pipe') -# -# Issue 12098: check sys.flags of child matches that for parent -# - -class TestFlags(unittest.TestCase): - @classmethod - def run_in_grandchild(cls, conn): - conn.send(tuple(sys.flags)) - - @classmethod - def run_in_child(cls): - import json - r, w = multiprocessing.Pipe(duplex=False) - p = multiprocessing.Process(target=cls.run_in_grandchild, args=(w,)) - p.start() - grandchild_flags = r.recv() - p.join() - r.close() - w.close() - flags = (tuple(sys.flags), grandchild_flags) - print(json.dumps(flags)) - - def test_flags(self): - import json, subprocess - # start child process using unusual flags - prog = ('from test.test_multiprocessing import TestFlags; ' + - 'TestFlags.run_in_child()') - data = subprocess.check_output( - [sys.executable, '-E', '-S', '-O', '-c', prog]) - child_flags, grandchild_flags = json.loads(data.decode('ascii')) - self.assertEqual(child_flags, grandchild_flags) - testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, - TestStdinBadfiledescriptor, TestWait, TestInvalidFamily, - TestFlags] + TestStdinBadfiledescriptor, TestWait, TestInvalidFamily] # # diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_pkg.py --- a/Lib/test/test_pkg.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_pkg.py Sat May 19 17:01:25 2012 -0400 @@ -23,8 +23,6 @@ def fixdir(lst): if "__builtins__" in lst: lst.remove("__builtins__") - if "__initializing__" in lst: - lst.remove("__initializing__") return lst diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_pyclbr.py --- a/Lib/test/test_pyclbr.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_pyclbr.py Sat May 19 17:01:25 2012 -0400 @@ -167,11 +167,6 @@ cm('email.parser') cm('test.test_pyclbr') - def test_issue_14798(self): - # test ImportError is raised when the first part of a dotted name is - # not a package - self.assertRaises(ImportError, pyclbr.readmodule_ex, 'asyncore.foo') - def test_main(): run_unittest(PyclbrTest) diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_textwrap.py --- a/Lib/test/test_textwrap.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_textwrap.py Sat May 19 17:01:25 2012 -0400 @@ -91,14 +91,6 @@ result = wrapper.fill(text) self.check(result, '\n'.join(expect)) - text = "\tTest\tdefault\t\ttabsize." - expect = [" Test default tabsize."] - self.check_wrap(text, 80, expect) - - text = "\tTest\tcustom\t\ttabsize." - expect = [" Test custom tabsize."] - self.check_wrap(text, 80, expect, tabsize=4) - def test_fix_sentence_endings(self): wrapper = TextWrapper(60, fix_sentence_endings=True) diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_threaded_import.py --- a/Lib/test/test_threaded_import.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_threaded_import.py Sat May 19 17:01:25 2012 -0400 @@ -12,7 +12,7 @@ import shutil import unittest from test.support import ( - verbose, import_module, run_unittest, TESTFN, reap_threads, forget, unlink) + verbose, import_module, run_unittest, TESTFN, reap_threads) threading = import_module('threading') def task(N, done, done_tasks, errors): @@ -187,7 +187,7 @@ contents = contents % {'delay': delay} with open(os.path.join(TESTFN, name + ".py"), "wb") as f: f.write(contents.encode('utf-8')) - self.addCleanup(forget, name) + self.addCleanup(sys.modules.pop, name, None) results = [] def import_ab(): @@ -204,23 +204,6 @@ t2.join() self.assertEqual(set(results), {'a', 'b'}) - def test_side_effect_import(self): - code = """if 1: - import threading - def target(): - import random - t = threading.Thread(target=target) - t.start() - t.join()""" - sys.path.insert(0, os.curdir) - self.addCleanup(sys.path.remove, os.curdir) - filename = TESTFN + ".py" - with open(filename, "wb") as f: - f.write(code.encode('utf-8')) - self.addCleanup(unlink, filename) - self.addCleanup(forget, TESTFN) - __import__(TESTFN) - @reap_threads def test_main(): diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_types.py --- a/Lib/test/test_types.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_types.py Sat May 19 17:01:25 2012 -0400 @@ -747,257 +747,8 @@ self.assertEqual(copy['key1'], 27) -class ClassCreationTests(unittest.TestCase): - - class Meta(type): - def __init__(cls, name, bases, ns, **kw): - super().__init__(name, bases, ns) - @staticmethod - def __new__(mcls, name, bases, ns, **kw): - return super().__new__(mcls, name, bases, ns) - @classmethod - def __prepare__(mcls, name, bases, **kw): - ns = super().__prepare__(name, bases) - ns["y"] = 1 - ns.update(kw) - return ns - - def test_new_class_basics(self): - C = types.new_class("C") - self.assertEqual(C.__name__, "C") - self.assertEqual(C.__bases__, (object,)) - - def test_new_class_subclass(self): - C = types.new_class("C", (int,)) - self.assertTrue(issubclass(C, int)) - - def test_new_class_meta(self): - Meta = self.Meta - settings = {"metaclass": Meta, "z": 2} - # We do this twice to make sure the passed in dict isn't mutated - for i in range(2): - C = types.new_class("C" + str(i), (), settings) - self.assertIsInstance(C, Meta) - self.assertEqual(C.y, 1) - self.assertEqual(C.z, 2) - - def test_new_class_exec_body(self): - Meta = self.Meta - def func(ns): - ns["x"] = 0 - C = types.new_class("C", (), {"metaclass": Meta, "z": 2}, func) - self.assertIsInstance(C, Meta) - self.assertEqual(C.x, 0) - self.assertEqual(C.y, 1) - self.assertEqual(C.z, 2) - - def test_new_class_exec_body(self): - #Test that keywords are passed to the metaclass: - def meta_func(name, bases, ns, **kw): - return name, bases, ns, kw - res = types.new_class("X", - (int, object), - dict(metaclass=meta_func, x=0)) - self.assertEqual(res, ("X", (int, object), {}, {"x": 0})) - - def test_new_class_defaults(self): - # Test defaults/keywords: - C = types.new_class("C", (), {}, None) - self.assertEqual(C.__name__, "C") - self.assertEqual(C.__bases__, (object,)) - - def test_new_class_meta_with_base(self): - Meta = self.Meta - def func(ns): - ns["x"] = 0 - C = types.new_class(name="C", - bases=(int,), - kwds=dict(metaclass=Meta, z=2), - exec_body=func) - self.assertTrue(issubclass(C, int)) - self.assertIsInstance(C, Meta) - self.assertEqual(C.x, 0) - self.assertEqual(C.y, 1) - self.assertEqual(C.z, 2) - - # Many of the following tests are derived from test_descr.py - def test_prepare_class(self): - # Basic test of metaclass derivation - expected_ns = {} - class A(type): - def __new__(*args, **kwargs): - return type.__new__(*args, **kwargs) - - def __prepare__(*args): - return expected_ns - - B = types.new_class("B", (object,)) - C = types.new_class("C", (object,), {"metaclass": A}) - - # The most derived metaclass of D is A rather than type. - meta, ns, kwds = types.prepare_class("D", (B, C), {"metaclass": type}) - self.assertIs(meta, A) - self.assertIs(ns, expected_ns) - self.assertEqual(len(kwds), 0) - - def test_metaclass_derivation(self): - # issue1294232: correct metaclass calculation - new_calls = [] # to check the order of __new__ calls - class AMeta(type): - def __new__(mcls, name, bases, ns): - new_calls.append('AMeta') - return super().__new__(mcls, name, bases, ns) - @classmethod - def __prepare__(mcls, name, bases): - return {} - - class BMeta(AMeta): - def __new__(mcls, name, bases, ns): - new_calls.append('BMeta') - return super().__new__(mcls, name, bases, ns) - @classmethod - def __prepare__(mcls, name, bases): - ns = super().__prepare__(name, bases) - ns['BMeta_was_here'] = True - return ns - - A = types.new_class("A", (), {"metaclass": AMeta}) - self.assertEqual(new_calls, ['AMeta']) - new_calls.clear() - - B = types.new_class("B", (), {"metaclass": BMeta}) - # BMeta.__new__ calls AMeta.__new__ with super: - self.assertEqual(new_calls, ['BMeta', 'AMeta']) - new_calls.clear() - - C = types.new_class("C", (A, B)) - # The most derived metaclass is BMeta: - self.assertEqual(new_calls, ['BMeta', 'AMeta']) - new_calls.clear() - # BMeta.__prepare__ should've been called: - self.assertIn('BMeta_was_here', C.__dict__) - - # The order of the bases shouldn't matter: - C2 = types.new_class("C2", (B, A)) - self.assertEqual(new_calls, ['BMeta', 'AMeta']) - new_calls.clear() - self.assertIn('BMeta_was_here', C2.__dict__) - - # Check correct metaclass calculation when a metaclass is declared: - D = types.new_class("D", (C,), {"metaclass": type}) - self.assertEqual(new_calls, ['BMeta', 'AMeta']) - new_calls.clear() - self.assertIn('BMeta_was_here', D.__dict__) - - E = types.new_class("E", (C,), {"metaclass": AMeta}) - self.assertEqual(new_calls, ['BMeta', 'AMeta']) - new_calls.clear() - self.assertIn('BMeta_was_here', E.__dict__) - - def test_metaclass_override_function(self): - # Special case: the given metaclass isn't a class, - # so there is no metaclass calculation. - class A(metaclass=self.Meta): - pass - - marker = object() - def func(*args, **kwargs): - return marker - - X = types.new_class("X", (), {"metaclass": func}) - Y = types.new_class("Y", (object,), {"metaclass": func}) - Z = types.new_class("Z", (A,), {"metaclass": func}) - self.assertIs(marker, X) - self.assertIs(marker, Y) - self.assertIs(marker, Z) - - def test_metaclass_override_callable(self): - # The given metaclass is a class, - # but not a descendant of type. - new_calls = [] # to check the order of __new__ calls - prepare_calls = [] # to track __prepare__ calls - class ANotMeta: - def __new__(mcls, *args, **kwargs): - new_calls.append('ANotMeta') - return super().__new__(mcls) - @classmethod - def __prepare__(mcls, name, bases): - prepare_calls.append('ANotMeta') - return {} - - class BNotMeta(ANotMeta): - def __new__(mcls, *args, **kwargs): - new_calls.append('BNotMeta') - return super().__new__(mcls) - @classmethod - def __prepare__(mcls, name, bases): - prepare_calls.append('BNotMeta') - return super().__prepare__(name, bases) - - A = types.new_class("A", (), {"metaclass": ANotMeta}) - self.assertIs(ANotMeta, type(A)) - self.assertEqual(prepare_calls, ['ANotMeta']) - prepare_calls.clear() - self.assertEqual(new_calls, ['ANotMeta']) - new_calls.clear() - - B = types.new_class("B", (), {"metaclass": BNotMeta}) - self.assertIs(BNotMeta, type(B)) - self.assertEqual(prepare_calls, ['BNotMeta', 'ANotMeta']) - prepare_calls.clear() - self.assertEqual(new_calls, ['BNotMeta', 'ANotMeta']) - new_calls.clear() - - C = types.new_class("C", (A, B)) - self.assertIs(BNotMeta, type(C)) - self.assertEqual(prepare_calls, ['BNotMeta', 'ANotMeta']) - prepare_calls.clear() - self.assertEqual(new_calls, ['BNotMeta', 'ANotMeta']) - new_calls.clear() - - C2 = types.new_class("C2", (B, A)) - self.assertIs(BNotMeta, type(C2)) - self.assertEqual(prepare_calls, ['BNotMeta', 'ANotMeta']) - prepare_calls.clear() - self.assertEqual(new_calls, ['BNotMeta', 'ANotMeta']) - new_calls.clear() - - # This is a TypeError, because of a metaclass conflict: - # BNotMeta is neither a subclass, nor a superclass of type - with self.assertRaises(TypeError): - D = types.new_class("D", (C,), {"metaclass": type}) - - E = types.new_class("E", (C,), {"metaclass": ANotMeta}) - self.assertIs(BNotMeta, type(E)) - self.assertEqual(prepare_calls, ['BNotMeta', 'ANotMeta']) - prepare_calls.clear() - self.assertEqual(new_calls, ['BNotMeta', 'ANotMeta']) - new_calls.clear() - - F = types.new_class("F", (object(), C)) - self.assertIs(BNotMeta, type(F)) - self.assertEqual(prepare_calls, ['BNotMeta', 'ANotMeta']) - prepare_calls.clear() - self.assertEqual(new_calls, ['BNotMeta', 'ANotMeta']) - new_calls.clear() - - F2 = types.new_class("F2", (C, object())) - self.assertIs(BNotMeta, type(F2)) - self.assertEqual(prepare_calls, ['BNotMeta', 'ANotMeta']) - prepare_calls.clear() - self.assertEqual(new_calls, ['BNotMeta', 'ANotMeta']) - new_calls.clear() - - # TypeError: BNotMeta is neither a - # subclass, nor a superclass of int - with self.assertRaises(TypeError): - X = types.new_class("X", (C, int())) - with self.assertRaises(TypeError): - X = types.new_class("X", (int(), C)) - - def test_main(): - run_unittest(TypesTests, MappingProxyTests, ClassCreationTests) + run_unittest(TypesTests, MappingProxyTests) if __name__ == '__main__': test_main() diff -r befd56673c80 -r 65c3af0d283b Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/test/test_urlparse.py Sat May 19 17:01:25 2012 -0400 @@ -636,20 +636,11 @@ ('s3', 'foo.com', '/stuff', '', '', '')) self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff"), ('x-newscheme', 'foo.com', '/stuff', '', '', '')) - self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query#fragment"), - ('x-newscheme', 'foo.com', '/stuff', '', 'query', 'fragment')) - self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query"), - ('x-newscheme', 'foo.com', '/stuff', '', 'query', '')) - # And for bytes... self.assertEqual(urllib.parse.urlparse(b"s3://foo.com/stuff"), (b's3', b'foo.com', b'/stuff', b'', b'', b'')) self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff"), (b'x-newscheme', b'foo.com', b'/stuff', b'', b'', b'')) - self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query#fragment"), - (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b'fragment')) - self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query"), - (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b'')) def test_mixed_types_rejected(self): # Several functions that process either strings or ASCII encoded bytes @@ -806,13 +797,6 @@ encoding='utf-8') self.assertRaises(TypeError, urllib.parse.quote, b'foo', errors='strict') - def test_issue14072(self): - p1 = urllib.parse.urlsplit('tel:+31-641044153') - self.assertEqual(p1.scheme, 'tel') - self.assertEqual(p1.path, '+31-641044153') - p2 = urllib.parse.urlsplit('tel:+31641044153') - self.assertEqual(p2.scheme, 'tel') - self.assertEqual(p2.path, '+31641044153') def test_main(): support.run_unittest(UrlParseTestCase) diff -r befd56673c80 -r 65c3af0d283b Lib/textwrap.py --- a/Lib/textwrap.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/textwrap.py Sat May 19 17:01:25 2012 -0400 @@ -39,11 +39,8 @@ of wrapped output; also counts towards each line's width. expand_tabs (default: true) Expand tabs in input text to spaces before further processing. - Each tab will become 0 .. 'tabsize' spaces, depending on its position - in its line. If false, each tab is treated as a single character. - tabsize (default: 8) - Expand tabs in input text to 0 .. 'tabsize' spaces, unless - 'expand_tabs' is false. + Each tab will become 1 .. 8 spaces, depending on its position in + its line. If false, each tab is treated as a single character. replace_whitespace (default: true) Replace all whitespace characters in the input text by spaces after tab expansion. Note that if expand_tabs is false and @@ -103,8 +100,7 @@ fix_sentence_endings=False, break_long_words=True, drop_whitespace=True, - break_on_hyphens=True, - tabsize=8): + break_on_hyphens=True): self.width = width self.initial_indent = initial_indent self.subsequent_indent = subsequent_indent @@ -114,7 +110,6 @@ self.break_long_words = break_long_words self.drop_whitespace = drop_whitespace self.break_on_hyphens = break_on_hyphens - self.tabsize = tabsize # -- Private methods ----------------------------------------------- @@ -128,7 +123,7 @@ becomes " foo bar baz". """ if self.expand_tabs: - text = text.expandtabs(self.tabsize) + text = text.expandtabs() if self.replace_whitespace: text = text.translate(self.unicode_whitespace_trans) return text diff -r befd56673c80 -r 65c3af0d283b Lib/token.py --- a/Lib/token.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/token.py Sat May 19 17:01:25 2012 -0400 @@ -70,7 +70,7 @@ tok_name = {value: name for name, value in globals().items() - if isinstance(value, int) and not name.startswith('_')} + if isinstance(value, int)} __all__.extend(tok_name.values()) def ISTERMINAL(x): diff -r befd56673c80 -r 65c3af0d283b Lib/types.py --- a/Lib/types.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/types.py Sat May 19 17:01:25 2012 -0400 @@ -40,61 +40,3 @@ MemberDescriptorType = type(FunctionType.__globals__) del sys, _f, _g, _C, # Not for export - - -# Provide a PEP 3115 compliant mechanism for class creation -def new_class(name, bases=(), kwds=None, exec_body=None): - """Create a class object dynamically using the appropriate metaclass.""" - meta, ns, kwds = prepare_class(name, bases, kwds) - if exec_body is not None: - exec_body(ns) - return meta(name, bases, ns, **kwds) - -def prepare_class(name, bases=(), kwds=None): - """Call the __prepare__ method of the appropriate metaclass. - - Returns (metaclass, namespace, kwds) as a 3-tuple - - *metaclass* is the appropriate metaclass - *namespace* is the prepared class namespace - *kwds* is an updated copy of the passed in kwds argument with any - 'metaclass' entry removed. If no kwds argument is passed in, this will - be an empty dict. - """ - if kwds is None: - kwds = {} - else: - kwds = dict(kwds) # Don't alter the provided mapping - if 'metaclass' in kwds: - meta = kwds.pop('metaclass') - else: - if bases: - meta = type(bases[0]) - else: - meta = type - if isinstance(meta, type): - # when meta is a type, we first determine the most-derived metaclass - # instead of invoking the initial candidate directly - meta = _calculate_meta(meta, bases) - if hasattr(meta, '__prepare__'): - ns = meta.__prepare__(name, bases, **kwds) - else: - ns = {} - return meta, ns, kwds - -def _calculate_meta(meta, bases): - """Calculate the most derived metaclass.""" - winner = meta - for base in bases: - base_meta = type(base) - if issubclass(winner, base_meta): - continue - if issubclass(base_meta, winner): - winner = base_meta - continue - # else: - raise TypeError("metaclass conflict: " - "the metaclass of a derived class " - "must be a (non-strict) subclass " - "of the metaclasses of all its bases") - return winner diff -r befd56673c80 -r 65c3af0d283b Lib/urllib/parse.py --- a/Lib/urllib/parse.py Sun May 20 02:34:13 2012 +1000 +++ b/Lib/urllib/parse.py Sat May 19 17:01:25 2012 -0400 @@ -44,9 +44,16 @@ 'imap', 'wais', 'file', 'mms', 'https', 'shttp', 'snews', 'prospero', 'rtsp', 'rtspu', 'rsync', '', 'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh'] +non_hierarchical = ['gopher', 'hdl', 'mailto', 'news', + 'telnet', 'wais', 'imap', 'snews', 'sip', 'sips'] uses_params = ['ftp', 'hdl', 'prospero', 'http', 'imap', 'https', 'shttp', 'rtsp', 'rtspu', 'sip', 'sips', 'mms', '', 'sftp'] +uses_query = ['http', 'wais', 'imap', 'https', 'shttp', 'mms', + 'gopher', 'rtsp', 'rtspu', 'sip', 'sips', ''] +uses_fragment = ['ftp', 'hdl', 'http', 'gopher', 'news', + 'nntp', 'wais', 'https', 'shttp', 'snews', + 'file', 'prospero', ''] # Characters valid in scheme names scheme_chars = ('abcdefghijklmnopqrstuvwxyz' @@ -338,21 +345,21 @@ if c not in scheme_chars: break else: - # make sure "url" is not actually a port number (in which case - # "scheme" is really part of the path) - rest = url[i+1:] - if not rest or any(c not in '0123456789' for c in rest): - # not a port number - scheme, url = url[:i].lower(), rest + try: + # make sure "url" is not actually a port number (in which case + # "scheme" is really part of the path + _testportnum = int(url[i+1:]) + except ValueError: + scheme, url = url[:i].lower(), url[i+1:] if url[:2] == '//': netloc, url = _splitnetloc(url, 2) if (('[' in netloc and ']' not in netloc) or (']' in netloc and '[' not in netloc)): raise ValueError("Invalid IPv6 URL") - if allow_fragments and '#' in url: + if allow_fragments and scheme in uses_fragment and '#' in url: url, fragment = url.split('#', 1) - if '?' in url: + if scheme in uses_query and '?' in url: url, query = url.split('?', 1) v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v diff -r befd56673c80 -r 65c3af0d283b Misc/ACKS --- a/Misc/ACKS Sun May 20 02:34:13 2012 +1000 +++ b/Misc/ACKS Sat May 19 17:01:25 2012 -0400 @@ -361,7 +361,6 @@ Dan Gass Andrew Gaul Stephen M. Gava -Xavier de Gaye Harry Henry Gebel Marius Gedminas Thomas Gellekum @@ -777,7 +776,6 @@ Joe Peterson Randy Pausch Samuele Pedroni -Justin Peel Marcel van der Peijl Berker Peksag Steven Pemberton diff -r befd56673c80 -r 65c3af0d283b Misc/NEWS --- a/Misc/NEWS Sun May 20 02:34:13 2012 +1000 +++ b/Misc/NEWS Sat May 19 17:01:25 2012 -0400 @@ -10,14 +10,6 @@ Core and Builtins ----------------- -- Issue #14494: Fix __future__.py and its documentation to note that - absolute imports are the default behavior in 3.0 instead of 2.7. - Patch by Sven Marnach. - -- Issue #9260: A finer-grained import lock. Most of the import sequence - now uses per-module locks rather than the global import lock, eliminating - well-known issues with threads and imports. - - Issue #14624: UTF-16 decoding is now 3x to 4x faster on various inputs. Patch by Serhiy Storchaka. @@ -42,33 +34,6 @@ Library ------- -- Issue #14588: The types module now provide new_class() and prepare_class() - functions to support PEP 3115 compliant dynamic class creation. Patch by - Daniel Urban and Nick Coghlan. - -- Issue #13152: Allow to specify a custom tabsize for expanding tabs in - textwrap. Patch by John Feuerstein. - -- Issue #14721: Send the correct 'Content-length: 0' header when the body is an - empty string ''. Initial Patch contributed by Arve Knudsen. - -- Issue #14072: Fix parsing of 'tel' URIs in urlparse by making the check for - ports stricter. - -- Issue #9374: Generic parsing of query and fragment portions of url for any - scheme. Supported both by RFC3986 and RFC2396. - -- Issue #14798: Fix the functions in pyclbr to raise an ImportError - when the first part of a dotted name is not a package. Patch by - Xavier de Gaye. - -- Issue #12098: multiprocessing on Windows now starts child processes - using the same sys.flags as the current process. Initial patch by - Sergey Mezentsev. - -- Issue #13031: Small speed-up for tarfile when unzipping tarfiles. - Patch by Justin Peel. - - Issue #14780: urllib.request.urlopen() now has a ``cadefault`` argument to use the default certificate store. Initial patch by James Oakley. @@ -163,20 +128,11 @@ Build ----- -- Upgrade Windows library versions: bzip 1.0.6, OpenSSL 1.0.1c. - - Issue #14693: Under non-Windows platforms, hashlib's fallback modules are always compiled, even if OpenSSL is present at build time. - Issue #13210: Windows build now uses VS2010, ported from VS2008. -Documentation -------------- - -- Issue #14588: The language reference now accurately documents the Python 3 - class definition process. Patch by Nick Coghlan. - - What's New in Python 3.3.0 Alpha 3? =================================== diff -r befd56673c80 -r 65c3af0d283b PC/VC6/readme.txt --- a/PC/VC6/readme.txt Sun May 20 02:34:13 2012 +1000 +++ b/PC/VC6/readme.txt Sat May 19 17:01:25 2012 -0400 @@ -153,9 +153,10 @@ Unpack into the "dist" directory, retaining the folder name from the archive - for example, the latest stable OpenSSL will install as - dist/openssl-1.0.1c + dist/openssl-1.0.0a - You need to use version 1.0.1c of OpenSSL. + You can (theoretically) use any version of OpenSSL you like - the + build process will automatically select the latest version. You can install the NASM assembler from http://www.nasm.us/ diff -r befd56673c80 -r 65c3af0d283b PC/VS8.0/pyproject.vsprops --- a/PC/VS8.0/pyproject.vsprops Sun May 20 02:34:13 2012 +1000 +++ b/PC/VS8.0/pyproject.vsprops Sat May 19 17:01:25 2012 -0400 @@ -58,7 +58,7 @@ /> = 4: + continue + if parts > best_parts: + best_parts = parts + best_name = c + if best_name is not None: + print("Found an SSL directory at '%s'" % (best_name,)) + else: + print("Could not find an SSL directory in '%s'" % (sources,)) + sys.stdout.flush() + return best_name def create_makefile64(makefile, m32): """Create and fix makefile for 64bit @@ -178,7 +202,7 @@ print("No Perl installation was found. Existing Makefiles are used.") sys.stdout.flush() # Look for SSL 2 levels up from pcbuild - ie, same place zlib etc all live. - ssl_dir = get_ssl_dir() + ssl_dir = find_best_ssl_dir(("..\\..",)) if ssl_dir is None: sys.exit(1) @@ -228,9 +252,9 @@ # Now run make. if arch == "amd64": - rc = os.system("nasm -f win64 -DNEAR -Ox -g ms\\uptable.asm") + rc = os.system("ml64 -c -Foms\\uptable.obj ms\\uptable.asm") if rc: - print("nasm assembler has failed.") + print("ml64 assembler has failed.") sys.exit(rc) copy(r"crypto\buildinf_%s.h" % arch, r"crypto\buildinf.h") diff -r befd56673c80 -r 65c3af0d283b PCbuild/pyproject.props --- a/PCbuild/pyproject.props Sun May 20 02:34:13 2012 +1000 +++ b/PCbuild/pyproject.props Sat May 19 17:01:25 2012 -0400 @@ -7,7 +7,7 @@ $(externalsDir)\sqlite-3.7.12 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.3 - $(externalsDir)\openssl-1.0.1c + $(externalsDir)\openssl-1.0.0a $(externalsDir)\tcltk $(externalsDir)\tcltk64 $(tcltkDir)\lib\tcl85.lib;$(tcltkDir)\lib\tk85.lib diff -r befd56673c80 -r 65c3af0d283b PCbuild/readme.txt --- a/PCbuild/readme.txt Sun May 20 02:34:13 2012 +1000 +++ b/PCbuild/readme.txt Sat May 19 17:01:25 2012 -0400 @@ -148,7 +148,7 @@ Get the source code through - svn export http://svn.python.org/projects/external/openssl-1.0.1c + svn export http://svn.python.org/projects/external/openssl-1.0.0a ** NOTE: if you use the Tools\buildbot\external(-amd64).bat approach for obtaining external sources then you don't need to manually get the source diff -r befd56673c80 -r 65c3af0d283b Python/import.c --- a/Python/import.c Sun May 20 02:34:13 2012 +1000 +++ b/Python/import.c Sat May 19 17:01:25 2012 -0400 @@ -1370,7 +1370,47 @@ PyObject * PyImport_ImportModuleNoBlock(const char *name) { - return PyImport_ImportModule(name); + PyObject *nameobj, *modules, *result; +#ifdef WITH_THREAD + long me; +#endif + + /* Try to get the module from sys.modules[name] */ + modules = PyImport_GetModuleDict(); + if (modules == NULL) + return NULL; + + nameobj = PyUnicode_FromString(name); + if (nameobj == NULL) + return NULL; + result = PyDict_GetItem(modules, nameobj); + if (result != NULL) { + Py_DECREF(nameobj); + Py_INCREF(result); + return result; + } + PyErr_Clear(); +#ifdef WITH_THREAD + /* check the import lock + * me might be -1 but I ignore the error here, the lock function + * takes care of the problem */ + me = PyThread_get_thread_ident(); + if (import_lock_thread == -1 || import_lock_thread == me) { + /* no thread or me is holding the lock */ + result = PyImport_Import(nameobj); + } + else { + PyErr_Format(PyExc_ImportError, + "Failed to import %R because the import lock" + "is held by another thread.", + nameobj); + result = NULL; + } +#else + result = PyImport_Import(nameobj); +#endif + Py_DECREF(nameobj); + return result; } @@ -1380,13 +1420,11 @@ int level) { _Py_IDENTIFIER(__import__); - _Py_IDENTIFIER(__initializing__); _Py_IDENTIFIER(__package__); _Py_IDENTIFIER(__path__); _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(_find_and_load); _Py_IDENTIFIER(_handle_fromlist); - _Py_IDENTIFIER(_lock_unlock_module); _Py_static_string(single_dot, "."); PyObject *abs_name = NULL; PyObject *builtins_import = NULL; @@ -1569,48 +1607,16 @@ goto error_with_unlock; } else if (mod != NULL) { - PyObject *value; - int initializing = 0; - Py_INCREF(mod); - /* Only call _bootstrap._lock_unlock_module() if __initializing__ is true. */ - value = _PyObject_GetAttrId(mod, &PyId___initializing__); - if (value == NULL) - PyErr_Clear(); - else { - initializing = PyObject_IsTrue(value); - Py_DECREF(value); - if (initializing == -1) - PyErr_Clear(); - } - if (initializing > 0) { - /* _bootstrap._lock_unlock_module() releases the import lock */ - value = _PyObject_CallMethodObjIdArgs(interp->importlib, - &PyId__lock_unlock_module, abs_name, - NULL); - if (value == NULL) - goto error; - Py_DECREF(value); - } - else { -#ifdef WITH_THREAD - if (_PyImport_ReleaseLock() < 0) { - PyErr_SetString(PyExc_RuntimeError, "not holding the import lock"); - goto error; - } -#endif - } } else { - /* _bootstrap._find_and_load() releases the import lock */ mod = _PyObject_CallMethodObjIdArgs(interp->importlib, &PyId__find_and_load, abs_name, builtins_import, NULL); if (mod == NULL) { - goto error; + goto error_with_unlock; } } - /* From now on we don't hold the import lock anymore. */ if (PyObject_Not(fromlist)) { if (level == 0 || PyUnicode_GET_LENGTH(name) > 0) { @@ -1619,12 +1625,12 @@ PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot); if (borrowed_dot == NULL) { - goto error; + goto error_with_unlock; } partition = PyUnicode_Partition(name, borrowed_dot); if (partition == NULL) { - goto error; + goto error_with_unlock; } if (PyUnicode_GET_LENGTH(PyTuple_GET_ITEM(partition, 1)) == 0) { @@ -1632,7 +1638,7 @@ Py_DECREF(partition); final_mod = mod; Py_INCREF(mod); - goto error; + goto exit_with_unlock; } front = PyTuple_GET_ITEM(partition, 0); @@ -1651,7 +1657,7 @@ abs_name_len - cut_off); Py_DECREF(front); if (to_return == NULL) { - goto error; + goto error_with_unlock; } final_mod = PyDict_GetItem(interp->modules, to_return); @@ -1677,8 +1683,8 @@ fromlist, builtins_import, NULL); } - goto error; + exit_with_unlock: error_with_unlock: #ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { diff -r befd56673c80 -r 65c3af0d283b Python/importlib.h Binary file Python/importlib.h has changed diff -r befd56673c80 -r 65c3af0d283b Tools/buildbot/external-common.bat --- a/Tools/buildbot/external-common.bat Sun May 20 02:34:13 2012 +1000 +++ b/Tools/buildbot/external-common.bat Sat May 19 17:01:25 2012 -0400 @@ -14,7 +14,7 @@ @rem if exist tk8.4.16 rd /s/q tk8.4.16 @rem if exist tk-8.4.18.1 rd /s/q tk-8.4.18.1 @rem if exist db-4.4.20 rd /s/q db-4.4.20 -@rem if exist openssl-1.0.1c rd /s/q openssl-1.0.1c +@rem if exist openssl-1.0.0a rd /s/q openssl-1.0.0a @rem if exist sqlite-3.7.12 rd /s/q sqlite-3.7.12 @rem bzip @@ -24,10 +24,7 @@ ) @rem OpenSSL -if not exist openssl-1.0.1c ( - rd /s/q openssl-1.0.0j - svn export http://svn.python.org/projects/external/openssl-1.0.1c -) +if not exist openssl-1.0.0a svn export http://svn.python.org/projects/external/openssl-1.0.0a @rem tcl/tk if not exist tcl-8.5.11.0 ( diff -r befd56673c80 -r 65c3af0d283b Tools/scripts/run_tests.py --- a/Tools/scripts/run_tests.py Sun May 20 02:34:13 2012 +1000 +++ b/Tools/scripts/run_tests.py Sat May 19 17:01:25 2012 -0400 @@ -10,10 +10,6 @@ import os import sys import test.support -try: - import threading -except ImportError: - threading = None def is_multiprocess_flag(arg): @@ -38,7 +34,7 @@ ]) if sys.platform == 'win32': args.append('-n') # Silence alerts under Windows - if threading and not any(is_multiprocess_flag(arg) for arg in regrtest_args): + if not any(is_multiprocess_flag(arg) for arg in regrtest_args): args.extend(['-j', '0']) # Use all CPU cores if not any(is_resource_use_flag(arg) for arg in regrtest_args): args.extend(['-u', 'all,-largefile,-audio,-gui'])