diff options
92 files changed, 2218 insertions, 853 deletions
@@ -76,6 +76,7 @@ a69a031ac1402dede8b1ef80096436bca6d371f3 v3.1 d18e9d71f369d8211f6ac87252c6d3211f9bd09f v3.1.3rc1 a4f75773c0060cee38b0bb651a7aba6f56b0e996 v3.1.3 32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1 +c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4 b37b7834757492d009b99cf0ca4d42d2153d7fac v3.2a1 56d4373cecb73c8b45126ba7b045b3c7b3f94b0b v3.2a2 da012d9a2c23d144e399d2e01a55b8a83ad94573 v3.2a3 diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 83b98f9..843707d 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -588,8 +588,8 @@ frequently-used builds will be described in the remainder of this section. Compiling the interpreter with the :c:macro:`Py_DEBUG` macro defined produces what is generally meant by "a debug build" of Python. :c:macro:`Py_DEBUG` is -enabled in the Unix build by adding :option:`--with-pydebug` to the -:file:`configure` command. It is also implied by the presence of the +enabled in the Unix build by adding ``--with-pydebug`` to the +:file:`./configure` command. It is also implied by the presence of the not-Python-specific :c:macro:`_DEBUG` macro. When :c:macro:`Py_DEBUG` is enabled in the Unix build, compiler optimization is disabled. diff --git a/Doc/distutils/install.rst b/Doc/distutils/install.rst index 31c1d7f..f8d6305 100644 --- a/Doc/distutils/install.rst +++ b/Doc/distutils/install.rst @@ -96,10 +96,16 @@ in the name of the downloaded archive, e.g. :file:`foo-1.0.tar.gz` or directory: :file:`foo-1.0` or :file:`widget-0.9.7`. Additionally, the distribution will contain a setup script :file:`setup.py`, and a file named :file:`README.txt` or possibly just :file:`README`, which should explain that -building and installing the module distribution is a simple matter of running :: +building and installing the module distribution is a simple matter of running +one command from a terminal:: python setup.py install +For Windows, this command should be run from a command prompt windows ("DOS +box"):: + + setup.py install + If all these things are true, then you already know how to build and install the modules you've just downloaded: Run the command above. Unless you need to install things in a non-standard way or customize the build process, you don't @@ -113,14 +119,11 @@ Standard Build and Install ========================== As described in section :ref:`inst-new-standard`, building and installing a module -distribution using the Distutils is usually one simple command:: +distribution using the Distutils is usually one simple command to run from a +terminal:: python setup.py install -On Unix, you'd run this command from a shell prompt; on Windows, you have to -open a command prompt window ("DOS box") and do it there; on Mac OS X, you open -a :command:`Terminal` window to get a shell prompt. - .. _inst-platform-variations: diff --git a/Doc/distutils/introduction.rst b/Doc/distutils/introduction.rst index 8dc604d..57d34a4 100644 --- a/Doc/distutils/introduction.rst +++ b/Doc/distutils/introduction.rst @@ -79,11 +79,17 @@ Some observations: for an example) To create a source distribution for this module, you would create a setup -script, :file:`setup.py`, containing the above code, and run:: +script, :file:`setup.py`, containing the above code, and run this command from a +terminal:: python setup.py sdist -which will create an archive file (e.g., tarball on Unix, ZIP file on Windows) +For Windows, open a command prompt windows ("DOS box") and change the command +to:: + + setup.py sdist + +:command:`sdist` will create an archive file (e.g., tarball on Unix, ZIP file on Windows) containing your setup script :file:`setup.py`, and your module :file:`foo.py`. The archive file will be named :file:`foo-1.0.tar.gz` (or :file:`.zip`), and will unpack into a directory :file:`foo-1.0`. diff --git a/Doc/documenting/markup.rst b/Doc/documenting/markup.rst index 57d9eeb..c005d0c 100644 --- a/Doc/documenting/markup.rst +++ b/Doc/documenting/markup.rst @@ -98,11 +98,12 @@ following example shows all of the features of this directive type:: Spam or ham the foo. -The signatures of object methods or data attributes should always include the -type name (``.. method:: FileInput.input(...)``), even if it is obvious from the -context which type they belong to; this is to enable consistent -cross-references. If you describe methods belonging to an abstract protocol, -such as "context managers", include a (pseudo-)type name too to make the +The signatures of object methods or data attributes should not include the +class name, but be nested in a class directive. The generated files will +reflect this nesting, and the target identifiers (for HTML output) will use +both the class and method name, to enable consistent cross-references. If you +describe methods belonging to an abstract protocol such as context managers, +use a class directive with a (pseudo-)type name too to make the index entries more informative. The directives are: diff --git a/Doc/library/builtins.rst b/Doc/library/builtins.rst index c495728..d4199d2 100644 --- a/Doc/library/builtins.rst +++ b/Doc/library/builtins.rst @@ -7,7 +7,9 @@ This module provides direct access to all 'built-in' identifiers of Python; for example, ``builtins.open`` is the full name for the built-in function -:func:`open`. +:func:`open`. See :ref:`built-in-funcs` and :ref:`built-in-consts` for +documentation. + This module is not normally accessed explicitly by most applications, but can be useful in modules that provide objects with the same name as a built-in value, diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 6c9b1e5..39a03dd 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -83,7 +83,7 @@ The class can be used to simulate nested scopes and is useful in templating. creating subcontexts that can be updated without altering values in any of the parent mappings. - .. attribute:: parents() + .. method:: parents() Returns a new :class:`ChainMap` containing all of the maps in the current instance except the first one. This is useful for skipping the first map diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index e5d13f3..3bd4531 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -169,6 +169,12 @@ to a :class:`ProcessPoolExecutor` will result in deadlock. of at most *max_workers* processes. If *max_workers* is ``None`` or not given, it will default to the number of processors on the machine. + .. versionchanged:: 3.3 + When one of the worker processes terminates abruptly, a + :exc:`BrokenProcessPool` error is now raised. Previously, behaviour + was undefined but operations on the executor or its futures would often + freeze or deadlock. + .. _processpoolexecutor-example: @@ -369,3 +375,16 @@ Module Functions :pep:`3148` -- futures - execute computations asynchronously The proposal which described this feature for inclusion in the Python standard library. + + +Exception classes +----------------- + +.. exception:: BrokenProcessPool + + Derived from :exc:`RuntimeError`, this exception class is raised when + one of the workers of a :class:`ProcessPoolExecutor` has terminated + in a non-clean fashion (for example, if it was killed from the outside). + + .. versionadded:: 3.3 + diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst index 51a1c26..fa61f68 100644 --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -1,3 +1,5 @@ +.. _built-in-consts: + Built-in Constants ================== diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 9346e99..e8353ea 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -436,6 +436,21 @@ supports sending logging messages to a remote or local Unix syslog. The record is formatted, and then sent to the syslog server. If exception information is present, it is *not* sent to the server. + .. versionchanged:: 3.2.1 + (See: :issue:`12168`.) In earlier versions, the message sent to the + syslog daemons was always terminated with a NUL byte, because early + versions of these daemons expected a NUL terminated message - even + though it's not in the relevant specification (RF 5424). More recent + versions of these daemons don't expect the NUL byte but strip it off + if it's there, and even more recent daemons (which adhere more closely + to RFC 5424) pass the NUL byte on as part of the message. + + To enable easier handling of syslog messages in the face of all these + differing daemon behaviours, the appending of the NUL byte has been + made configurable, through the use of a class-level attribute, + ``append_nul``. This defaults to ``True`` (preserving the existing + behaviour) but can be set to ``False`` on a ``SysLogHandler`` instance + in order for that instance to *not* append the NUL terminator. .. method:: encodePriority(facility, priority) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index eb2c718..5070487 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -453,6 +453,26 @@ The useful mapping keys in a :class:`LogRecord` are given in the section on record. Otherwise, the ISO8601 format is used. The resulting string is returned. + This function uses a user-configurable function to convert the creation + time to a tuple. By default, :func:`time.localtime` is used; to change + this for a particular formatter instance, set the ``converter`` attribute + to a function with the same signature as :func:`time.localtime` or + :func:`time.gmtime`. To change it for all formatters, for example if you + want all logging times to be shown in GMT, set the ``converter`` + attribute in the ``Formatter`` class. + + .. versionchanged:: 3.3 + Previously, the default ISO 8601 format was hard-coded as in this + example: ``2010-09-06 22:38:15,292`` where the part before the comma is + handled by a strptime format string (``'%Y-%m-%d %H:%M:%S'``), and the + part after the comma is a millisecond value. Because strptime does not + have a format placeholder for milliseconds, the millisecond value is + appended using another format string, ``'%s,%03d'`` – and both of these + format strings have been hardcoded into this method. With the change, + these strings are defined as class-level attributes which can be + overridden at the instance level when desired. The names of the + attributes are ``default_time_format`` (for the strptime format string) + and ``default_msec_format`` (for appending the millisecond value). .. method:: formatException(exc_info) @@ -544,6 +564,9 @@ wire). :param name: The name of the logger used to log the event represented by this LogRecord. :param level: The numeric level of the logging event (one of DEBUG, INFO etc.) + Note that this is converted to *two* attributes of the LogRecord: + ``levelno`` for the numeric value and ``levelname`` for the + corresponding level name. :param pathname: The full pathname of the source file where the logging call was made. :param lineno: The line number in the source file where the logging call was diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst index 7a901c9..7708028 100644 --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -190,12 +190,16 @@ To map anonymous memory, -1 should be passed as the fileno along with the length move will raise a :exc:`TypeError` exception. - .. method:: read(num) + .. method:: read([n]) - Return a :class:`bytes` containing up to *num* bytes starting from the - current file position; the file position is updated to point after the - bytes that were returned. + Return a :class:`bytes` containing up to *n* bytes starting from the + current file position. If the argument is omitted, *None* or negative, + return all bytes from the current file position to the end of the + mapping. The file position is updated to point after the bytes that were + returned. + .. versionchanged:: 3.3 + Argument can be omitted or *None*. .. method:: read_byte() diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index e1f4382..0e220d6 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -411,6 +411,20 @@ The :mod:`multiprocessing` package mostly replicates the API of the See :ref:`multiprocessing-auth-keys`. + .. attribute:: sentinel + + A numeric handle of a system object which will become "ready" when + the process ends. + + On Windows, this is an OS handle usable with the ``WaitForSingleObject`` + and ``WaitForMultipleObjects`` family of API calls. On Unix, this is + a file descriptor usable with primitives from the :mod:`select` module. + + You can use this value if you want to wait on several events at once. + Otherwise calling :meth:`join()` is simpler. + + .. versionadded:: 3.3 + .. method:: terminate() Terminate the process. On Unix this is done using the ``SIGTERM`` signal; diff --git a/Doc/library/os.rst b/Doc/library/os.rst index c62a00d..0a097d4 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -219,6 +219,17 @@ process and user. Availability: Unix. +.. function:: getgrouplist(user, group) + + Return list of group ids that *user* belongs to. If *group* is not in the + list, it is included; typically, *group* is specified as the group ID + field from the password record for *user*. + + Availability: Unix. + + .. versionadded:: 3.3 + + .. function:: getgroups() Return list of supplemental group ids associated with the current process. @@ -1019,11 +1030,11 @@ as internal buffering of data. Availability: Unix, Windows. -.. function:: pipe2(flags=0) +.. function:: pipe2(flags) Create a pipe with *flags* set atomically. - *flags* is optional and can be constructed by ORing together zero or more of - these values: :data:`O_NONBLOCK`, :data:`O_CLOEXEC`. + *flags* can be constructed by ORing together one or more of these values: + :data:`O_NONBLOCK`, :data:`O_CLOEXEC`. Return a pair of file descriptors ``(r, w)`` usable for reading and writing, respectively. diff --git a/Doc/library/packaging.compiler.rst b/Doc/library/packaging.compiler.rst index dac6263..cf88685 100644 --- a/Doc/library/packaging.compiler.rst +++ b/Doc/library/packaging.compiler.rst @@ -569,10 +569,10 @@ extension modules. .. class:: Extension The Extension class describes a single C or C++ extension module. It accepts - the following keyword arguments in its constructor + the following keyword arguments in its constructor: +------------------------+--------------------------------+---------------------------+ - | argument name | value | type | + | argument name | value | type [#]_ | +========================+================================+===========================+ | *name* | the full name of the | string | | | extension, including any | | @@ -670,3 +670,5 @@ extension modules. | | from the source extensions if | | | | not provided. | | +------------------------+--------------------------------+---------------------------+ + +.. [#] For values documented as lists, the given type is the type of each element. diff --git a/Doc/license.rst b/Doc/license.rst index 6c9ecf5..615b18c 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -847,7 +847,7 @@ expat ----- The :mod:`pyexpat` extension is built using an included copy of the expat -sources unless the build is configured :option:`--with-system-expat`:: +sources unless the build is configured ``--with-system-expat``:: Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd and Clark Cooper @@ -876,7 +876,7 @@ libffi ------ The :mod:`_ctypes` extension is built using an included copy of the libffi -sources unless the build is configured :option:`--with-system-libffi`:: +sources unless the build is configured ``--with-system-libffi``:: Copyright (c) 1996-2008 Red Hat, Inc and others. diff --git a/Doc/packaging/setupcfg.rst b/Doc/packaging/setupcfg.rst index 92ddb8b..2b01ffb 100644 --- a/Doc/packaging/setupcfg.rst +++ b/Doc/packaging/setupcfg.rst @@ -141,13 +141,16 @@ files Modules, scripts, data, documentation and other files to include in the distribution. +extension sections + Options used to build extension modules. + command sections Options given for specific commands, identical to those that can be given on the command line. Global options -============== +-------------- Contains global options for Packaging. This section is shared with Distutils. @@ -173,19 +176,23 @@ compilers compilers = hotcompiler.SmartCCompiler -setup_hook - defines a callable that will be called right after the - :file:`setup.cfg` file is read. The callable receives the configuration - in form of a mapping and can make some changes to it. *optional* +setup_hooks + Defines a list of callables to be called right after the :file:`setup.cfg` + file is read, before any other processing. The callables are executed in the + order they're found in the file; if one of them cannot be found, tools should + not stop, but for example produce a warning and continue with the next line. + Each callable receives the configuration as a dictionary (keys are + :file:`setup.cfg` sections, values are dictionaries of fields) and can make + any changes to it. *optional*, *multi* Example:: [global] - setup_hook = package.setup.customize_dist + setup_hooks = package.setup.customize_dist Metadata -======== +-------- The metadata section contains the metadata for the project as described in :PEP:`345`. Field names are case-insensitive. @@ -265,9 +272,9 @@ obsoletes-dist Same format than *requires-dist*. *optional*, *multi*, *environ* requires-python - Specifies the Python version the distribution requires. - The value is a version number, as described in PEP 345. - *optional*, *multi*, *environ* + Specifies the Python version the distribution requires. The value is a + comma-separated list of version predicates, as described in PEP 345. + *optional*, *environ* requires-externals a dependency in the system. This field is free-form, @@ -282,6 +289,7 @@ One extra field not present in PEP 345 is supported: description-file Path to a text file that will be used to fill the ``description`` field. + Multiple values are accepted; they must be separated by whitespace. ``description-file`` and ``description`` are mutually exclusive. *optional* @@ -308,7 +316,7 @@ from the fields present in the file. Files -===== +----- This section describes the files included in the project. @@ -352,7 +360,7 @@ Example:: Resources ---------- +^^^^^^^^^ This section describes the files used by the project which must not be installed in the same place that python modules or libraries, they are called @@ -448,10 +456,10 @@ Where {datafir} category will be platform-dependent. More control on source part -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +""""""""""""""""""""""""""" Glob syntax -""""""""""" +''''''''''' When you declare source file, you can use a glob-like syntax to match multiples file, for example:: @@ -469,7 +477,7 @@ Glob tokens are: .. TODO Add examples Order of declaration -"""""""""""""""""""" +'''''''''''''''''''' The order of declaration is important if one file match multiple rules. The last rules matched by file is used, this is useful if you have this source tree:: @@ -492,7 +500,7 @@ one by one, you can declare them in this way:: doc/README = {help} Exclude -""""""" +''''''' You can exclude some files of resources declaration by giving no destination, it can be useful if you have a non-resources file in the same directory of @@ -513,12 +521,12 @@ Your **files** section will be:: doc/RELEASES = More control on destination part -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +"""""""""""""""""""""""""""""""" .. _setupcfg-resources-base-prefix: Defining a base prefix -"""""""""""""""""""""" +'''''''''''''''''''''' When you define your resources, you can have more control of how the final path is computed. @@ -577,7 +585,7 @@ path will be:: Overwriting paths for categories -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +"""""""""""""""""""""""""""""""" This part is intended for system administrators or downstream OS packagers. @@ -614,18 +622,18 @@ The platform-dependent categories are: Defining extra categories -^^^^^^^^^^^^^^^^^^^^^^^^^ +""""""""""""""""""""""""" .. TODO Examples -^^^^^^^^ +"""""""" These examples are incremental but work unitarily. Resources in root dir -""""""""""""""""""""" +''''''''''''''''''''' Source tree:: @@ -647,7 +655,7 @@ So babar.sh and launch.sh will be placed in {scripts} directory. Now let's move all the scripts into a scripts directory. Resources in sub-directory -"""""""""""""""""""""""""" +'''''''''''''''''''''''''' Source tree:: @@ -673,7 +681,7 @@ scripts into {scripts} instead of {scripts}/scripts. Now let's add some docs. Resources in multiple sub-directories -""""""""""""""""""""""""""""""""""""" +''''''''''''''''''''''''''''''''''''' Source tree:: @@ -706,7 +714,7 @@ file is used. Now let's add some scripts for windows users. Complete example -"""""""""""""""" +'''''''''''''''' Source tree:: @@ -736,8 +744,37 @@ We use brace expansion syntax to place all the shell and batch scripts into {scripts} category. +Extension sections +------------------ + +If a project includes extension modules written in C or C++, each one of them +needs to have its options defined in a dedicated section. Here's an example:: + + [files] + packages = coconut + + [extension=_fastcoconut] + name = coconut._fastcoconut + language = cxx + sources = cxx_src/cononut_utils.cxx + cxx_src/python_module.cxx + include_dirs = /usr/include/gecode + /usr/include/blitz + extra_compile_args = + -fPIC -O2 + -DGECODE_VERSION=$(./gecode_version) -- sys.platform != 'win32' + /DGECODE_VERSION='win32' -- sys.platform == 'win32' + +The section name must start with ``extension=``; the righ-hand part is currently +discarded. Valid fields and their values are listed in the documentation of the +:class:`packaging.compiler.extension.Extension` class; values documented as +Python lists translate to multi-line values in the configuration file. In +addition, multi-line values accept environment markers on each line, after a +``--``. + + Command sections -================ +---------------- To pass options to commands without having to type them on the command line for each invocation, you can write them in the :file:`setup.cfg` file, in a diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 129f987..e628a02 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1343,7 +1343,8 @@ access (use of, assignment to, or deletion of ``x.name``) for class instances. .. method:: object.__dir__(self) - Called when :func:`dir` is called on the object. A list must be returned. + Called when :func:`dir` is called on the object. A sequence must be + returned. :func:`dir` converts the returned sequence to a list and sorts it. .. _descriptors: diff --git a/Doc/tutorial/interpreter.rst b/Doc/tutorial/interpreter.rst index eeddf76..4b83170 100644 --- a/Doc/tutorial/interpreter.rst +++ b/Doc/tutorial/interpreter.rst @@ -169,6 +169,8 @@ also be ``.pyw``, in that case, the console window that normally appears is suppressed. +.. _tut-source-encoding: + Source Code Encoding -------------------- diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 72b77cd..29c5772 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -511,7 +511,7 @@ Debug-mode variables ~~~~~~~~~~~~~~~~~~~~ Setting these variables only has an effect in a debug build of Python, that is, -if Python was configured with the :option:`--with-pydebug` build option. +if Python was configured with the ``--with-pydebug`` build option. .. envvar:: PYTHONTHREADDEBUG diff --git a/Lib/argparse.py b/Lib/argparse.py index 0658472..f0cfe27 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1969,17 +1969,12 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): # if we didn't consume all the argument strings, there were extras extras.extend(arg_strings[stop_index:]) - # if we didn't use all the Positional objects, there were too few - # arg strings supplied. - if positionals: - self.error(_('too few arguments')) - # make sure all required actions were present - for action in self._actions: - if action.required: - if action not in seen_actions: - name = _get_action_name(action) - self.error(_('argument %s is required') % name) + required_actions = [_get_action_name(action) for action in self._actions + if action.required and action not in seen_actions] + if required_actions: + self.error(_('the following arguments are required: %s') % + ', '.join(required_actions)) # make sure all required groups had one option present for group in self._mutually_exclusive_groups: diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index f0bf6d5..c2331e7 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -46,10 +46,11 @@ Process #1..n: __author__ = 'Brian Quinlan (brian@sweetapp.com)' import atexit +import os from concurrent.futures import _base import queue import multiprocessing -from multiprocessing.queues import SimpleQueue +from multiprocessing.queues import SimpleQueue, SentinelReady import threading import weakref @@ -122,7 +123,7 @@ def _process_worker(call_queue, result_queue): call_item = call_queue.get(block=True) if call_item is None: # Wake up queue management thread - result_queue.put(None) + result_queue.put(os.getpid()) return try: r = call_item.fn(*call_item.args, **call_item.kwargs) @@ -194,29 +195,63 @@ def _queue_management_worker(executor_reference, result_queue: A multiprocessing.Queue of _ResultItems generated by the process workers. """ - nb_shutdown_processes = 0 - def shutdown_one_process(): - """Tell a worker to terminate, which will in turn wake us again""" - nonlocal nb_shutdown_processes - call_queue.put(None) - nb_shutdown_processes += 1 + + def shutdown_worker(): + # This is an upper bound + nb_children_alive = sum(p.is_alive() for p in processes.values()) + for i in range(0, nb_children_alive): + call_queue.put(None) + # If .join() is not called on the created processes then + # some multiprocessing.Queue methods may deadlock on Mac OS + # X. + for p in processes.values(): + p.join() + while True: _add_call_item_to_queue(pending_work_items, work_ids_queue, call_queue) - result_item = result_queue.get() - if result_item is not None: - work_item = pending_work_items[result_item.work_id] - del pending_work_items[result_item.work_id] - - if result_item.exception: - work_item.future.set_exception(result_item.exception) - else: - work_item.future.set_result(result_item.result) - continue - # If we come here, we either got a timeout or were explicitly woken up. - # In either case, check whether we should start shutting down. + sentinels = [p.sentinel for p in processes.values()] + assert sentinels + try: + result_item = result_queue.get(sentinels=sentinels) + except SentinelReady as e: + # Mark the process pool broken so that submits fail right now. + executor = executor_reference() + if executor is not None: + executor._broken = True + executor._shutdown_thread = True + del executor + # All futures in flight must be marked failed + for work_id, work_item in pending_work_items.items(): + work_item.future.set_exception( + BrokenProcessPool( + "A process in the process pool was " + "terminated abruptly while the future was " + "running or pending." + )) + pending_work_items.clear() + # Terminate remaining workers forcibly: the queues or their + # locks may be in a dirty state and block forever. + for p in processes.values(): + p.terminate() + for p in processes.values(): + p.join() + return + if isinstance(result_item, int): + # Clean shutdown of a worker using its PID + # (avoids marking the executor broken) + del processes[result_item] + elif result_item is not None: + work_item = pending_work_items.pop(result_item.work_id, None) + # work_item can be None if another process terminated (see above) + if work_item is not None: + if result_item.exception: + work_item.future.set_exception(result_item.exception) + else: + work_item.future.set_result(result_item.result) + # Check whether we should start shutting down. executor = executor_reference() # No more work items can be added if: # - The interpreter is shutting down OR @@ -226,17 +261,11 @@ def _queue_management_worker(executor_reference, # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not pending_work_items: - while nb_shutdown_processes < len(processes): - shutdown_one_process() - # If .join() is not called on the created processes then - # some multiprocessing.Queue methods may deadlock on Mac OS - # X. - for p in processes: - p.join() + shutdown_worker() return else: # Start shutting down by telling a process it can exit. - shutdown_one_process() + call_queue.put(None) del executor _system_limits_checked = False @@ -264,6 +293,14 @@ def _check_system_limits(): _system_limited = "system provides too few semaphores (%d available, 256 necessary)" % nsems_max raise NotImplementedError(_system_limited) + +class BrokenProcessPool(RuntimeError): + """ + Raised when a process in a ProcessPoolExecutor terminated abruptly + while a future was in the running state. + """ + + class ProcessPoolExecutor(_base.Executor): def __init__(self, max_workers=None): """Initializes a new ProcessPoolExecutor instance. @@ -288,11 +325,13 @@ class ProcessPoolExecutor(_base.Executor): self._result_queue = SimpleQueue() self._work_ids = queue.Queue() self._queue_management_thread = None - self._processes = set() + # Map of pids to processes + self._processes = {} # Shutdown is a two-step process. self._shutdown_thread = False self._shutdown_lock = threading.Lock() + self._broken = False self._queue_count = 0 self._pending_work_items = {} @@ -302,6 +341,8 @@ class ProcessPoolExecutor(_base.Executor): def weakref_cb(_, q=self._result_queue): q.put(None) if self._queue_management_thread is None: + # Start the processes so that their sentinels are known. + self._adjust_process_count() self._queue_management_thread = threading.Thread( target=_queue_management_worker, args=(weakref.ref(self, weakref_cb), @@ -321,10 +362,13 @@ class ProcessPoolExecutor(_base.Executor): args=(self._call_queue, self._result_queue)) p.start() - self._processes.add(p) + self._processes[p.pid] = p def submit(self, fn, *args, **kwargs): with self._shutdown_lock: + if self._broken: + raise BrokenProcessPool('A child process terminated ' + 'abruptly, the process pool is not usable anymore') if self._shutdown_thread: raise RuntimeError('cannot schedule new futures after shutdown') @@ -338,7 +382,6 @@ class ProcessPoolExecutor(_base.Executor): self._result_queue.put(None) self._start_queue_management_thread() - self._adjust_process_count() return f submit.__doc__ = _base.Executor.submit.__doc__ diff --git a/Lib/idlelib/config-main.def b/Lib/idlelib/config-main.def index 5ddd098..9546e2b 100644 --- a/Lib/idlelib/config-main.def +++ b/Lib/idlelib/config-main.def @@ -46,8 +46,8 @@ [General] editor-on-startup= 0 autosave= 0 -print-command-posix=lpr %s -print-command-win=start /min notepad /p %s +print-command-posix=lpr %%s +print-command-win=start /min notepad /p %%s delete-exitfunc= 1 [EditorWindow] diff --git a/Lib/importlib/test/__main__.py b/Lib/importlib/test/__main__.py index decc53d..a1990b1 100644 --- a/Lib/importlib/test/__main__.py +++ b/Lib/importlib/test/__main__.py @@ -4,7 +4,6 @@ Specifying the ``--builtin`` flag will run tests, where applicable, with builtins.__import__ instead of importlib.__import__. """ -import importlib from importlib.test.import_ import util import os.path from test.support import run_unittest @@ -13,11 +12,7 @@ import unittest def test_main(): - if '__pycache__' in __file__: - parts = __file__.split(os.path.sep) - start_dir = sep.join(parts[:-2]) - else: - start_dir = os.path.dirname(__file__) + start_dir = os.path.dirname(__file__) top_dir = os.path.dirname(os.path.dirname(start_dir)) test_loader = unittest.TestLoader() if '--builtin' in sys.argv: diff --git a/Lib/inspect.py b/Lib/inspect.py index f200a82..aa4c30f 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -518,9 +518,13 @@ def findsource(object): or code object. The source code is returned as a list of all the lines in the file and the line number indexes a line in that list. An IOError is raised if the source code cannot be retrieved.""" - file = getsourcefile(object) - if not file: + + file = getfile(object) + sourcefile = getsourcefile(object) + if not sourcefile and file[0] + file[-1] != '<>': raise IOError('source code not available') + file = sourcefile if sourcefile else file + module = getmodule(object, file) if module: lines = linecache.getlines(file, module.__dict__) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 1a4b241..509dae6 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -467,6 +467,9 @@ class Formatter(object): self._fmt = self._style._fmt self.datefmt = datefmt + default_time_format = '%Y-%m-%d %H:%M:%S' + default_msec_format = '%s,%03d' + def formatTime(self, record, datefmt=None): """ Return the creation time of the specified LogRecord as formatted text. @@ -489,8 +492,8 @@ class Formatter(object): if datefmt: s = time.strftime(datefmt, ct) else: - t = time.strftime("%Y-%m-%d %H:%M:%S", ct) - s = "%s,%03d" % (t, record.msecs) # the use of % here is internal + t = time.strftime(self.default_time_format, ct) + s = self.default_msec_format % (t, record.msecs) return s def formatException(self, ei): diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index f17db0e..5779a7d 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -769,6 +769,8 @@ class SysLogHandler(logging.Handler): """ return self.priority_map.get(levelName, "warning") + append_nul = True # some old syslog daemons expect a NUL terminator + def emit(self, record): """ Emit a record. @@ -776,7 +778,9 @@ class SysLogHandler(logging.Handler): The record is formatted, and then sent to the syslog server. If exception information is present, it is NOT sent to the server. """ - msg = self.format(record) + '\000' + msg = self.format(record) + if self.append_nul: + msg += '\000' """ We need to convert record level to lowercase, maybe this will change in the future. diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 415e210..ede2908 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -48,14 +48,18 @@ import itertools import _multiprocessing from multiprocessing import current_process, AuthenticationError, BufferTooShort -from multiprocessing.util import get_temp_dir, Finalize, sub_debug, debug +from multiprocessing.util import ( + get_temp_dir, Finalize, sub_debug, debug, _eintr_retry) try: from _multiprocessing import win32 + from _subprocess import WAIT_OBJECT_0, WAIT_TIMEOUT, INFINITE except ImportError: if sys.platform == 'win32': raise win32 = None +_select = _eintr_retry(select.select) + # # # @@ -118,6 +122,15 @@ def address_type(address): else: raise ValueError('address type of %r unrecognized' % address) + +class SentinelReady(Exception): + """ + Raised when a sentinel is ready when polling. + """ + def __init__(self, *args): + Exception.__init__(self, *args) + self.sentinels = args[0] + # # Connection classes # @@ -253,19 +266,17 @@ class _ConnectionBase: (offset + size) // itemsize]) return size - def recv(self): + def recv(self, sentinels=None): """Receive a (picklable) object""" self._check_closed() self._check_readable() - buf = self._recv_bytes() + buf = self._recv_bytes(sentinels=sentinels) return pickle.loads(buf.getbuffer()) def poll(self, timeout=0.0): """Whether there is any input available to be read""" self._check_closed() self._check_readable() - if timeout < 0.0: - timeout = None return self._poll(timeout) @@ -274,61 +285,88 @@ if win32: class PipeConnection(_ConnectionBase): """ Connection class based on a Windows named pipe. + Overlapped I/O is used, so the handles must have been created + with FILE_FLAG_OVERLAPPED. """ + _buffered = b'' def _close(self): win32.CloseHandle(self._handle) def _send_bytes(self, buf): - nwritten = win32.WriteFile(self._handle, buf) + overlapped = win32.WriteFile(self._handle, buf, overlapped=True) + nwritten, complete = overlapped.GetOverlappedResult(True) + assert complete assert nwritten == len(buf) - def _recv_bytes(self, maxsize=None): + def _recv_bytes(self, maxsize=None, sentinels=()): + if sentinels: + self._poll(-1.0, sentinels) buf = io.BytesIO() - bufsize = 512 - if maxsize is not None: - bufsize = min(bufsize, maxsize) - try: - firstchunk, complete = win32.ReadFile(self._handle, bufsize) - except IOError as e: - if e.errno == win32.ERROR_BROKEN_PIPE: - raise EOFError - raise - lenfirstchunk = len(firstchunk) - buf.write(firstchunk) - if complete: - return buf + firstchunk = self._buffered + if firstchunk: + lenfirstchunk = len(firstchunk) + buf.write(firstchunk) + self._buffered = b'' + else: + # A reasonable size for the first chunk transfer + bufsize = 128 + if maxsize is not None and maxsize < bufsize: + bufsize = maxsize + try: + overlapped = win32.ReadFile(self._handle, bufsize, overlapped=True) + lenfirstchunk, complete = overlapped.GetOverlappedResult(True) + firstchunk = overlapped.getbuffer() + assert lenfirstchunk == len(firstchunk) + except IOError as e: + if e.errno == win32.ERROR_BROKEN_PIPE: + raise EOFError + raise + buf.write(firstchunk) + if complete: + return buf navail, nleft = win32.PeekNamedPipe(self._handle) if maxsize is not None and lenfirstchunk + nleft > maxsize: return None - lastchunk, complete = win32.ReadFile(self._handle, nleft) - assert complete - buf.write(lastchunk) + if nleft > 0: + overlapped = win32.ReadFile(self._handle, nleft, overlapped=True) + res, complete = overlapped.GetOverlappedResult(True) + assert res == nleft + assert complete + buf.write(overlapped.getbuffer()) return buf - def _poll(self, timeout): + def _poll(self, timeout, sentinels=()): + # Fast non-blocking path navail, nleft = win32.PeekNamedPipe(self._handle) if navail > 0: return True elif timeout == 0.0: return False - # Setup a polling loop (translated straight from old - # pipe_connection.c) + # Blocking: use overlapped I/O if timeout < 0.0: - deadline = None + timeout = INFINITE else: - deadline = time.time() + timeout - delay = 0.001 - max_delay = 0.02 - while True: - time.sleep(delay) - navail, nleft = win32.PeekNamedPipe(self._handle) - if navail > 0: - return True - if deadline and time.time() > deadline: - return False - if delay < max_delay: - delay += 0.001 + timeout = int(timeout * 1000 + 0.5) + overlapped = win32.ReadFile(self._handle, 1, overlapped=True) + try: + handles = [overlapped.event] + handles += sentinels + res = win32.WaitForMultipleObjects(handles, False, timeout) + finally: + # Always cancel overlapped I/O in the same thread + # (because CancelIoEx() appears only in Vista) + overlapped.cancel() + if res == WAIT_TIMEOUT: + return False + idx = res - WAIT_OBJECT_0 + if idx == 0: + # I/O was successful, store received data + overlapped.GetOverlappedResult(True) + self._buffered += overlapped.getbuffer() + return True + assert 0 < idx < len(handles) + raise SentinelReady([handles[idx]]) class Connection(_ConnectionBase): @@ -357,11 +395,18 @@ class Connection(_ConnectionBase): break buf = buf[n:] - def _recv(self, size, read=_read): + def _recv(self, size, sentinels=(), read=_read): buf = io.BytesIO() + handle = self._handle + if sentinels: + handles = [handle] + sentinels remaining = size while remaining > 0: - chunk = read(self._handle, remaining) + if sentinels: + r = _select(handles, [], [])[0] + if handle not in r: + raise SentinelReady(r) + chunk = read(handle, remaining) n = len(chunk) if n == 0: if remaining == size: @@ -381,15 +426,17 @@ class Connection(_ConnectionBase): if n > 0: self._send(buf) - def _recv_bytes(self, maxsize=None): - buf = self._recv(4) + def _recv_bytes(self, maxsize=None, sentinels=()): + buf = self._recv(4, sentinels) size, = struct.unpack("=i", buf.getvalue()) if maxsize is not None and size > maxsize: return None - return self._recv(size) + return self._recv(size, sentinels) def _poll(self, timeout): - r = select.select([self._handle], [], [], timeout)[0] + if timeout < 0.0: + timeout = None + r = _select([self._handle], [], [], timeout)[0] return bool(r) @@ -495,23 +542,21 @@ else: obsize, ibsize = 0, BUFSIZE h1 = win32.CreateNamedPipe( - address, openmode, + address, openmode | win32.FILE_FLAG_OVERLAPPED, win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | win32.PIPE_WAIT, 1, obsize, ibsize, win32.NMPWAIT_WAIT_FOREVER, win32.NULL ) h2 = win32.CreateFile( - address, access, 0, win32.NULL, win32.OPEN_EXISTING, 0, win32.NULL + address, access, 0, win32.NULL, win32.OPEN_EXISTING, + win32.FILE_FLAG_OVERLAPPED, win32.NULL ) win32.SetNamedPipeHandleState( h2, win32.PIPE_READMODE_MESSAGE, None, None ) - try: - win32.ConnectNamedPipe(h1, win32.NULL) - except WindowsError as e: - if e.args[0] != win32.ERROR_PIPE_CONNECTED: - raise + overlapped = win32.ConnectNamedPipe(h1, overlapped=True) + overlapped.GetOverlappedResult(True) c1 = PipeConnection(h1, writable=duplex) c2 = PipeConnection(h2, readable=duplex) diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py index 3d95557..a2c61ef 100644 --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -35,6 +35,7 @@ import os import sys import signal +import select from multiprocessing import util, process @@ -101,10 +102,12 @@ else: if sys.platform != 'win32': import time + import select exit = os._exit duplicate = os.dup close = os.close + _select = util._eintr_retry(select.select) # # We define a Popen class similar to the one from subprocess, but @@ -118,8 +121,12 @@ if sys.platform != 'win32': sys.stderr.flush() self.returncode = None + r, w = os.pipe() + self.sentinel = r + self.pid = os.fork() if self.pid == 0: + os.close(r) if 'random' in sys.modules: import random random.seed() @@ -128,6 +135,11 @@ if sys.platform != 'win32': sys.stderr.flush() os._exit(code) + # `w` will be closed when the child exits, at which point `r` + # will become ready for reading (using e.g. select()). + os.close(w) + util.Finalize(self, os.close, (r,)) + def poll(self, flag=os.WNOHANG): if self.returncode is None: try: @@ -145,20 +157,14 @@ if sys.platform != 'win32': return self.returncode def wait(self, timeout=None): - if timeout is None: - return self.poll(0) - deadline = time.time() + timeout - delay = 0.0005 - while 1: - res = self.poll() - if res is not None: - break - remaining = deadline - time.time() - if remaining <= 0: - break - delay = min(delay * 2, remaining, 0.05) - time.sleep(delay) - return res + if self.returncode is None: + if timeout is not None: + r = _select([self.sentinel], [], [], timeout)[0] + if not r: + return None + # This shouldn't block if select() returned successfully. + return self.poll(os.WNOHANG if timeout == 0.0 else 0) + return self.returncode def terminate(self): if self.returncode is None: @@ -258,6 +264,7 @@ else: self.pid = pid self.returncode = None self._handle = hp + self.sentinel = int(hp) # send information to child prep_data = get_preparation_data(process_obj._name) diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py index 3fb9ff6..99ee532 100644 --- a/Lib/multiprocessing/process.py +++ b/Lib/multiprocessing/process.py @@ -132,6 +132,7 @@ class Process(object): else: from .forking import Popen self._popen = Popen(self) + self._sentinel = self._popen.sentinel _current_process._children.add(self) def terminate(self): @@ -218,6 +219,17 @@ class Process(object): pid = ident + @property + def sentinel(self): + ''' + Return a file descriptor (Unix) or handle (Windows) suitable for + waiting for process termination. + ''' + try: + return self._sentinel + except AttributeError: + raise ValueError("process not started") + def __repr__(self): if self is _current_process: status = 'started' diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py index 3280a25..3324363 100644 --- a/Lib/multiprocessing/queues.py +++ b/Lib/multiprocessing/queues.py @@ -44,7 +44,7 @@ import weakref from queue import Empty, Full import _multiprocessing -from multiprocessing import Pipe +from multiprocessing.connection import Pipe, SentinelReady from multiprocessing.synchronize import Lock, BoundedSemaphore, Semaphore, Condition from multiprocessing.util import debug, info, Finalize, register_after_fork from multiprocessing.forking import assert_spawning @@ -372,10 +372,10 @@ class SimpleQueue(object): def _make_methods(self): recv = self._reader.recv racquire, rrelease = self._rlock.acquire, self._rlock.release - def get(): + def get(*, sentinels=None): racquire() try: - return recv() + return recv(sentinels) finally: rrelease() self.get = get diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py index 30b7a85..b59ac9f 100644 --- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -32,9 +32,11 @@ # SUCH DAMAGE. # +import functools import itertools import weakref import atexit +import select import threading # we want threading to install it's # cleanup function before multiprocessing does @@ -315,3 +317,21 @@ class ForkAwareLocal(threading.local): register_after_fork(self, lambda obj : obj.__dict__.clear()) def __reduce__(self): return type(self), () + + +# +# Automatic retry after EINTR +# + +def _eintr_retry(func, _errors=(EnvironmentError, select.error)): + @functools.wraps(func) + def wrapped(*args, **kwargs): + while True: + try: + return func(*args, **kwargs) + except _errors as e: + # select.error has no `errno` attribute + if e.args[0] == errno.EINTR: + continue + raise + return wrapped diff --git a/Lib/netrc.py b/Lib/netrc.py index a60b8b7..c96db6f 100644 --- a/Lib/netrc.py +++ b/Lib/netrc.py @@ -2,7 +2,7 @@ # Module and documentation by Eric S. Raymond, 21 Dec 1998 -import os, shlex +import io, os, shlex __all__ = ["netrc", "NetrcParseError"] @@ -37,12 +37,14 @@ class netrc: lexer.commenters = lexer.commenters.replace('#', '') while 1: # Look for a machine, default, or macdef top-level keyword + saved_lineno = lexer.lineno toplevel = tt = lexer.get_token() if not tt: break elif tt[0] == '#': - fp.readline(); - continue; + if lexer.lineno == saved_lineno and len(tt) == 1: + lexer.instream.readline() + continue elif tt == 'machine': entryname = lexer.get_token() elif tt == 'default': @@ -68,8 +70,8 @@ class netrc: self.hosts[entryname] = {} while 1: tt = lexer.get_token() - if (tt=='' or tt == 'machine' or - tt == 'default' or tt =='macdef'): + if (tt.startswith('#') or + tt in {'', 'machine', 'default', 'macdef'}): if password: self.hosts[entryname] = (login, account, password) lexer.push_token(tt) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index ec8a7ab..826be87 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -672,3 +672,14 @@ except ImportError: def sameopenfile(f1, f2): """Test whether two file objects reference the same file""" return _getfileinformation(f1) == _getfileinformation(f2) + + +try: + # The genericpath.isdir implementation uses os.stat and checks the mode + # attribute to tell whether or not the path is a directory. + # This is overkill on Windows - just pass the path to GetFileAttributes + # and check the attribute from there. + from nt import _isdir as isdir +except ImportError: + # Use genericpath.isdir as imported above. + pass diff --git a/Lib/packaging/command/sdist.py b/Lib/packaging/command/sdist.py index a19203f..09b26db 100644 --- a/Lib/packaging/command/sdist.py +++ b/Lib/packaging/command/sdist.py @@ -201,15 +201,20 @@ class sdist(Command): self.filelist.write(self.manifest) def add_defaults(self): - """Add all the default files to self.filelist: - - all pure Python modules mentioned in setup script - - all files pointed by package_data (build_py) - - all files defined in data_files. - - all files defined as scripts. - - all C sources listed as part of extensions or C libraries - in the setup script (doesn't catch C headers!) - Everything is optional. + """Add all default files to self.filelist. + + In addition to the setup.cfg file, this will include all files returned + by the get_source_files of every registered command. This will find + Python modules and packages, data files listed in package_data_, + data_files and extra_files, scripts, C sources of extension modules or + C libraries (headers are missing). """ + if os.path.exists('setup.cfg'): + self.filelist.append('setup.cfg') + else: + logger.warning("%s: standard 'setup.cfg' file not found", + self.get_command_name()) + for cmd_name in get_command_names(): try: cmd_obj = self.get_finalized_command(cmd_name) diff --git a/Lib/packaging/config.py b/Lib/packaging/config.py index 6df2bab..21bbcf8 100644 --- a/Lib/packaging/config.py +++ b/Lib/packaging/config.py @@ -9,7 +9,8 @@ from configparser import RawConfigParser from packaging import logger from packaging.errors import PackagingOptionError from packaging.compiler.extension import Extension -from packaging.util import check_environ, iglob, resolve_name, strtobool +from packaging.util import (check_environ, iglob, resolve_name, strtobool, + split_multiline) from packaging.compiler import set_compiler from packaging.command import set_command from packaging.markers import interpret @@ -60,17 +61,15 @@ def get_resources_dests(resources_root, rules): class Config: - """Reads configuration files and work with the Distribution instance - """ + """Class used to work with configuration files""" def __init__(self, dist): self.dist = dist - self.setup_hook = None + self.setup_hooks = [] - def run_hook(self, config): - if self.setup_hook is None: - return - # the hook gets only the config - self.setup_hook(config) + def run_hooks(self, config): + """Run setup hooks in the order defined in the spec.""" + for hook in self.setup_hooks: + hook(config) def find_config_files(self): """Find as many configuration files as should be processed for this @@ -124,29 +123,26 @@ class Config: # XXX return value - def _multiline(self, value): - value = [v for v in - [v.strip() for v in value.split('\n')] - if v != ''] - return value - def _read_setup_cfg(self, parser, cfg_filename): cfg_directory = os.path.dirname(os.path.abspath(cfg_filename)) content = {} for section in parser.sections(): content[section] = dict(parser.items(section)) - # global:setup_hook is called *first* + # global setup hooks are called first if 'global' in content: - if 'setup_hook' in content['global']: - setup_hook = content['global']['setup_hook'] - try: - self.setup_hook = resolve_name(setup_hook) - except ImportError as e: - logger.warning('could not import setup_hook: %s', - e.args[0]) - else: - self.run_hook(content) + if 'setup_hooks' in content['global']: + setup_hooks = split_multiline(content['global']['setup_hooks']) + + for line in setup_hooks: + try: + hook = resolve_name(line) + except ImportError as e: + logger.warning('cannot find setup hook: %s', e.args[0]) + else: + self.setup_hooks.append(hook) + + self.run_hooks(content) metadata = self.dist.metadata @@ -155,7 +151,7 @@ class Config: for key, value in content['metadata'].items(): key = key.replace('_', '-') if metadata.is_multi_field(key): - value = self._multiline(value) + value = split_multiline(value) if key == 'project-url': value = [(label.strip(), url.strip()) @@ -168,21 +164,18 @@ class Config: "mutually exclusive") raise PackagingOptionError(msg) - if isinstance(value, list): - filenames = value - else: - filenames = value.split() + filenames = value.split() - # concatenate each files - value = '' + # concatenate all files + value = [] for filename in filenames: # will raise if file not found with open(filename) as description_file: - value += description_file.read().strip() + '\n' + value.append(description_file.read().strip()) # add filename as a required file if filename not in metadata.requires_files: metadata.requires_files.append(filename) - value = value.strip() + value = '\n'.join(value).strip() key = 'description' if metadata.is_metadata_field(key): @@ -192,7 +185,7 @@ class Config: files = content['files'] self.dist.package_dir = files.pop('packages_root', None) - files = dict((key, self._multiline(value)) for key, value in + files = dict((key, split_multiline(value)) for key, value in files.items()) self.dist.packages = [] @@ -310,7 +303,7 @@ class Config: opt = opt.replace('-', '_') if opt == 'sub_commands': - val = self._multiline(val) + val = split_multiline(val) if isinstance(val, str): val = [val] @@ -348,14 +341,14 @@ class Config: raise PackagingOptionError(msg) def _load_compilers(self, compilers): - compilers = self._multiline(compilers) + compilers = split_multiline(compilers) if isinstance(compilers, str): compilers = [compilers] for compiler in compilers: set_compiler(compiler.strip()) def _load_commands(self, commands): - commands = self._multiline(commands) + commands = split_multiline(commands) if isinstance(commands, str): commands = [commands] for command in commands: diff --git a/Lib/packaging/create.py b/Lib/packaging/create.py index c18d42f..917b6cf 100644 --- a/Lib/packaging/create.py +++ b/Lib/packaging/create.py @@ -175,11 +175,11 @@ def convert_yn_to_bool(yn, yes=True, no=False): def _build_classifiers_dict(classifiers): d = {} for key in classifiers: - subDict = d + subdict = d for subkey in key.split(' :: '): - if not subkey in subDict: - subDict[subkey] = {} - subDict = subDict[subkey] + if subkey not in subdict: + subdict[subkey] = {} + subdict = subdict[subkey] return d CLASSIFIERS = _build_classifiers_dict(_CLASSIFIERS_LIST) diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py index 22d4b13..e3c57ba 100644 --- a/Lib/packaging/database.py +++ b/Lib/packaging/database.py @@ -104,12 +104,12 @@ def _generate_cache(use_egg_info=False, paths=sys.path): for dist in _yield_distributions(gen_dist, gen_egg, paths): if isinstance(dist, Distribution): _cache_path[dist.path] = dist - if not dist.name in _cache_name: + if dist.name not in _cache_name: _cache_name[dist.name] = [] _cache_name[dist.name].append(dist) else: _cache_path_egg[dist.path] = dist - if not dist.name in _cache_name_egg: + if dist.name not in _cache_name_egg: _cache_name_egg[dist.name] = [] _cache_name_egg[dist.name].append(dist) @@ -150,7 +150,7 @@ class Distribution: self.version = self.metadata['Version'] self.path = path - if _cache_enabled and not path in _cache_path: + if _cache_enabled and path not in _cache_path: _cache_path[path] = self def __repr__(self): diff --git a/Lib/packaging/depgraph.py b/Lib/packaging/depgraph.py index 48ea3d9..b3c555a 100644 --- a/Lib/packaging/depgraph.py +++ b/Lib/packaging/depgraph.py @@ -58,7 +58,7 @@ class DependencyGraph: """ self.adjacency_list[x].append((y, label)) # multiple edges are allowed, so be careful - if not x in self.reverse_list[y]: + if x not in self.reverse_list[y]: self.reverse_list[y].append(x) def add_missing(self, distribution, requirement): @@ -72,7 +72,7 @@ class DependencyGraph: self.missing[distribution].append(requirement) def _repr_dist(self, dist): - return '%s %s' % (dist.name, dist.metadata['Version']) + return '%r %s' % (dist.name, dist.metadata['Version']) def repr_node(self, dist, level=1): """Prints only a subgraph""" @@ -154,10 +154,10 @@ def generate_graph(dists): if len(comps) == 2: version = comps[1] if len(version) < 3 or version[0] != '(' or version[-1] != ')': - raise PackagingError('Distribution %s has ill formed' \ - 'provides field: %s' % (dist.name, p)) + raise PackagingError('distribution %r has ill-formed' + 'provides field: %r' % (dist.name, p)) version = version[1:-1] # trim off parenthesis - if not name in provided: + if name not in provided: provided[name] = [] provided[name].append((version, dist)) @@ -174,7 +174,7 @@ def generate_graph(dists): name = predicate.name - if not name in provided: + if name not in provided: graph.add_missing(dist, req) else: matched = False @@ -204,8 +204,9 @@ def dependent_dists(dists, dist): :param dists: a list of distributions :param dist: a distribution, member of *dists* for which we are interested """ - if not dist in dists: - raise ValueError('The given distribution is not a member of the list') + if dist not in dists: + raise ValueError('given distribution %r is not a member of the list' % + dist.name) graph = generate_graph(dists) dep = [dist] # dependent distributions @@ -215,7 +216,7 @@ def dependent_dists(dists, dist): node = fringe.pop() dep.append(node) for prev in graph.reverse_list[node]: - if not prev in dep: + if prev not in dep: fringe.append(prev) dep.pop(0) # remove dist from dep, was there to prevent infinite loops @@ -236,17 +237,19 @@ def main(): except Exception as e: tempout.seek(0) tempout = tempout.read() - print('Could not generate the graph\n%s\n%s\n' % (tempout, e)) + print('Could not generate the graph') + print(tempout) + print(e) sys.exit(1) for dist, reqs in graph.missing.items(): if len(reqs) > 0: - print("Warning: Missing dependencies for %s:" % dist.name, + print("Warning: Missing dependencies for %r:" % dist.name, ", ".join(reqs)) # XXX replace with argparse if len(sys.argv) == 1: print('Dependency graph:') - print(' ' + repr(graph).replace('\n', '\n ')) + print(' ', repr(graph).replace('\n', '\n ')) sys.exit(0) elif len(sys.argv) > 1 and sys.argv[1] in ('-d', '--dot'): if len(sys.argv) > 2: @@ -259,7 +262,7 @@ def main(): tempout.seek(0) tempout = tempout.read() print(tempout) - print('Dot file written at "%s"' % filename) + print('Dot file written at %r' % filename) sys.exit(0) else: print('Supported option: -d [filename]') diff --git a/Lib/packaging/dist.py b/Lib/packaging/dist.py index 6065e78..5c390ce 100644 --- a/Lib/packaging/dist.py +++ b/Lib/packaging/dist.py @@ -509,14 +509,14 @@ Common commands: (see '--help-commands' for more) options = self.global_options parser.set_option_table(options) parser.print_help(self.common_usage + "\nGlobal options:") - print('') + print() if display_options: parser.set_option_table(self.display_options) parser.print_help( "Information display options (just display " + "information, ignore any commands)") - print('') + print() for command in self.commands: if isinstance(command, type) and issubclass(command, Command): @@ -529,7 +529,7 @@ Common commands: (see '--help-commands' for more) else: parser.set_option_table(cls.user_options) parser.print_help("Options for %r command:" % cls.__name__) - print('') + print() print(gen_usage(self.script_name)) @@ -544,7 +544,7 @@ Common commands: (see '--help-commands' for more) # we ignore "foo bar"). if self.help_commands: self.print_commands() - print('') + print() print(gen_usage(self.script_name)) return 1 diff --git a/Lib/packaging/install.py b/Lib/packaging/install.py index 4b82088..c5bda45 100644 --- a/Lib/packaging/install.py +++ b/Lib/packaging/install.py @@ -13,7 +13,7 @@ import errno import shutil import logging import tempfile -from sysconfig import get_config_var, get_path +from sysconfig import get_config_var, get_path, is_python_build from packaging import logger from packaging.dist import Distribution @@ -488,20 +488,31 @@ def install(project): Returns True on success, False on failure """ + if is_python_build(): + # Python would try to install into the site-packages directory under + # $PREFIX, but when running from an uninstalled code checkout we don't + # want to create directories under the installation root + message = ('installing third-party projects from an uninstalled ' + 'Python is not supported') + logger.error(message) + return False + logger.info('Checking the installation location...') purelib_path = get_path('purelib') + # trying to write a file there try: with tempfile.NamedTemporaryFile(suffix=project, dir=purelib_path) as testfile: testfile.write(b'test') except OSError: - # was unable to write a file + # FIXME this should check the errno, or be removed altogether (race + # condition: the directory permissions could be changed between here + # and the actual install) logger.info('Unable to write in "%s". Do you have the permissions ?' % purelib_path) return False - logger.info('Getting information about %r...', project) try: info = get_infos(project) @@ -520,7 +531,7 @@ def install(project): except InstallationConflict as e: if logger.isEnabledFor(logging.INFO): - projects = ['%s %s' % (p.name, p.version) for p in e.args[0]] + projects = ['%r %s' % (p.name, p.version) for p in e.args[0]] logger.info('%r conflicts with %s', project, ','.join(projects)) return True diff --git a/Lib/packaging/pypi/dist.py b/Lib/packaging/pypi/dist.py index db04cda..d3824c2 100644 --- a/Lib/packaging/pypi/dist.py +++ b/Lib/packaging/pypi/dist.py @@ -256,7 +256,7 @@ class DistInfo(IndexReference): hashlib.new(hashname) except ValueError: raise UnsupportedHashName(hashname) - if not url in [u['url'] for u in self.urls]: + if url not in [u['url'] for u in self.urls]: self.urls.append({ 'url': url, 'hashname': hashname, @@ -329,7 +329,7 @@ class DistInfo(IndexReference): url param""" hashname = self.url['hashname'] expected_hashval = self.url['hashval'] - if not None in (expected_hashval, hashname): + if None not in (expected_hashval, hashname): with open(filename, 'rb') as f: hashval = hashlib.new(hashname) hashval.update(f.read()) @@ -409,7 +409,7 @@ class ReleasesList(IndexReference): (release.name, self.name)) version = str(release.version) - if not version in self.get_versions(): + if version not in self.get_versions(): # append only if not already exists self.releases.append(release) for dist in release.dists.values(): diff --git a/Lib/packaging/pypi/simple.py b/Lib/packaging/pypi/simple.py index c372c6f..1dcb8ce 100644 --- a/Lib/packaging/pypi/simple.py +++ b/Lib/packaging/pypi/simple.py @@ -231,7 +231,8 @@ class Crawler(BaseClient): """ self._mirrors_used.add(self.index_url) index_url = self._mirrors.pop() - if not ("http://" or "https://" or "file://") in index_url: + # XXX use urllib.parse for a real check of missing scheme part + if not index_url.startswith(("http://", "https://", "file://")): index_url = "http://%s" % index_url if not index_url.endswith("/simple"): @@ -282,7 +283,7 @@ class Crawler(BaseClient): name = release.name else: name = release_info['name'] - if not name.lower() in self._projects: + if name.lower() not in self._projects: self._projects[name.lower()] = ReleasesList(name, index=self._index) if release: @@ -320,7 +321,7 @@ class Crawler(BaseClient): # it's a distribution, so create a dist object try: infos = get_infos_from_url(link, project_name, - is_external=not self.index_url in url) + is_external=self.index_url not in url) except CantParseArchiveName as e: if self.verbose: logger.warning( diff --git a/Lib/packaging/run.py b/Lib/packaging/run.py index c17ccfd..3e720cf 100644 --- a/Lib/packaging/run.py +++ b/Lib/packaging/run.py @@ -286,9 +286,9 @@ def _metadata(dispatcher, args, **kw): value = metadata[key] if isinstance(value, list): for v in value: - print(' ' + v) + print(' ', v) else: - print(' ' + value.replace('\n', '\n ')) + print(' ', value.replace('\n', '\n ')) @action_help(remove_usage) @@ -366,7 +366,7 @@ def _list(dispatcher, args, **kw): print('%s %s at %s' % (dist.name, dist.metadata['version'], dist.path)) number += 1 - print('') + print() if number == 0: print('Nothing seems to be installed.') else: @@ -405,7 +405,6 @@ class Dispatcher: self.verbose = 1 self.dry_run = False self.help = False - self.script_name = 'pysetup' self.cmdclass = {} self.commands = [] self.command_options = {} @@ -574,17 +573,17 @@ class Dispatcher: from packaging.command.cmd import Command print('Usage: pysetup [options] action [action_options]') - print('') + print() if global_options_: self.print_usage(self.parser) - print('') + print() if display_options_: parser.set_option_table(display_options) parser.print_help( "Information display options (just display " + "information, ignore any commands)") - print('') + print() for command in commands: if isinstance(command, type) and issubclass(command, Command): @@ -598,15 +597,15 @@ class Dispatcher: parser.set_option_table(cls.user_options) parser.print_help("Options for %r command:" % cls.__name__) - print('') + print() def _show_command_help(self, command): if isinstance(command, str): command = get_command_class(command) desc = getattr(command, 'description', '(no description available)') - print('Description: %s' % desc) - print('') + print('Description:', desc) + print() if (hasattr(command, 'help_options') and isinstance(command.help_options, list)): @@ -616,7 +615,7 @@ class Dispatcher: self.parser.set_option_table(command.user_options) self.parser.print_help("Options:") - print('') + print() def _get_command_groups(self): """Helper function to retrieve all the command class names divided diff --git a/Lib/packaging/tests/test_command_bdist_dumb.py b/Lib/packaging/tests/test_command_bdist_dumb.py index 41b0dd0..b235795 100644 --- a/Lib/packaging/tests/test_command_bdist_dumb.py +++ b/Lib/packaging/tests/test_command_bdist_dumb.py @@ -49,7 +49,6 @@ class BuildDumbTestCase(support.TempdirManager, 'py_modules': ['foo'], 'url': 'xxx', 'author': 'xxx', 'author_email': 'xxx'}) - dist.script_name = 'setup.py' os.chdir(pkg_dir) sys.argv[:] = ['setup.py'] diff --git a/Lib/packaging/tests/test_command_build_py.py b/Lib/packaging/tests/test_command_build_py.py index 49069f5..243a863 100644 --- a/Lib/packaging/tests/test_command_build_py.py +++ b/Lib/packaging/tests/test_command_build_py.py @@ -33,9 +33,7 @@ class BuildPyTestCase(support.TempdirManager, dist = Distribution({"packages": ["pkg"], "package_dir": sources}) - # script_name need not exist, it just need to be initialized - dist.script_name = os.path.join(sources, "setup.py") dist.command_obj["build"] = support.DummyCommand( force=False, build_lib=destination, @@ -89,8 +87,6 @@ class BuildPyTestCase(support.TempdirManager, dist = Distribution({"packages": ["pkg"], "package_dir": sources, "package_data": {"pkg": ["doc/*"]}}) - # script_name need not exist, it just need to be initialized - dist.script_name = os.path.join(sources, "setup.py") dist.script_args = ["build"] dist.parse_command_line() diff --git a/Lib/packaging/tests/test_command_install_dist.py b/Lib/packaging/tests/test_command_install_dist.py index 1974a2f..7821a3a 100644 --- a/Lib/packaging/tests/test_command_install_dist.py +++ b/Lib/packaging/tests/test_command_install_dist.py @@ -30,8 +30,6 @@ class InstallTestCase(support.TempdirManager, destination = os.path.join(builddir, "installation") dist = Distribution({"name": "foopkg"}) - # script_name need not exist, it just need to be initialized - dist.script_name = os.path.join(builddir, "setup.py") dist.command_obj["build"] = support.DummyCommand( build_base=builddir, build_lib=os.path.join(builddir, "lib"), diff --git a/Lib/packaging/tests/test_command_install_distinfo.py b/Lib/packaging/tests/test_command_install_distinfo.py index 6d40f66..ade191c 100644 --- a/Lib/packaging/tests/test_command_install_distinfo.py +++ b/Lib/packaging/tests/test_command_install_distinfo.py @@ -162,7 +162,7 @@ class InstallDistinfoTestCase(support.TempdirManager, expected = [] for f in install.get_outputs(): - if (f.endswith('.pyc') or f == os.path.join( + if (f.endswith(('.pyc', '.pyo')) or f == os.path.join( install_dir, 'foo-1.0.dist-info', 'RECORD')): expected.append([f, '', '']) else: diff --git a/Lib/packaging/tests/test_command_install_lib.py b/Lib/packaging/tests/test_command_install_lib.py index 96749e3..b46f3bd 100644 --- a/Lib/packaging/tests/test_command_install_lib.py +++ b/Lib/packaging/tests/test_command_install_lib.py @@ -65,7 +65,6 @@ class InstallLibTestCase(support.TempdirManager, self.write_file(f, '# python package') cmd.distribution.ext_modules = [Extension('foo', ['xxx'])] cmd.distribution.packages = [pkg_dir] - cmd.distribution.script_name = 'setup.py' # make sure the build_lib is set the temp dir build_dir = os.path.split(pkg_dir)[0] @@ -86,7 +85,6 @@ class InstallLibTestCase(support.TempdirManager, self.write_file(f, '# python package') cmd.distribution.ext_modules = [Extension('foo', ['xxx'])] cmd.distribution.packages = [pkg_dir] - cmd.distribution.script_name = 'setup.py' # get_input should return 2 elements self.assertEqual(len(cmd.get_inputs()), 2) diff --git a/Lib/packaging/tests/test_command_sdist.py b/Lib/packaging/tests/test_command_sdist.py index 41b2a24..bcaa630 100644 --- a/Lib/packaging/tests/test_command_sdist.py +++ b/Lib/packaging/tests/test_command_sdist.py @@ -24,16 +24,11 @@ from packaging.util import find_executable from packaging.tests import support from shutil import get_archive_formats -SETUP_PY = """ -from packaging.core import setup -import somecode - -setup(name='fake') -""" MANIFEST = """\ # file GENERATED by packaging, do NOT edit inroot.txt +setup.cfg data%(sep)sdata.dt scripts%(sep)sscript.py some%(sep)sfile.txt @@ -56,8 +51,6 @@ class SDistTestCase(support.TempdirManager, restore_environ = ['HOME'] def setUp(self): - # PyPIRCCommandTestCase creates a temp dir already - # and put it in self.tmp_dir super(SDistTestCase, self).setUp() self.tmp_dir = self.mkdtemp() os.environ['HOME'] = self.tmp_dir @@ -68,7 +61,6 @@ class SDistTestCase(support.TempdirManager, # a package, and a README self.write_file((self.tmp_dir, 'README'), 'xxx') self.write_file((self.tmp_dir, 'somecode', '__init__.py'), '#') - self.write_file((self.tmp_dir, 'setup.py'), SETUP_PY) os.chdir(self.tmp_dir) def tearDown(self): @@ -83,7 +75,6 @@ class SDistTestCase(support.TempdirManager, 'url': 'xxx', 'author': 'xxx', 'author_email': 'xxx'} dist = Distribution(metadata) - dist.script_name = 'setup.py' dist.packages = ['somecode'] dist.include_package_data = True cmd = sdist(dist) @@ -173,6 +164,7 @@ class SDistTestCase(support.TempdirManager, # in package_data dist.package_data = {'': ['*.cfg', '*.dat'], 'somecode': ['*.txt']} + self.write_file((self.tmp_dir, 'setup.cfg'), '#') self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#') @@ -211,9 +203,9 @@ class SDistTestCase(support.TempdirManager, with zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) as zip_file: content = zip_file.namelist() - # Making sure everything was added. This includes 9 code and data - # files in addition to PKG-INFO. - self.assertEqual(len(content), 9) + # Making sure everything was added. This includes 8 code and data + # files in addition to PKG-INFO and setup.cfg + self.assertEqual(len(content), 10) # Checking the MANIFEST with open(join(self.tmp_dir, 'MANIFEST')) as fp: @@ -230,7 +222,7 @@ class SDistTestCase(support.TempdirManager, cmd.ensure_finalized() cmd.run() warnings = self.get_logs(logging.WARN) - self.assertEqual(len(warnings), 3) + self.assertEqual(len(warnings), 4) # trying with a complete set of metadata self.loghandler.flush() @@ -242,8 +234,9 @@ class SDistTestCase(support.TempdirManager, # removing manifest generated warnings warnings = [warn for warn in warnings if not warn.endswith('-- skipping')] - # the remaining warning is about the use of the default file list - self.assertEqual(len(warnings), 1) + # the remaining warnings are about the use of the default file list and + # the absence of setup.cfg + self.assertEqual(len(warnings), 2) def test_show_formats(self): __, stdout = captured_stdout(show_formats) diff --git a/Lib/packaging/tests/test_command_upload.py b/Lib/packaging/tests/test_command_upload.py index d7609a2..dbb4db7 100644 --- a/Lib/packaging/tests/test_command_upload.py +++ b/Lib/packaging/tests/test_command_upload.py @@ -140,8 +140,8 @@ class UploadTestCase(support.TempdirManager, support.EnvironRestorer, cmd.upload_docs = True cmd.ensure_finalized() cmd.repository = self.pypi.full_address + prev_dir = os.getcwd() try: - prev_dir = os.getcwd() os.chdir(self.tmp_dir) cmd.run() finally: diff --git a/Lib/packaging/tests/test_config.py b/Lib/packaging/tests/test_config.py index a276730..6be63eb 100644 --- a/Lib/packaging/tests/test_config.py +++ b/Lib/packaging/tests/test_config.py @@ -90,7 +90,7 @@ commands = compilers = packaging.tests.test_config.DCompiler -setup_hook = %(setup-hook)s +setup_hooks = %(setup-hooks)s @@ -114,7 +114,7 @@ libraries = gecodeint gecodekernel -- sys.platform != 'win32' GecodeInt GecodeKernel -- sys.platform == 'win32' [extension=fast_taunt] -name = three.fast_taunt +name = two.fast_taunt sources = cxx_src/utils_taunt.cxx cxx_src/python_module.cxx include_dirs = /usr/include/gecode @@ -135,8 +135,16 @@ class DCompiler: pass -def hook(content): - content['metadata']['version'] += '.dev1' +def version_hook(config): + config['metadata']['version'] += '.dev1' + + +def first_hook(config): + config['files']['modules'] += '\n first' + + +def third_hook(config): + config['files']['modules'] += '\n third' class FooBarBazTest: @@ -186,7 +194,7 @@ class ConfigTestCase(support.TempdirManager, def write_setup(self, kwargs=None): opts = {'description-file': 'README', 'extra-files': '', - 'setup-hook': 'packaging.tests.test_config.hook'} + 'setup-hooks': 'packaging.tests.test_config.version_hook'} if kwargs: opts.update(kwargs) self.write_file('setup.cfg', SETUP_CFG % opts, encoding='utf-8') @@ -305,7 +313,7 @@ class ConfigTestCase(support.TempdirManager, self.assertEqual(ext.extra_link_args, ['`gcc -print-file-name=libgcc.a`', '-shared']) - ext = ext_modules.get('three.fast_taunt') + ext = ext_modules.get('two.fast_taunt') self.assertEqual(ext.sources, ['cxx_src/utils_taunt.cxx', 'cxx_src/python_module.cxx']) self.assertEqual(ext.include_dirs, @@ -318,16 +326,30 @@ class ConfigTestCase(support.TempdirManager, self.assertEqual(ext.extra_compile_args, cargs) self.assertEqual(ext.language, 'cxx') - def test_missing_setuphook_warns(self): - self.write_setup({'setup-hook': 'this.does._not.exist'}) + def test_missing_setup_hook_warns(self): + self.write_setup({'setup-hooks': 'this.does._not.exist'}) self.write_file('README', 'yeah') dist = self.get_dist() logs = self.get_logs(logging.WARNING) self.assertEqual(1, len(logs)) - self.assertIn('could not import setup_hook', logs[0]) + self.assertIn('cannot find setup hook', logs[0]) + + def test_multiple_setup_hooks(self): + self.write_setup({ + 'setup-hooks': '\n packaging.tests.test_config.first_hook' + '\n packaging.tests.test_config.missing_hook' + '\n packaging.tests.test_config.third_hook' + }) + self.write_file('README', 'yeah') + dist = self.get_dist() + + self.assertEqual(['haven', 'first', 'third'], dist.py_modules) + logs = self.get_logs(logging.WARNING) + self.assertEqual(1, len(logs)) + self.assertIn('cannot find setup hook', logs[0]) def test_metadata_requires_description_files_missing(self): - self.write_setup({'description-file': 'README\n README2'}) + self.write_setup({'description-file': 'README README2'}) self.write_file('README', 'yeah') self.write_file('README2', 'yeah') os.mkdir('src') diff --git a/Lib/packaging/tests/test_create.py b/Lib/packaging/tests/test_create.py index 906ca8f..a82ab43 100644 --- a/Lib/packaging/tests/test_create.py +++ b/Lib/packaging/tests/test_create.py @@ -13,6 +13,7 @@ class CreateTestCase(support.TempdirManager, support.EnvironRestorer, unittest.TestCase): + maxDiff = None restore_environ = ['PLAT'] def setUp(self): @@ -65,10 +66,15 @@ class CreateTestCase(support.TempdirManager, # building the structure tempdir = self.wdir dirs = ['pkg1', 'data', 'pkg2', 'pkg2/sub'] - files = ['README', 'setup.cfg', 'foo.py', - 'pkg1/__init__.py', 'pkg1/bar.py', - 'data/data1', 'pkg2/__init__.py', - 'pkg2/sub/__init__.py'] + files = [ + 'README', + 'data/data1', + 'foo.py', + 'pkg1/__init__.py', + 'pkg1/bar.py', + 'pkg2/__init__.py', + 'pkg2/sub/__init__.py', + ] for dir_ in dirs: os.mkdir(os.path.join(tempdir, dir_)) @@ -85,8 +91,8 @@ class CreateTestCase(support.TempdirManager, ['pkg1', 'pkg2', 'pkg2.sub']) self.assertEqual(mainprogram.data['modules'], ['foo']) data_fn = os.path.join('data', 'data1') - self.assertEqual(set(mainprogram.data['extra_files']), - set(['setup.cfg', 'README', data_fn])) + self.assertEqual(mainprogram.data['extra_files'], + ['README', data_fn]) def test_convert_setup_py_to_cfg(self): self.write_file((self.wdir, 'setup.py'), @@ -130,43 +136,45 @@ class CreateTestCase(support.TempdirManager, main() with open(os.path.join(self.wdir, 'setup.cfg'), encoding='utf-8') as fp: - lines = set(line.rstrip() for line in fp) - - # FIXME don't use sets - self.assertEqual(lines, set(['', - '[metadata]', - 'version = 0.2', - 'name = pyxfoil', - 'maintainer = André Espaze', - 'description = My super Death-scription', - ' |barbar is now on the public domain,', - ' |ho, baby !', - 'maintainer_email = andre.espaze@logilab.fr', - 'home_page = http://www.python-science.org/project/pyxfoil', - 'download_url = UNKNOWN', - 'summary = Python bindings for the Xfoil engine', - '[files]', - 'modules = my_lib', - ' mymodule', - 'packages = pyxfoil', - ' babar', - ' me', - 'extra_files = Martinique/Lamentin/dady', - ' Martinique/Lamentin/mumy', - ' Martinique/Lamentin/sys', - ' Martinique/Lamentin/bro', - ' Pom', - ' Flora', - ' Alexander', - ' setup.py', - ' README', - ' pyxfoil/fengine.so', - 'scripts = my_script', - ' bin/run', - 'resources =', - ' README.rst = {doc}', - ' pyxfoil.1 = {man}', - ])) + contents = fp.read() + + self.assertEqual(contents, dedent("""\ + [metadata] + name = pyxfoil + version = 0.2 + summary = Python bindings for the Xfoil engine + download_url = UNKNOWN + home_page = http://www.python-science.org/project/pyxfoil + maintainer = André Espaze + maintainer_email = andre.espaze@logilab.fr + description = My super Death-scription + |barbar is now on the public domain, + |ho, baby ! + + [files] + packages = pyxfoil + babar + me + modules = my_lib + mymodule + scripts = my_script + bin/run + extra_files = Martinique/Lamentin/dady + Martinique/Lamentin/mumy + Martinique/Lamentin/sys + Martinique/Lamentin/bro + setup.py + README + Pom + Flora + Alexander + pyxfoil/fengine.so + + resources = + README.rst = {doc} + pyxfoil.1 = {man} + + """)) def test_convert_setup_py_to_cfg_with_description_in_readme(self): self.write_file((self.wdir, 'setup.py'), @@ -203,26 +211,29 @@ ho, baby! # FIXME Out of memory error. main() with open(os.path.join(self.wdir, 'setup.cfg'), encoding='utf-8') as fp: - lines = set(line.rstrip() for line in fp) - - self.assertEqual(lines, set(['', - '[metadata]', - 'version = 0.2', - 'name = pyxfoil', - 'maintainer = André Espaze', - 'maintainer_email = andre.espaze@logilab.fr', - 'home_page = http://www.python-science.org/project/pyxfoil', - 'download_url = UNKNOWN', - 'summary = Python bindings for the Xfoil engine', - 'description-file = README.txt', - '[files]', - 'packages = pyxfoil', - 'extra_files = pyxfoil/fengine.so', - ' pyxfoil/babar.so', - 'resources =', - ' README.rst = {doc}', - ' pyxfoil.1 = {man}', - ])) + contents = fp.read() + + self.assertEqual(contents, dedent("""\ + [metadata] + name = pyxfoil + version = 0.2 + summary = Python bindings for the Xfoil engine + download_url = UNKNOWN + home_page = http://www.python-science.org/project/pyxfoil + maintainer = André Espaze + maintainer_email = andre.espaze@logilab.fr + description-file = README.txt + + [files] + packages = pyxfoil + extra_files = pyxfoil/fengine.so + pyxfoil/babar.so + + resources = + README.rst = {doc} + pyxfoil.1 = {man} + + """)) def test_suite(): diff --git a/Lib/packaging/tests/test_dist.py b/Lib/packaging/tests/test_dist.py index fb6d524..e1c5ff0 100644 --- a/Lib/packaging/tests/test_dist.py +++ b/Lib/packaging/tests/test_dist.py @@ -35,7 +35,7 @@ class DistributionTestCase(support.TempdirManager, support.EnvironRestorer, unittest.TestCase): - restore_environ = ['HOME'] + restore_environ = ['HOME', 'PLAT'] def setUp(self): super(DistributionTestCase, self).setUp() diff --git a/Lib/packaging/tests/test_install.py b/Lib/packaging/tests/test_install.py index c50a45e..35733c8 100644 --- a/Lib/packaging/tests/test_install.py +++ b/Lib/packaging/tests/test_install.py @@ -1,5 +1,7 @@ """Tests for the packaging.install module.""" import os +import logging +from sysconfig import is_python_build from tempfile import mkstemp from packaging import install @@ -357,9 +359,17 @@ class TestInstall(LoggingCatcher, TempdirManager, unittest.TestCase): install._install_dist = old_install_dist def test_install_permission_denied(self): - # if we don't have the access to the installation - # path, we should abort immediatly + # if we don't have access to the installation path, we should abort + # immediately project = os.path.join(os.path.dirname(__file__), 'package.tgz') + + # when running from an uninstalled build, a warning is emitted and the + # installation is not attempted + if is_python_build(): + self.assertFalse(install.install(project)) + self.assertEqual(1, len(self.get_logs(logging.ERROR))) + return + install_path = self.mkdtemp() old_get_path = install.get_path install.get_path = lambda path: install_path diff --git a/Lib/packaging/tests/test_util.py b/Lib/packaging/tests/test_util.py index 5a94a73..9b6498b 100644 --- a/Lib/packaging/tests/test_util.py +++ b/Lib/packaging/tests/test_util.py @@ -8,16 +8,18 @@ import subprocess from io import StringIO from packaging.tests import support, unittest +from packaging.tests.test_config import SETUP_CFG from packaging.errors import ( PackagingPlatformError, PackagingByteCompileError, PackagingFileError, PackagingExecError, InstallationException) from packaging import util +from packaging.dist import Distribution from packaging.util import ( convert_path, change_root, split_quoted, strtobool, rfc822_escape, get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages, spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob, RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging, - get_install_method) + get_install_method, cfg_to_args) PYPIRC = """\ @@ -88,13 +90,15 @@ class UtilTestCase(support.EnvironRestorer, support.LoggingCatcher, unittest.TestCase): - restore_environ = ['HOME'] + restore_environ = ['HOME', 'PLAT'] def setUp(self): super(UtilTestCase, self).setUp() - self.tmp_dir = self.mkdtemp() - self.rc = os.path.join(self.tmp_dir, '.pypirc') - os.environ['HOME'] = self.tmp_dir + self.addCleanup(os.chdir, os.getcwd()) + tempdir = self.mkdtemp() + self.rc = os.path.join(tempdir, '.pypirc') + os.environ['HOME'] = tempdir + os.chdir(tempdir) # saving the environment self.name = os.name self.platform = sys.platform @@ -103,7 +107,6 @@ class UtilTestCase(support.EnvironRestorer, self.join = os.path.join self.isabs = os.path.isabs self.splitdrive = os.path.splitdrive - #self._config_vars = copy(sysconfig._config_vars) # patching os.uname if hasattr(os, 'uname'): @@ -137,7 +140,6 @@ class UtilTestCase(support.EnvironRestorer, os.uname = self.uname else: del os.uname - #sysconfig._config_vars = copy(self._config_vars) util.find_executable = self.old_find_executable subprocess.Popen = self.old_popen sys.old_stdout = self.old_stdout @@ -491,6 +493,38 @@ class UtilTestCase(support.EnvironRestorer, content = f.read() self.assertEqual(content, WANTED) + def test_cfg_to_args(self): + opts = {'description-file': 'README', 'extra-files': '', + 'setup-hooks': 'packaging.tests.test_config.version_hook'} + self.write_file('setup.cfg', SETUP_CFG % opts, encoding='utf-8') + self.write_file('README', 'loooong description') + + args = cfg_to_args() + # use Distribution to get the contents of the setup.cfg file + dist = Distribution() + dist.parse_config_files() + metadata = dist.metadata + + self.assertEqual(args['name'], metadata['Name']) + # + .dev1 because the test SETUP_CFG also tests a hook function in + # test_config.py for appending to the version string + self.assertEqual(args['version'] + '.dev1', metadata['Version']) + self.assertEqual(args['author'], metadata['Author']) + self.assertEqual(args['author_email'], metadata['Author-Email']) + self.assertEqual(args['maintainer'], metadata['Maintainer']) + self.assertEqual(args['maintainer_email'], + metadata['Maintainer-Email']) + self.assertEqual(args['description'], metadata['Summary']) + self.assertEqual(args['long_description'], metadata['Description']) + self.assertEqual(args['classifiers'], metadata['Classifier']) + self.assertEqual(args['requires'], metadata['Requires-Dist']) + self.assertEqual(args['provides'], metadata['Provides-Dist']) + + self.assertEqual(args['package_dir'].get(''), dist.package_dir) + self.assertEqual(args['packages'], dist.packages) + self.assertEqual(args['scripts'], dist.scripts) + self.assertEqual(args['py_modules'], dist.py_modules) + class GlobTestCaseBase(support.TempdirManager, support.LoggingCatcher, diff --git a/Lib/packaging/util.py b/Lib/packaging/util.py index d4aae41..4dff547 100644 --- a/Lib/packaging/util.py +++ b/Lib/packaging/util.py @@ -250,6 +250,14 @@ def split_quoted(s): return words +def split_multiline(value): + """Split a multiline string into a list, excluding blank lines.""" + + return [element for element in + (line.strip() for line in value.split('\n')) + if element] + + def execute(func, args, msg=None, verbose=0, dry_run=False): """Perform some action that affects the outside world. @@ -542,18 +550,15 @@ def write_file(filename, contents): def _is_package(path): - if not os.path.isdir(path): - return False - return os.path.isfile(os.path.join(path, '__init__.py')) + return os.path.isdir(path) and os.path.isfile( + os.path.join(path, '__init__.py')) # Code taken from the pip project def _is_archive_file(name): archives = ('.zip', '.tar.gz', '.tar.bz2', '.tgz', '.tar') ext = splitext(name)[1].lower() - if ext in archives: - return True - return False + return ext in archives def _under(path, root): @@ -772,12 +777,13 @@ def spawn(cmd, search_path=True, verbose=0, dry_run=False, env=None): Raise PackagingExecError if running the program fails in any way; just return on success. """ - logger.info(' '.join(cmd)) + logger.debug('spawn: running %r', cmd) if dry_run: + logging.debug('dry run, no process actually spawned') return exit_status = subprocess.call(cmd, env=env) if exit_status != 0: - msg = "command '%s' failed with exit status %d" + msg = "command %r failed with exit status %d" raise PackagingExecError(msg % (cmd, exit_status)) @@ -1010,16 +1016,20 @@ def cfg_to_args(path='setup.cfg'): "requires": ("metadata", "requires_dist"), "provides": ("metadata", "provides_dist"), # ** "obsoletes": ("metadata", "obsoletes_dist"), # ** + "package_dir": ("files", 'packages_root'), "packages": ("files",), "scripts": ("files",), "py_modules": ("files", "modules"), # ** } MULTI_FIELDS = ("classifiers", - "requires", "platforms", + "requires", + "provides", + "obsoletes", "packages", - "scripts") + "scripts", + "py_modules") def has_get_option(config, section, option): if config.has_option(section, option): @@ -1031,10 +1041,10 @@ def cfg_to_args(path='setup.cfg'): # The real code starts here config = RawConfigParser() - if not os.path.exists(file): + if not os.path.exists(path): raise PackagingFileError("file '%s' does not exist" % - os.path.abspath(file)) - config.read(path) + os.path.abspath(path)) + config.read(path, encoding='utf-8') kwargs = {} for arg in D1_D2_SETUP_ARGS: @@ -1050,17 +1060,24 @@ def cfg_to_args(path='setup.cfg'): in_cfg_value = has_get_option(config, section, option) if not in_cfg_value: # There is no such option in the setup.cfg - if arg == "long_description": - filename = has_get_option(config, section, "description_file") - if filename: - with open(filename) as fp: - in_cfg_value = fp.read() + if arg == 'long_description': + filenames = has_get_option(config, section, 'description-file') + if filenames: + filenames = split_multiline(filenames) + in_cfg_value = [] + for filename in filenames: + with open(filename) as fp: + in_cfg_value.append(fp.read()) + in_cfg_value = '\n\n'.join(in_cfg_value) else: continue + if arg == 'package_dir' and in_cfg_value: + in_cfg_value = {'': in_cfg_value} + if arg in MULTI_FIELDS: # support multiline options - in_cfg_value = in_cfg_value.strip().split('\n') + in_cfg_value = split_multiline(in_cfg_value) kwargs[arg] = in_cfg_value @@ -1099,7 +1116,7 @@ def ask(message, options): response = input(message) response = response.strip().lower() if response not in options: - print('invalid response: %r' % response) + print('invalid response:', repr(response)) print('choose one of', ', '.join(repr(o) for o in options)) else: return response diff --git a/Lib/smtplib.py b/Lib/smtplib.py index f724b9f..f9d1c99 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -162,7 +162,7 @@ def quotedata(data): re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data)) def _quote_periods(bindata): - return re.sub(br'(?m)^\.', '..', bindata) + return re.sub(br'(?m)^\.', b'..', bindata) def _fix_eols(data): return re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data) @@ -172,27 +172,6 @@ try: except ImportError: _have_ssl = False else: - class SSLFakeFile: - """A fake file like object that really wraps a SSLObject. - - It only supports what is needed in smtplib. - """ - def __init__(self, sslobj): - self.sslobj = sslobj - - def readline(self): - str = b"" - chr = None - while chr != b"\n": - chr = self.sslobj.read(1) - if not chr: - break - str += chr - return str - - def close(self): - pass - _have_ssl = True @@ -322,6 +301,7 @@ class SMTP: if self.debuglevel > 0: print('connect:', (host, port), file=stderr) self.sock = self._get_socket(host, port, self.timeout) + self.file = None (code, msg) = self.getreply() if self.debuglevel > 0: print("connect:", msg, file=stderr) @@ -669,7 +649,7 @@ class SMTP: self.sock = context.wrap_socket(self.sock) else: self.sock = ssl.wrap_socket(self.sock, keyfile, certfile) - self.file = SSLFakeFile(self.sock) + self.file = None # RFC 3207: # The client MUST discard any knowledge obtained from # the server, such as the list of SMTP service extensions, @@ -853,7 +833,6 @@ if _have_ssl: new_socket = self.context.wrap_socket(new_socket) else: new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile) - self.file = SSLFakeFile(new_socket) return new_socket __all__.append("SMTP_SSL") @@ -890,6 +869,7 @@ class LMTP(SMTP): # Handle Unix-domain sockets. try: self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.file = None self.sock.connect(host) except socket.error as msg: if self.debuglevel > 0: diff --git a/Lib/sysconfig.cfg b/Lib/sysconfig.cfg index 1f6b8bc..573b12e 100644 --- a/Lib/sysconfig.cfg +++ b/Lib/sysconfig.cfg @@ -1,24 +1,24 @@ [globals] -# These are the useful categories that are sometimes referenced at runtime, -# using packaging.resources.get_file: +# These are useful categories that can be referenced at run time, +# using packaging.database.get_file. # Configuration files config = {confdir}/{distribution.name} # Non-writable data that is independent of architecture (images, many xml/text files) appdata = {datadir}/{distribution.name} # Non-writable data that is architecture-dependent (some binary data formats) appdata.arch = {libdir}/{distribution.name} -# Data, written by the package, that must be preserved (databases) +# Data, written by the app/lib, that must be preserved (databases) appdata.persistent = {statedir}/lib/{distribution.name} -# Data, written by the package, that can be safely discarded (cache) +# Data, written by the app/lib, that can be safely discarded (cache) appdata.disposable = {statedir}/cache/{distribution.name} -# Help or documentation files referenced at runtime +# Help or documentation files help = {datadir}/{distribution.name} icon = {datadir}/pixmaps scripts = {base}/bin # Non-runtime files. These are valid categories for marking files for -# install, but they should not be referenced by the app at runtime: -# Help or documentation files not referenced by the package at runtime +# install, but they should not be referenced by the app/lib at run time. +# Help or documentation files doc = {datadir}/doc/{distribution.name} # GNU info documentation files info = {datadir}/info diff --git a/Lib/test/support.py b/Lib/test/support.py index 739cb7b..a51d943 100644 --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1561,9 +1561,10 @@ def can_symlink(): try: os.symlink(TESTFN, symlink_path) can = True - os.remove(symlink_path) except (OSError, NotImplementedError, AttributeError): can = False + else: + os.remove(symlink_path) _can_symlink = can return can diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 2836e7e..b0e9a03 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -4480,6 +4480,67 @@ class TestArgumentTypeError(TestCase): else: self.fail() +# ========================= +# MessageContentError tests +# ========================= + +class TestMessageContentError(TestCase): + + def test_missing_argument_name_in_message(self): + parser = ErrorRaisingArgumentParser(prog='PROG', usage='') + parser.add_argument('req_pos', type=str) + parser.add_argument('-req_opt', type=int, required=True) + parser.add_argument('need_one', type=str, nargs='+') + + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args([]) + msg = str(cm.exception) + self.assertRegex(msg, 'req_pos') + self.assertRegex(msg, 'req_opt') + self.assertRegex(msg, 'need_one') + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args(['myXargument']) + msg = str(cm.exception) + self.assertNotIn(msg, 'req_pos') + self.assertRegex(msg, 'req_opt') + self.assertRegex(msg, 'need_one') + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args(['myXargument', '-req_opt=1']) + msg = str(cm.exception) + self.assertNotIn(msg, 'req_pos') + self.assertNotIn(msg, 'req_opt') + self.assertRegex(msg, 'need_one') + + def test_optional_optional_not_in_message(self): + parser = ErrorRaisingArgumentParser(prog='PROG', usage='') + parser.add_argument('req_pos', type=str) + parser.add_argument('--req_opt', type=int, required=True) + parser.add_argument('--opt_opt', type=bool, nargs='?', + default=True) + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args([]) + msg = str(cm.exception) + self.assertRegex(msg, 'req_pos') + self.assertRegex(msg, 'req_opt') + self.assertNotIn(msg, 'opt_opt') + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args(['--req_opt=1']) + msg = str(cm.exception) + self.assertRegex(msg, 'req_pos') + self.assertNotIn(msg, 'req_opt') + self.assertNotIn(msg, 'opt_opt') + + def test_optional_positional_not_in_message(self): + parser = ErrorRaisingArgumentParser(prog='PROG', usage='') + parser.add_argument('req_pos') + parser.add_argument('optional_positional', nargs='?', default='eggs') + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args([]) + msg = str(cm.exception) + self.assertRegex(msg, 'req_pos') + self.assertNotIn(msg, 'optional_positional') + + # ====================== # parse_known_args tests # ====================== diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 97619cf..ce1586f 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -372,7 +372,15 @@ class BuiltinTest(unittest.TestCase): f = Foo() self.assertTrue(dir(f) == ["ga", "kan", "roo"]) - # dir(obj__dir__not_list) + # dir(obj__dir__tuple) + class Foo(object): + def __dir__(self): + return ("b", "c", "a") + res = dir(Foo()) + self.assertIsInstance(res, list) + self.assertTrue(res == ["a", "b", "c"]) + + # dir(obj__dir__not_sequence) class Foo(object): def __dir__(self): return 7 diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index 7457f39..5968980 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -19,7 +19,7 @@ import unittest from concurrent import futures from concurrent.futures._base import ( PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future) -import concurrent.futures.process +from concurrent.futures.process import BrokenProcessPool def create_future(state=PENDING, exception=None, result=None): @@ -154,7 +154,7 @@ class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): processes = self.executor._processes self.executor.shutdown() - for p in processes: + for p in processes.values(): p.join() def test_context_manager_shutdown(self): @@ -163,7 +163,7 @@ class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): self.assertEqual(list(e.map(abs, range(-5, 5))), [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) - for p in processes: + for p in processes.values(): p.join() def test_del_shutdown(self): @@ -174,7 +174,7 @@ class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): del executor queue_management_thread.join() - for p in processes: + for p in processes.values(): p.join() class WaitTests(unittest.TestCase): @@ -381,7 +381,17 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest): - pass + def test_killed_child(self): + # When a child process is abruptly terminated, the whole pool gets + # "broken". + futures = [self.executor.submit(time.sleep, 3)] + # Get one of the processes, and terminate (kill) it + p = next(iter(self.executor._processes.values())) + p.terminate() + for fut in futures: + self.assertRaises(BrokenProcessPool, fut.result) + # Submitting other jobs fails as well. + self.assertRaises(BrokenProcessPool, self.executor.submit, pow, 2, 8) class FutureTests(unittest.TestCase): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index f5dff1e..7666fe4 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -298,6 +298,23 @@ class TestRetrievingSourceCode(GetSourceBase): del sys.modules[name] inspect.getmodule(compile('a=10','','single')) + def test_proceed_with_fake_filename(self): + '''doctest monkeypatches linecache to enable inspection''' + fn, source = '<test>', 'def x(): pass\n' + getlines = linecache.getlines + def monkey(filename, module_globals=None): + if filename == fn: + return source.splitlines(True) + else: + return getlines(filename, module_globals) + linecache.getlines = monkey + try: + ns = {} + exec(compile(source, fn, 'single'), ns) + inspect.getsource(ns["x"]) + finally: + linecache.getlines = getlines + class TestDecorators(GetSourceBase): fodderModule = mod2 diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index ceefd95..b0b8e19 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1399,8 +1399,7 @@ class DatagramHandlerTest(BaseTest): pointing to that server's address and port.""" BaseTest.setUp(self) addr = ('localhost', 0) - self.server = server = TestUDPServer(addr, self.handle_datagram, - 0.01) + self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01) server.start() server.ready.wait() self.sock_hdlr = logging.handlers.DatagramHandler('localhost', @@ -1478,6 +1477,11 @@ class SysLogHandlerTest(BaseTest): logger.error("sp\xe4m") self.handled.wait() self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m\x00') + self.handled.clear() + self.sl_hdlr.append_nul = False + logger.error("sp\xe4m") + self.handled.wait() + self.assertEqual(self.log_output, b'<11>\xef\xbb\xbfsp\xc3\xa4m') @unittest.skipUnless(threading, 'Threading required for this test.') diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 712378b..4bbb19b 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -417,6 +417,35 @@ class MmapTests(unittest.TestCase): m[x] = b self.assertEqual(m[x], b) + def test_read_all(self): + m = mmap.mmap(-1, 16) + self.addCleanup(m.close) + + # With no parameters, or None or a negative argument, reads all + m.write(bytes(range(16))) + m.seek(0) + self.assertEqual(m.read(), bytes(range(16))) + m.seek(8) + self.assertEqual(m.read(), bytes(range(8, 16))) + m.seek(16) + self.assertEqual(m.read(), b'') + m.seek(3) + self.assertEqual(m.read(None), bytes(range(3, 16))) + m.seek(4) + self.assertEqual(m.read(-1), bytes(range(4, 16))) + m.seek(5) + self.assertEqual(m.read(-2), bytes(range(5, 16))) + m.seek(9) + self.assertEqual(m.read(-42), bytes(range(9, 16))) + + def test_read_invalid_arg(self): + m = mmap.mmap(-1, 16) + self.addCleanup(m.close) + + self.assertRaises(TypeError, m.read, 'foo') + self.assertRaises(TypeError, m.read, 5.5) + self.assertRaises(TypeError, m.read, [1, 2, 3]) + def test_extended_getslice(self): # Test extended slicing by comparing with list slicing. s = bytes(reversed(range(256))) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py index 0c05ff6..85094cc 100644 --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -71,6 +71,23 @@ HAVE_GETVALUE = not getattr(_multiprocessing, 'HAVE_BROKEN_SEM_GETVALUE', False) WIN32 = (sys.platform == "win32") +if WIN32: + from _subprocess import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 + + def wait_for_handle(handle, timeout): + if timeout is None or timeout < 0.0: + timeout = INFINITE + else: + timeout = int(1000 * timeout) + return WaitForSingleObject(handle, timeout) == WAIT_OBJECT_0 +else: + from select import select + _select = util._eintr_retry(select) + + def wait_for_handle(handle, timeout): + if timeout is not None and timeout < 0.0: + timeout = None + return handle in _select([handle], [], [], timeout)[0] # # Some tests require ctypes @@ -307,6 +324,26 @@ class _TestProcess(BaseTestCase): ] self.assertEqual(result, expected) + @classmethod + def _test_sentinel(cls, event): + event.wait(10.0) + + def test_sentinel(self): + if self.TYPE == "threads": + return + event = self.Event() + p = self.Process(target=self._test_sentinel, args=(event,)) + with self.assertRaises(ValueError): + p.sentinel + p.start() + self.addCleanup(p.join) + sentinel = p.sentinel + self.assertIsInstance(sentinel, int) + self.assertFalse(wait_for_handle(sentinel, timeout=0.0)) + event.set() + p.join() + self.assertTrue(wait_for_handle(sentinel, timeout=DELTA)) + # # # diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py index da7ec05..ef70e37 100644 --- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -1,54 +1,107 @@ - -import netrc, os, unittest, sys +import netrc, os, unittest, sys, textwrap from test import support -TEST_NETRC = """ - - #this is a comment -#this is a comment -# this is a comment - -machine foo login log1 password pass1 account acct1 -machine bar login log1 password pass# account acct1 - -macdef macro1 -line1 -line2 - -macdef macro2 -line3 -line4 - -default login log2 password pass2 - -""" - temp_filename = support.TESTFN class NetrcTestCase(unittest.TestCase): - def setUp(self): - mode = 'w' - if sys.platform not in ['cygwin']: - mode += 't' - fp = open(temp_filename, mode) - fp.write(TEST_NETRC) - fp.close() - self.nrc = netrc.netrc(temp_filename) - def tearDown(self): os.unlink(temp_filename) - def test_case_1(self): - self.assertEqual(self.nrc.hosts['foo'], ('log1', 'acct1', 'pass1')) - self.assertEqual(self.nrc.hosts['default'], ('log2', None, 'pass2')) + def make_nrc(self, test_data): + test_data = textwrap.dedent(test_data) + mode = 'w' + if sys.platform != 'cygwin': + mode += 't' + with open(temp_filename, mode) as fp: + fp.write(test_data) + return netrc.netrc(temp_filename) + + def test_default(self): + nrc = self.make_nrc("""\ + machine host1.domain.com login log1 password pass1 account acct1 + default login log2 password pass2 + """) + self.assertEqual(nrc.hosts['host1.domain.com'], + ('log1', 'acct1', 'pass1')) + self.assertEqual(nrc.hosts['default'], ('log2', None, 'pass2')) def test_macros(self): - self.assertEqual(self.nrc.macros, {'macro1':['line1\n', 'line2\n'], - 'macro2':['line3\n', 'line4\n']}) + nrc = self.make_nrc("""\ + macdef macro1 + line1 + line2 + + macdef macro2 + line3 + line4 + """) + self.assertEqual(nrc.macros, {'macro1': ['line1\n', 'line2\n'], + 'macro2': ['line3\n', 'line4\n']}) + + def _test_passwords(self, nrc, passwd): + nrc = self.make_nrc(nrc) + self.assertEqual(nrc.hosts['host.domain.com'], ('log', 'acct', passwd)) + + def test_password_with_leading_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password #pass account acct + """, '#pass') + + def test_password_with_trailing_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password pass# account acct + """, 'pass#') + + def test_password_with_internal_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password pa#ss account acct + """, 'pa#ss') + + def _test_comment(self, nrc, passwd='pass'): + nrc = self.make_nrc(nrc) + self.assertEqual(nrc.hosts['foo.domain.com'], ('bar', None, passwd)) + self.assertEqual(nrc.hosts['bar.domain.com'], ('foo', None, 'pass')) + + def test_comment_before_machine_line(self): + self._test_comment("""\ + # comment + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_before_machine_line_no_space(self): + self._test_comment("""\ + #comment + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_before_machine_line_hash_only(self): + self._test_comment("""\ + # + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line(self): + self._test_comment("""\ + machine foo.domain.com login bar password pass # comment + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line_no_space(self): + self._test_comment("""\ + machine foo.domain.com login bar password pass #comment + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line_pass_has_hash(self): + self._test_comment("""\ + machine foo.domain.com login bar password #pass #comment + machine bar.domain.com login foo password pass + """, '#pass') - def test_parses_passwords_with_hash_character(self): - self.assertEqual(self.nrc.hosts['bar'], ('log1', 'acct1', 'pass#')) def test_main(): support.run_unittest(NetrcTestCase) diff --git a/Lib/test/test_ossaudiodev.py b/Lib/test/test_ossaudiodev.py index 9cb89d6..3908a05 100644 --- a/Lib/test/test_ossaudiodev.py +++ b/Lib/test/test_ossaudiodev.py @@ -170,6 +170,22 @@ class OSSAudioDevTests(unittest.TestCase): pass self.assertTrue(dsp.closed) + def test_on_closed(self): + dsp = ossaudiodev.open('w') + dsp.close() + self.assertRaises(ValueError, dsp.fileno) + self.assertRaises(ValueError, dsp.read, 1) + self.assertRaises(ValueError, dsp.write, b'x') + self.assertRaises(ValueError, dsp.writeall, b'x') + self.assertRaises(ValueError, dsp.bufsize) + self.assertRaises(ValueError, dsp.obufcount) + self.assertRaises(ValueError, dsp.obufcount) + self.assertRaises(ValueError, dsp.obuffree) + self.assertRaises(ValueError, dsp.getptr) + + mixer = ossaudiodev.openmixer() + mixer.close() + self.assertRaises(ValueError, mixer.fileno) def test_main(): try: diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index b59f6e6..93f86d9 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -1,8 +1,9 @@ -import sys import os -import unittest import platform import subprocess +import sys +import unittest +import warnings from test import support @@ -250,10 +251,12 @@ class PlatformTest(unittest.TestCase): command = '"{}" -c "print(\'Hello\')"'.format(sys.executable) else: command = "'{}' -c 'print(\"Hello\")'".format(sys.executable) - with platform.popen(command) as stdout: - hello = stdout.read().strip() - stdout.close() - self.assertEqual(hello, "Hello") + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + with platform.popen(command) as stdout: + hello = stdout.read().strip() + stdout.close() + self.assertEqual(hello, "Hello") data = 'plop' if mswindows: @@ -261,15 +264,17 @@ class PlatformTest(unittest.TestCase): else: command = "'{}' -c 'import sys; data=sys.stdin.read(); exit(len(data))'" command = command.format(sys.executable) - with platform.popen(command, 'w') as stdin: - stdout = stdin.write(data) - ret = stdin.close() - self.assertIsNotNone(ret) - if os.name == 'nt': - returncode = ret - else: - returncode = ret >> 8 - self.assertEqual(returncode, len(data)) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + with platform.popen(command, 'w') as stdin: + stdout = stdin.write(data) + ret = stdin.close() + self.assertIsNotNone(ret) + if os.name == 'nt': + returncode = ret + else: + returncode = ret >> 8 + self.assertEqual(returncode, len(data)) def test_main(): diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 421ea68..438634e 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -481,8 +481,8 @@ class PosixTester(unittest.TestCase): self.assertRaises(TypeError, os.pipe2, 'DEADBEEF') self.assertRaises(TypeError, os.pipe2, 0, 0) - # try calling without flag, like os.pipe() - r, w = os.pipe2() + # try calling with flags = 0, like os.pipe() + r, w = os.pipe2(0) os.close(r) os.close(w) @@ -569,6 +569,21 @@ class PosixTester(unittest.TestCase): os.chdir(curdir) support.rmtree(base_path) + @unittest.skipUnless(hasattr(posix, 'getgrouplist'), "test needs posix.getgrouplist()") + @unittest.skipUnless(hasattr(pwd, 'getpwuid'), "test needs pwd.getpwuid()") + @unittest.skipUnless(hasattr(os, 'getuid'), "test needs os.getuid()") + def test_getgrouplist(self): + with os.popen('id -G') as idg: + groups = idg.read().strip() + + if not groups: + raise unittest.SkipTest("need working 'id -G'") + + self.assertEqual( + set([int(x) for x in groups.split()]), + set(posix.getgrouplist(pwd.getpwuid(os.getuid())[0], + pwd.getpwuid(os.getuid())[3]))) + @unittest.skipUnless(hasattr(os, 'getegid'), "test needs os.getegid()") def test_getgroups(self): with os.popen('id -G') as idg: diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 0631390..effdbef 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -9,6 +9,7 @@ import struct import subprocess import traceback import sys, os, time, errno +from test.script_helper import assert_python_ok try: import threading except ImportError: @@ -600,12 +601,84 @@ class PendingSignalsTests(unittest.TestCase): @unittest.skipUnless(hasattr(signal, 'sigwait'), 'need signal.sigwait()') + @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), + 'need signal.pthread_sigmask()') + @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()') def test_sigwait(self): - old_handler = signal.signal(signal.SIGALRM, self.handler) - self.addCleanup(signal.signal, signal.SIGALRM, old_handler) + def test(signum): + signal.alarm(1) + received = signal.sigwait([signum]) + if received != signum: + print("sigwait() received %s, not %s" + % (received, signum), + file=sys.stderr) + os._exit(1) + + signum = signal.SIGALRM + + # sigwait must be called with the signal blocked: since the current + # process might have several threads running, we fork() a child process + # to have a single thread. + pid = os.fork() + if pid == 0: + # child: block and wait the signal + try: + signal.signal(signum, self.handler) + signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) - signal.alarm(1) - self.assertEqual(signal.sigwait([signal.SIGALRM]), signal.SIGALRM) + # Do the tests + test(signum) + + # The handler must not be called on unblock + try: + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + except ZeroDivisionError: + print("the signal handler has been called", + file=sys.stderr) + os._exit(1) + except BaseException as err: + print("error: {}".format(err), file=sys.stderr) + os._exit(1) + else: + os._exit(0) + else: + # parent: check that the child correcty received the signal + self.assertEqual(os.waitpid(pid, 0), (pid, 0)) + + @unittest.skipUnless(hasattr(signal, 'sigwait'), + 'need signal.sigwait()') + @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), + 'need signal.pthread_sigmask()') + @unittest.skipIf(threading is None, "test needs threading module") + def test_sigwait_thread(self): + # Check that calling sigwait() from a thread doesn't suspend the whole + # process. A new interpreter is spawned to avoid problems when mixing + # threads and fork(): only async-safe functions are allowed between + # fork() and exec(). + assert_python_ok("-c", """if True: + import os, threading, sys, time, signal + + # the default handler terminates the process + signum = signal.SIGUSR1 + + def kill_later(): + # wait until the main thread is waiting in sigwait() + time.sleep(1) + os.kill(os.getpid(), signum) + + # the signal must be blocked by all the threads + signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) + killer = threading.Thread(target=kill_later) + killer.start() + received = signal.sigwait([signum]) + if received != signum: + print("sigwait() received %s, not %s" % (received, signum), + file=sys.stderr) + sys.exit(1) + killer.join() + # unblock the signal, which should have been cleared by sigwait() + signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum]) + """) @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index dfe08fa..1204707 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -278,6 +278,21 @@ class DebuggingServerTests(unittest.TestCase): mexpect = '%s%s\n%s' % (MSG_BEGIN, m.decode('ascii'), MSG_END) self.assertEqual(self.output.getvalue(), mexpect) + def testSendNeedingDotQuote(self): + # Issue 12283 + m = '.A test\n.mes.sage.' + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) + smtp.sendmail('John', 'Sally', m) + # XXX (see comment in testSend) + time.sleep(0.01) + smtp.quit() + + self.client_evt.set() + self.serv_evt.wait() + self.output.flush() + mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END) + self.assertEqual(self.output.getvalue(), mexpect) + def testSendMessage(self): m = email.mime.text.MIMEText('A test message') smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 7d4ca2c..b52d8e8 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -127,9 +127,10 @@ class ProcessTestCase(BaseTestCase): with self.assertRaises(subprocess.TimeoutExpired) as c: output = subprocess.check_output( [sys.executable, "-c", - "import sys; sys.stdout.write('BDFL')\n" + "import sys, time\n" + "sys.stdout.write('BDFL')\n" "sys.stdout.flush()\n" - "while True: pass"], + "time.sleep(3600)"], # Some heavily loaded buildbots (sparc Debian 3.x) require # this much time to start and print. timeout=3) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 9663715..4dcb690 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -345,6 +345,24 @@ class TestsWithSourceFile(unittest.TestCase): with zipfile.ZipFile(f, "r") as zipfp: self.assertEqual(zipfp.namelist(), [TESTFN]) + def test_ignores_newline_at_end(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: + zipfp.write(TESTFN, TESTFN) + with open(TESTFN2, 'a') as f: + f.write("\r\n\00\00\00") + with zipfile.ZipFile(TESTFN2, "r") as zipfp: + self.assertIsInstance(zipfp, zipfile.ZipFile) + + def test_ignores_stuff_appended_past_comments(self): + with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: + zipfp.comment = b"this is a comment" + zipfp.write(TESTFN, TESTFN) + with open(TESTFN2, 'a') as f: + f.write("abcdef\r\n") + with zipfile.ZipFile(TESTFN2, "r") as zipfp: + self.assertIsInstance(zipfp, zipfile.ZipFile) + self.assertEqual(zipfp.comment, b"this is a comment") + def test_write_default_name(self): """Check that calling ZipFile.write without arcname specified produces the expected result.""" diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 50f4848..5cc7816 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -246,16 +246,14 @@ def _EndRecData(fpin): # found the magic number; attempt to unpack and interpret recData = data[start:start+sizeEndCentDir] endrec = list(struct.unpack(structEndArchive, recData)) - comment = data[start+sizeEndCentDir:] - # check that comment length is correct - if endrec[_ECD_COMMENT_SIZE] == len(comment): - # Append the archive comment and start offset - endrec.append(comment) - endrec.append(maxCommentStart + start) - - # Try to read the "Zip64 end of central directory" structure - return _EndRecData64(fpin, maxCommentStart + start - filesize, - endrec) + commentSize = endrec[_ECD_COMMENT_SIZE] #as claimed by the zip file + comment = data[start+sizeEndCentDir:start+sizeEndCentDir+commentSize] + endrec.append(comment) + endrec.append(maxCommentStart + start) + + # Try to read the "Zip64 end of central directory" structure + return _EndRecData64(fpin, maxCommentStart + start - filesize, + endrec) # Unable to find a valid end of central directory structure return diff --git a/Makefile.pre.in b/Makefile.pre.in index 07486fd..2ca89cf 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -950,7 +950,7 @@ libinstall: build_all $(srcdir)/Lib/$(PLATDIR) else true; \ fi; \ done - @for i in $(srcdir)/Lib/*.py $(srcdir)/Lib/*.egg-info $(srcdir)/Lib/*.cfg ; \ + @for i in $(srcdir)/Lib/*.py $(srcdir)/Lib/*.cfg ; \ do \ if test -x $$i; then \ $(INSTALL_SCRIPT) $$i $(DESTDIR)$(LIBDEST); \ @@ -116,6 +116,7 @@ Monty Brandenberg Georg Brandl Christopher Brannon Terrence Brannon +Erik Bray Brian Brazil Dave Brennan Tom Bridgman @@ -548,7 +549,9 @@ Vincent Legoll Kip Lehman Joerg Lehmann Robert Lehmann +Petri Lehtinen Luke Kenneth Casson Leighton +Tshepang Lekhonkhobe Marc-Andre Lemburg John Lenton Christopher Tur Lesniewski-Laas @@ -643,6 +646,7 @@ James A Morrison Derek McTavish Mounce Pablo Mouzo Mher Movsisyan +Ruslan Mstoi Sjoerd Mullender Sape Mullender Michael Muller @@ -13,6 +13,9 @@ Core and Builtins - Issue #12084: os.stat on Windows now works properly with relative symbolic links when called from any directory. +- Loosen type restrictions on the __dir__ method. __dir__ can now return any + sequence, which will be converted to a list and sorted by dir(). + - Issue #12265: Make error messages produced by passing an invalid set of arguments to a function more informative. @@ -190,6 +193,52 @@ Core and Builtins Library ------- +- Issue #12240: Allow multiple setup hooks in packaging's setup.cfg files. + Original patch by Erik Bray. + +- Issue #9284: Allow inspect.findsource() to find the source of doctest + functions. + +- Issue #11595: Fix assorted bugs in packaging.util.cfg_to_args, a + compatibility helper for the distutils-packaging transition. Original patch + by Erik Bray. + +- Issue #12287: In ossaudiodev, check that the device isn't closed in several + methods. + +- Issue #12009: Fixed regression in netrc file comment handling. + +- Issue #12246: Warn and fail when trying to install a third-party project from + an uninstalled Python (built in a source checkout). Original patch by + Tshepang Lekhonkhobe. + +- Issue #10694: zipfile now ignores garbage at the end of a zipfile. + +- Issue #12283: Fixed regression in smtplib quoting of leading dots in DATA. + +- Issue #10424: Argparse now includes the names of the missing required + arguments in the missing arguments error message. + +- Issue #12168: SysLogHandler now allows NUL termination to be controlled using + a new 'append_nul' attribute on the handler. + +- Issue #11583: Speed up os.path.isdir on Windows by using GetFileAttributes + instead of os.stat. + +- Issue #12021: Make mmap's read() method argument optional. Patch by Petri + Lehtinen. + +- Issue #9205: concurrent.futures.ProcessPoolExecutor now detects killed + children and raises BrokenProcessPool in such a situation. Previously it + would reliably freeze/deadlock. + +- Issue #12040: Expose a new attribute ``sentinel`` on instances of + :class:`multiprocessing.Process`. Also, fix Process.join() to not use + polling anymore, when given a timeout. + +- Issue #11893: Remove obsolete internal wrapper class ``SSLFakeFile`` in the + smtplib module. Patch by Catalin Iacob. + - Issue #12080: Fix a Decimal.power() case that took an unreasonably long time to compute. @@ -767,6 +816,12 @@ Library Build ----- +- Issue #10645: Installing Python does no longer create a + Python-X.Y.Z-pyX.Y.egg-info file in the lib-dynload directory. + +- Do not accidentally include the directory containing sqlite.h twice when + building sqlite3. + - Issue #11217: For 64-bit/32-bit Mac OS X universal framework builds, ensure "make install" creates symlinks in --prefix bin for the "-32" files in the framework bin directory like the installer does. diff --git a/Modules/_multiprocessing/win32_functions.c b/Modules/_multiprocessing/win32_functions.c index 12dc0cd..c017b2a 100644 --- a/Modules/_multiprocessing/win32_functions.c +++ b/Modules/_multiprocessing/win32_functions.c @@ -12,10 +12,223 @@ #define WIN32_FUNCTION(func) \ {#func, (PyCFunction)win32_ ## func, METH_VARARGS | METH_STATIC, ""} +#define WIN32_KWARGS_FUNCTION(func) \ + {#func, (PyCFunction)win32_ ## func, METH_VARARGS | METH_KEYWORDS | METH_STATIC, ""} + #define WIN32_CONSTANT(fmt, con) \ PyDict_SetItemString(Win32Type.tp_dict, #con, Py_BuildValue(fmt, con)) +/* Grab CancelIoEx dynamically from kernel32 */ +static int has_CancelIoEx = -1; +static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED); + +static int +check_CancelIoEx() +{ + if (has_CancelIoEx == -1) + { + HINSTANCE hKernel32 = GetModuleHandle("KERNEL32"); + * (FARPROC *) &Py_CancelIoEx = GetProcAddress(hKernel32, + "CancelIoEx"); + has_CancelIoEx = (Py_CancelIoEx != NULL); + } + return has_CancelIoEx; +} + + +/* + * A Python object wrapping an OVERLAPPED structure and other useful data + * for overlapped I/O + */ + +typedef struct { + PyObject_HEAD + OVERLAPPED overlapped; + /* For convenience, we store the file handle too */ + HANDLE handle; + /* Whether there's I/O in flight */ + int pending; + /* Whether I/O completed successfully */ + int completed; + /* Buffer used for reading (optional) */ + PyObject *read_buffer; + /* Buffer used for writing (optional) */ + Py_buffer write_buffer; +} OverlappedObject; + +static void +overlapped_dealloc(OverlappedObject *self) +{ + int err = GetLastError(); + if (self->pending) { + if (check_CancelIoEx()) + Py_CancelIoEx(self->handle, &self->overlapped); + else { + PyErr_SetString(PyExc_RuntimeError, + "I/O operations still in flight while destroying " + "Overlapped object, the process may crash"); + PyErr_WriteUnraisable(NULL); + } + } + CloseHandle(self->overlapped.hEvent); + SetLastError(err); + if (self->write_buffer.obj) + PyBuffer_Release(&self->write_buffer); + Py_CLEAR(self->read_buffer); + PyObject_Del(self); +} + +static PyObject * +overlapped_GetOverlappedResult(OverlappedObject *self, PyObject *waitobj) +{ + int wait; + BOOL res; + DWORD transferred = 0; + + wait = PyObject_IsTrue(waitobj); + if (wait < 0) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = GetOverlappedResult(self->handle, &self->overlapped, &transferred, + wait != 0); + Py_END_ALLOW_THREADS + + if (!res) { + int err = GetLastError(); + if (err == ERROR_IO_INCOMPLETE) + Py_RETURN_NONE; + if (err != ERROR_MORE_DATA) { + self->pending = 0; + return PyErr_SetExcFromWindowsErr(PyExc_IOError, err); + } + } + self->pending = 0; + self->completed = 1; + if (self->read_buffer) { + assert(PyBytes_CheckExact(self->read_buffer)); + if (_PyBytes_Resize(&self->read_buffer, transferred)) + return NULL; + } + return Py_BuildValue("lN", (long) transferred, PyBool_FromLong(res)); +} + +static PyObject * +overlapped_getbuffer(OverlappedObject *self) +{ + PyObject *res; + if (!self->completed) { + PyErr_SetString(PyExc_ValueError, + "can't get read buffer before GetOverlappedResult() " + "signals the operation completed"); + return NULL; + } + res = self->read_buffer ? self->read_buffer : Py_None; + Py_INCREF(res); + return res; +} + +static PyObject * +overlapped_cancel(OverlappedObject *self) +{ + BOOL res = TRUE; + + if (self->pending) { + Py_BEGIN_ALLOW_THREADS + if (check_CancelIoEx()) + res = Py_CancelIoEx(self->handle, &self->overlapped); + else + res = CancelIo(self->handle); + Py_END_ALLOW_THREADS + } + + /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */ + if (!res && GetLastError() != ERROR_NOT_FOUND) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + self->pending = 0; + Py_RETURN_NONE; +} + +static PyMethodDef overlapped_methods[] = { + {"GetOverlappedResult", (PyCFunction) overlapped_GetOverlappedResult, + METH_O, NULL}, + {"getbuffer", (PyCFunction) overlapped_getbuffer, METH_NOARGS, NULL}, + {"cancel", (PyCFunction) overlapped_cancel, METH_NOARGS, NULL}, + {NULL} +}; + +static PyMemberDef overlapped_members[] = { + {"event", T_HANDLE, + offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent), + READONLY, "overlapped event handle"}, + {NULL} +}; + +PyTypeObject OverlappedType = { + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_multiprocessing.win32.Overlapped", + /* tp_basicsize */ sizeof(OverlappedObject), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor) overlapped_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_reserved */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ 0, + /* tp_getattro */ 0, + /* tp_setattro */ 0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT, + /* tp_doc */ "OVERLAPPED structure wrapper", + /* tp_traverse */ 0, + /* tp_clear */ 0, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ overlapped_methods, + /* tp_members */ overlapped_members, + /* tp_getset */ 0, + /* tp_base */ 0, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ 0, +}; + +static OverlappedObject * +new_overlapped(HANDLE handle) +{ + OverlappedObject *self; + + self = PyObject_New(OverlappedObject, &OverlappedType); + if (!self) + return NULL; + self->handle = handle; + self->read_buffer = NULL; + self->pending = 0; + self->completed = 0; + memset(&self->overlapped, 0, sizeof(OVERLAPPED)); + memset(&self->write_buffer, 0, sizeof(Py_buffer)); + /* Manual reset, initially non-signalled */ + self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + return self; +} + + +/* + * Module functions + */ + static PyObject * win32_CloseHandle(PyObject *self, PyObject *args) { @@ -36,20 +249,44 @@ win32_CloseHandle(PyObject *self, PyObject *args) } static PyObject * -win32_ConnectNamedPipe(PyObject *self, PyObject *args) +win32_ConnectNamedPipe(PyObject *self, PyObject *args, PyObject *kwds) { HANDLE hNamedPipe; - LPOVERLAPPED lpOverlapped; + int use_overlapped = 0; BOOL success; + OverlappedObject *overlapped = NULL; + static char *kwlist[] = {"handle", "overlapped", NULL}; - if (!PyArg_ParseTuple(args, F_HANDLE F_POINTER, - &hNamedPipe, &lpOverlapped)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, + F_HANDLE "|i", kwlist, + &hNamedPipe, &use_overlapped)) return NULL; + if (use_overlapped) { + overlapped = new_overlapped(hNamedPipe); + if (!overlapped) + return NULL; + } + Py_BEGIN_ALLOW_THREADS - success = ConnectNamedPipe(hNamedPipe, lpOverlapped); + success = ConnectNamedPipe(hNamedPipe, + overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS + if (overlapped) { + int err = GetLastError(); + /* Overlapped ConnectNamedPipe never returns a success code */ + assert(success == 0); + if (err == ERROR_IO_PENDING) + overlapped->pending = 1; + else if (err == ERROR_PIPE_CONNECTED) + SetEvent(overlapped->overlapped.hEvent); + else { + Py_DECREF(overlapped); + return PyErr_SetFromWindowsErr(err); + } + return (PyObject *) overlapped; + } if (!success) return PyErr_SetFromWindowsErr(0); @@ -280,46 +517,109 @@ win32_send(PyObject *self, PyObject *args) } static PyObject * -win32_WriteFile(PyObject *self, PyObject *args) +win32_WriteFile(PyObject *self, PyObject *args, PyObject *kwds) { HANDLE handle; - Py_buffer buf; + Py_buffer _buf, *buf; + PyObject *bufobj; int written; BOOL ret; + int use_overlapped = 0; + OverlappedObject *overlapped = NULL; + static char *kwlist[] = {"handle", "buffer", "overlapped", NULL}; + + /* First get handle and use_overlapped to know which Py_buffer to use */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, + F_HANDLE "O|i:WriteFile", kwlist, + &handle, &bufobj, &use_overlapped)) + return NULL; + + if (use_overlapped) { + overlapped = new_overlapped(handle); + if (!overlapped) + return NULL; + buf = &overlapped->write_buffer; + } + else + buf = &_buf; - if (!PyArg_ParseTuple(args, F_HANDLE "y*:WriteFile" , &handle, &buf)) + if (!PyArg_Parse(bufobj, "y*", buf)) { + Py_XDECREF(overlapped); return NULL; + } Py_BEGIN_ALLOW_THREADS - ret = WriteFile(handle, buf.buf, buf.len, &written, NULL); + ret = WriteFile(handle, buf->buf, buf->len, &written, + overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS - PyBuffer_Release(&buf); + if (overlapped) { + int err = GetLastError(); + if (!ret) { + if (err == ERROR_IO_PENDING) + overlapped->pending = 1; + else { + Py_DECREF(overlapped); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + } + return (PyObject *) overlapped; + } + + PyBuffer_Release(buf); if (!ret) return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); return PyLong_FromLong(written); } static PyObject * -win32_ReadFile(PyObject *self, PyObject *args) +win32_ReadFile(PyObject *self, PyObject *args, PyObject *kwds) { HANDLE handle; int size; DWORD nread; PyObject *buf; BOOL ret; + int use_overlapped = 0; + OverlappedObject *overlapped = NULL; + static char *kwlist[] = {"handle", "size", "overlapped", NULL}; - if (!PyArg_ParseTuple(args, F_HANDLE "i:ReadFile" , &handle, &size)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, + F_HANDLE "i|i:ReadFile", kwlist, + &handle, &size, &use_overlapped)) return NULL; buf = PyBytes_FromStringAndSize(NULL, size); if (!buf) return NULL; + if (use_overlapped) { + overlapped = new_overlapped(handle); + if (!overlapped) { + Py_DECREF(buf); + return NULL; + } + /* Steals reference to buf */ + overlapped->read_buffer = buf; + } Py_BEGIN_ALLOW_THREADS - ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread, NULL); + ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread, + overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS + if (overlapped) { + int err = GetLastError(); + if (!ret) { + if (err == ERROR_IO_PENDING) + overlapped->pending = 1; + else if (err != ERROR_MORE_DATA) { + Py_DECREF(overlapped); + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + } + } + return (PyObject *) overlapped; + } + if (!ret && GetLastError() != ERROR_MORE_DATA) { Py_DECREF(buf); return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); @@ -373,19 +673,71 @@ win32_PeekNamedPipe(PyObject *self, PyObject *args) } } +static PyObject * +win32_WaitForMultipleObjects(PyObject* self, PyObject* args) +{ + DWORD result; + PyObject *handle_seq; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + Py_ssize_t nhandles, i; + int wait_flag; + int milliseconds = INFINITE; + + if (!PyArg_ParseTuple(args, "Oi|i:WaitForMultipleObjects", + &handle_seq, &wait_flag, &milliseconds)) + return NULL; + + if (!PySequence_Check(handle_seq)) { + PyErr_Format(PyExc_TypeError, + "sequence type expected, got '%s'", + Py_TYPE(handle_seq)->tp_doc); + return NULL; + } + nhandles = PySequence_Length(handle_seq); + if (nhandles == -1) + return NULL; + if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS) { + PyErr_Format(PyExc_ValueError, + "need at most %zd handles, got a sequence of length %zd", + MAXIMUM_WAIT_OBJECTS, nhandles); + return NULL; + } + for (i = 0; i < nhandles; i++) { + HANDLE h; + PyObject *v = PySequence_GetItem(handle_seq, i); + if (v == NULL) + return NULL; + if (!PyArg_Parse(v, F_HANDLE, &h)) + return NULL; + handles[i] = h; + } + + Py_BEGIN_ALLOW_THREADS + result = WaitForMultipleObjects((DWORD) nhandles, handles, + (BOOL) wait_flag, (DWORD) milliseconds); + Py_END_ALLOW_THREADS + + if (result == WAIT_FAILED) + return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); + + return PyLong_FromLong((int) result); +} + + static PyMethodDef win32_methods[] = { WIN32_FUNCTION(CloseHandle), WIN32_FUNCTION(GetLastError), WIN32_FUNCTION(OpenProcess), WIN32_FUNCTION(ExitProcess), - WIN32_FUNCTION(ConnectNamedPipe), + WIN32_KWARGS_FUNCTION(ConnectNamedPipe), WIN32_FUNCTION(CreateFile), WIN32_FUNCTION(CreateNamedPipe), - WIN32_FUNCTION(ReadFile), + WIN32_KWARGS_FUNCTION(ReadFile), WIN32_FUNCTION(PeekNamedPipe), WIN32_FUNCTION(SetNamedPipeHandleState), + WIN32_FUNCTION(WaitForMultipleObjects), WIN32_FUNCTION(WaitNamedPipe), - WIN32_FUNCTION(WriteFile), + WIN32_KWARGS_FUNCTION(WriteFile), WIN32_FUNCTION(closesocket), WIN32_FUNCTION(recv), WIN32_FUNCTION(send), @@ -407,12 +759,18 @@ create_win32_namespace(void) return NULL; Py_INCREF(&Win32Type); + if (PyType_Ready(&OverlappedType) < 0) + return NULL; + PyDict_SetItemString(Win32Type.tp_dict, "Overlapped", + (PyObject *) &OverlappedType); + WIN32_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); WIN32_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); WIN32_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); + WIN32_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); WIN32_CONSTANT(F_DWORD, GENERIC_READ); WIN32_CONSTANT(F_DWORD, GENERIC_WRITE); WIN32_CONSTANT(F_DWORD, INFINITE); diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 533f404..ae68c15 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2091,7 +2091,7 @@ array_repr(arrayobject *a) if (len == 0) { return PyUnicode_FromFormat("array('%c')", (int)typecode); } - if ((typecode == 'u')) + if (typecode == 'u') v = array_tounicode(a, NULL); else v = array_tolist(a, NULL); diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 36ca67d..ab12e2c 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -240,15 +240,37 @@ mmap_read_line_method(mmap_object *self, return result; } +/* Basically the "n" format code with the ability to turn None into -1. */ +static int +mmap_convert_ssize_t(PyObject *obj, void *result) { + Py_ssize_t limit; + if (obj == Py_None) { + limit = -1; + } + else if (PyNumber_Check(obj)) { + limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError); + if (limit == -1 && PyErr_Occurred()) + return 0; + } + else { + PyErr_Format(PyExc_TypeError, + "integer argument expected, got '%.200s'", + Py_TYPE(obj)->tp_name); + return 0; + } + *((Py_ssize_t *)result) = limit; + return 1; +} + static PyObject * mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes, n; + Py_ssize_t num_bytes = -1, n; PyObject *result; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n:read", &num_bytes)) + if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes)) return(NULL); /* silently 'adjust' out-of-range requests */ @@ -645,9 +667,9 @@ mmap_move_method(mmap_object *self, PyObject *args) return NULL; } else { /* bounds check the values */ - if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt || - src < 0 || src > self->size || (src + cnt) > self->size || - dest < 0 || dest > self->size || (dest + cnt) > self->size) { + if ((cnt + dest) < cnt || (cnt + src) < cnt || + src > self->size || (src + cnt) > self->size || + dest > self->size || (dest + cnt) > self->size) { PyErr_SetString(PyExc_ValueError, "source, destination, or count out of range"); return NULL; diff --git a/Modules/nismodule.c b/Modules/nismodule.c index a81ca8c..0af495f 100644 --- a/Modules/nismodule.c +++ b/Modules/nismodule.c @@ -411,7 +411,7 @@ nis_maps (PyObject *self, PyObject *args, PyObject *kwdict) return NULL; if ((list = PyList_New(0)) == NULL) return NULL; - for (maps = maps; maps; maps = maps->next) { + for (; maps; maps = maps->next) { PyObject *str = PyUnicode_FromString(maps->map); if (!str || PyList_Append(list, str) < 0) { diff --git a/Modules/ossaudiodev.c b/Modules/ossaudiodev.c index e660e50..1505731 100644 --- a/Modules/ossaudiodev.c +++ b/Modules/ossaudiodev.c @@ -213,6 +213,21 @@ oss_mixer_dealloc(oss_mixer_t *self) * Helper functions */ +/* Check if a given file descriptor is valid (i.e. hasn't been closed). + * If true, return 1. Otherwise, raise ValueError and return 0. + */ +static int _is_fd_valid(int fd) +{ + /* the FD is set to -1 in oss_close()/oss_mixer_close() */ + if (fd >= 0) { + return 1; + } else { + PyErr_SetString(PyExc_ValueError, + "Operation on closed OSS device."); + return 0; + } +} + /* _do_ioctl_1() is a private helper function used for the OSS ioctls -- SNDCTL_DSP_{SETFMT,CHANNELS,SPEED} -- that that are called from C like this: @@ -300,6 +315,9 @@ _do_ioctl_0(int fd, PyObject *args, char *fname, int cmd) static PyObject * oss_nonblock(oss_audio_t *self, PyObject *unused) { + if (!_is_fd_valid(self->fd)) + return NULL; + /* Hmmm: it doesn't appear to be possible to return to blocking mode once we're in non-blocking mode! */ if (ioctl(self->fd, SNDCTL_DSP_NONBLOCK, NULL) == -1) @@ -311,6 +329,9 @@ oss_nonblock(oss_audio_t *self, PyObject *unused) static PyObject * oss_setfmt(oss_audio_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1(self->fd, args, "setfmt", SNDCTL_DSP_SETFMT); } @@ -318,6 +339,10 @@ static PyObject * oss_getfmts(oss_audio_t *self, PyObject *unused) { int mask; + + if (!_is_fd_valid(self->fd)) + return NULL; + if (ioctl(self->fd, SNDCTL_DSP_GETFMTS, &mask) == -1) return PyErr_SetFromErrno(PyExc_IOError); return PyLong_FromLong(mask); @@ -326,30 +351,45 @@ oss_getfmts(oss_audio_t *self, PyObject *unused) static PyObject * oss_channels(oss_audio_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1(self->fd, args, "channels", SNDCTL_DSP_CHANNELS); } static PyObject * oss_speed(oss_audio_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1(self->fd, args, "speed", SNDCTL_DSP_SPEED); } static PyObject * oss_sync(oss_audio_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_0(self->fd, args, "sync", SNDCTL_DSP_SYNC); } static PyObject * oss_reset(oss_audio_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_0(self->fd, args, "reset", SNDCTL_DSP_RESET); } static PyObject * oss_post(oss_audio_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_0(self->fd, args, "post", SNDCTL_DSP_POST); } @@ -364,6 +404,9 @@ oss_read(oss_audio_t *self, PyObject *args) char *cp; PyObject *rv; + if (!_is_fd_valid(self->fd)) + return NULL; + if (!PyArg_ParseTuple(args, "i:read", &size)) return NULL; rv = PyBytes_FromStringAndSize(NULL, size); @@ -391,6 +434,9 @@ oss_write(oss_audio_t *self, PyObject *args) char *cp; int rv, size; + if (!_is_fd_valid(self->fd)) + return NULL; + if (!PyArg_ParseTuple(args, "y#:write", &cp, &size)) { return NULL; } @@ -422,6 +468,9 @@ oss_writeall(oss_audio_t *self, PyObject *args) mode, the behaviour of write() and writeall() from Python is indistinguishable. */ + if (!_is_fd_valid(self->fd)) + return NULL; + if (!PyArg_ParseTuple(args, "y#:write", &cp, &size)) return NULL; @@ -489,6 +538,9 @@ oss_exit(PyObject *self, PyObject *unused) static PyObject * oss_fileno(oss_audio_t *self, PyObject *unused) { + if (!_is_fd_valid(self->fd)) + return NULL; + return PyLong_FromLong(self->fd); } @@ -503,6 +555,9 @@ oss_setparameters(oss_audio_t *self, PyObject *args) int fmt, channels, rate; PyObject * rv; /* return tuple (fmt, channels, rate) */ + if (!_is_fd_valid(self->fd)) + return NULL; + if (!PyArg_ParseTuple(args, "iii|i:setparameters", &wanted_fmt, &wanted_channels, &wanted_rate, &strict)) @@ -593,6 +648,9 @@ oss_bufsize(oss_audio_t *self, PyObject *unused) audio_buf_info ai; int nchannels=0, ssize=0; + if (!_is_fd_valid(self->fd)) + return NULL; + if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) { PyErr_SetFromErrno(PyExc_IOError); return NULL; @@ -612,6 +670,9 @@ oss_obufcount(oss_audio_t *self, PyObject *unused) audio_buf_info ai; int nchannels=0, ssize=0; + if (!_is_fd_valid(self->fd)) + return NULL; + if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) { PyErr_SetFromErrno(PyExc_IOError); return NULL; @@ -632,6 +693,9 @@ oss_obuffree(oss_audio_t *self, PyObject *unused) audio_buf_info ai; int nchannels=0, ssize=0; + if (!_is_fd_valid(self->fd)) + return NULL; + if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) { PyErr_SetFromErrno(PyExc_IOError); return NULL; @@ -649,6 +713,9 @@ oss_getptr(oss_audio_t *self, PyObject *unused) count_info info; int req; + if (!_is_fd_valid(self->fd)) + return NULL; + if (self->mode == O_RDONLY) req = SNDCTL_DSP_GETIPTR; else @@ -679,6 +746,9 @@ oss_mixer_close(oss_mixer_t *self, PyObject *unused) static PyObject * oss_mixer_fileno(oss_mixer_t *self, PyObject *unused) { + if (!_is_fd_valid(self->fd)) + return NULL; + return PyLong_FromLong(self->fd); } @@ -687,6 +757,9 @@ oss_mixer_fileno(oss_mixer_t *self, PyObject *unused) static PyObject * oss_mixer_controls(oss_mixer_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1_internal(self->fd, args, "controls", SOUND_MIXER_READ_DEVMASK); } @@ -694,6 +767,9 @@ oss_mixer_controls(oss_mixer_t *self, PyObject *args) static PyObject * oss_mixer_stereocontrols(oss_mixer_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1_internal(self->fd, args, "stereocontrols", SOUND_MIXER_READ_STEREODEVS); } @@ -701,6 +777,9 @@ oss_mixer_stereocontrols(oss_mixer_t *self, PyObject *args) static PyObject * oss_mixer_reccontrols(oss_mixer_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1_internal(self->fd, args, "reccontrols", SOUND_MIXER_READ_RECMASK); } @@ -710,6 +789,9 @@ oss_mixer_get(oss_mixer_t *self, PyObject *args) { int channel, volume; + if (!_is_fd_valid(self->fd)) + return NULL; + /* Can't use _do_ioctl_1 because of encoded arg thingy. */ if (!PyArg_ParseTuple(args, "i:get", &channel)) return NULL; @@ -730,6 +812,9 @@ oss_mixer_set(oss_mixer_t *self, PyObject *args) { int channel, volume, leftVol, rightVol; + if (!_is_fd_valid(self->fd)) + return NULL; + /* Can't use _do_ioctl_1 because of encoded arg thingy. */ if (!PyArg_ParseTuple(args, "i(ii):set", &channel, &leftVol, &rightVol)) return NULL; @@ -755,6 +840,9 @@ oss_mixer_set(oss_mixer_t *self, PyObject *args) static PyObject * oss_mixer_get_recsrc(oss_mixer_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1_internal(self->fd, args, "get_recsrc", SOUND_MIXER_READ_RECSRC); } @@ -762,6 +850,9 @@ oss_mixer_get_recsrc(oss_mixer_t *self, PyObject *args) static PyObject * oss_mixer_set_recsrc(oss_mixer_t *self, PyObject *args) { + if (!_is_fd_valid(self->fd)) + return NULL; + return _do_ioctl_1(self->fd, args, "set_recsrc", SOUND_MIXER_WRITE_RECSRC); } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 518fa1e..14d18bc 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3007,6 +3007,45 @@ posix__getfileinformation(PyObject *self, PyObject *args) info.nFileIndexHigh, info.nFileIndexLow); } + +PyDoc_STRVAR(posix__isdir__doc__, +"Return true if the pathname refers to an existing directory."); + +static PyObject * +posix__isdir(PyObject *self, PyObject *args) +{ + PyObject *opath; + char *path; + PyUnicodeObject *po; + DWORD attributes; + + if (PyArg_ParseTuple(args, "U|:_isdir", &po)) { + Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po); + + attributes = GetFileAttributesW(wpath); + if (attributes == INVALID_FILE_ATTRIBUTES) + Py_RETURN_FALSE; + goto check; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + + if (!PyArg_ParseTuple(args, "O&:_isdir", + PyUnicode_FSConverter, &opath)) + return NULL; + + path = PyBytes_AsString(opath); + attributes = GetFileAttributesA(path); + if (attributes == INVALID_FILE_ATTRIBUTES) + Py_RETURN_FALSE; + +check: + if (attributes & FILE_ATTRIBUTE_DIRECTORY) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} #endif /* MS_WINDOWS */ PyDoc_STRVAR(posix_mkdir__doc__, @@ -4680,6 +4719,70 @@ posix_getpid(PyObject *self, PyObject *noargs) return PyLong_FromPid(getpid()); } +#ifdef HAVE_GETGROUPLIST +PyDoc_STRVAR(posix_getgrouplist__doc__, +"getgrouplist(user, group) -> list of groups to which a user belongs\n\n\ +Returns a list of groups to which a user belongs.\n\n\ + user: username to lookup\n\ + group: base group id of the user"); + +static PyObject * +posix_getgrouplist(PyObject *self, PyObject *args) +{ +#ifdef NGROUPS_MAX +#define MAX_GROUPS NGROUPS_MAX +#else + /* defined to be 16 on Solaris7, so this should be a small number */ +#define MAX_GROUPS 64 +#endif + + const char *user; + int i, ngroups; + PyObject *list; +#ifdef __APPLE__ + int *groups, basegid; +#else + gid_t *groups, basegid; +#endif + ngroups = MAX_GROUPS; + + if (!PyArg_ParseTuple(args, "si", &user, &basegid)) + return NULL; + +#ifdef __APPLE__ + groups = PyMem_Malloc(ngroups * sizeof(int)); +#else + groups = PyMem_Malloc(ngroups * sizeof(gid_t)); +#endif + if (groups == NULL) + return PyErr_NoMemory(); + + if (getgrouplist(user, basegid, groups, &ngroups) == -1) { + PyMem_Del(groups); + return posix_error(); + } + + list = PyList_New(ngroups); + if (list == NULL) { + PyMem_Del(groups); + return NULL; + } + + for (i = 0; i < ngroups; i++) { + PyObject *o = PyLong_FromUnsignedLong((unsigned long)groups[i]); + if (o == NULL) { + Py_DECREF(list); + PyMem_Del(groups); + return NULL; + } + PyList_SET_ITEM(list, i, o); + } + + PyMem_Del(groups); + + return list; +} +#endif #ifdef HAVE_GETGROUPS PyDoc_STRVAR(posix_getgroups__doc__, @@ -6596,20 +6699,21 @@ posix_pipe(PyObject *self, PyObject *noargs) #ifdef HAVE_PIPE2 PyDoc_STRVAR(posix_pipe2__doc__, -"pipe2(flags=0) -> (read_end, write_end)\n\n\ -Create a pipe with flags set atomically.\ -flags is optional and can be constructed by ORing together zero or more\n\ -of these values: O_NONBLOCK, O_CLOEXEC.\n\ +"pipe2(flags) -> (read_end, write_end)\n\n\ +Create a pipe with flags set atomically.\n\ +flags can be constructed by ORing together one or more of these values:\n\ +O_NONBLOCK, O_CLOEXEC.\n\ "); static PyObject * -posix_pipe2(PyObject *self, PyObject *args) +posix_pipe2(PyObject *self, PyObject *arg) { - int flags = 0; + int flags; int fds[2]; int res; - if (!PyArg_ParseTuple(args, "|i:pipe2", &flags)) + flags = PyLong_AsLong(arg); + if (flags == -1 && PyErr_Occurred()) return NULL; res = pipe2(fds, flags); @@ -9390,6 +9494,9 @@ static PyMethodDef posix_methods[] = { #ifdef HAVE_GETGID {"getgid", posix_getgid, METH_NOARGS, posix_getgid__doc__}, #endif /* HAVE_GETGID */ +#ifdef HAVE_GETGROUPLIST + {"getgrouplist", posix_getgrouplist, METH_VARARGS, posix_getgrouplist__doc__}, +#endif #ifdef HAVE_GETGROUPS {"getgroups", posix_getgroups, METH_NOARGS, posix_getgroups__doc__}, #endif @@ -9514,7 +9621,7 @@ static PyMethodDef posix_methods[] = { {"pipe", posix_pipe, METH_NOARGS, posix_pipe__doc__}, #endif #ifdef HAVE_PIPE2 - {"pipe2", posix_pipe2, METH_VARARGS, posix_pipe2__doc__}, + {"pipe2", posix_pipe2, METH_O, posix_pipe2__doc__}, #endif #ifdef HAVE_MKFIFO {"mkfifo", posix_mkfifo, METH_VARARGS, posix_mkfifo__doc__}, @@ -9607,6 +9714,7 @@ static PyMethodDef posix_methods[] = { {"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL}, {"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL}, {"_getfileinformation", posix__getfileinformation, METH_VARARGS, NULL}, + {"_isdir", posix__isdir, METH_VARARGS, posix__isdir__doc__}, #endif #ifdef HAVE_GETLOADAVG {"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__}, diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 6d27ab3..94e6bcb 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -662,7 +662,9 @@ signal_sigwait(PyObject *self, PyObject *args) if (iterable_to_sigset(signals, &set)) return NULL; + Py_BEGIN_ALLOW_THREADS err = sigwait(&set, &signum); + Py_END_ALLOW_THREADS if (err) { errno = err; return PyErr_SetFromErrno(PyExc_OSError); diff --git a/Objects/object.c b/Objects/object.c index e42c1d9..05c52f1 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1,5 +1,5 @@ -/* Generic object operations; and implementation of None (NoObject) */ +/* Generic object operations; and implementation of None */ #include "Python.h" #include "frameobject.h" @@ -1205,6 +1205,10 @@ _dir_locals(void) Py_DECREF(names); return NULL; } + if (PyList_Sort(names)) { + Py_DECREF(names); + return NULL; + } /* the locals don't need to be DECREF'd */ return names; } @@ -1213,7 +1217,7 @@ _dir_locals(void) static PyObject * _dir_object(PyObject *obj) { - PyObject *result; + PyObject *result, *sorted; static PyObject *dir_str = NULL; PyObject *dirfunc = _PyObject_LookupSpecial(obj, "__dir__", &dir_str); @@ -1228,18 +1232,16 @@ _dir_object(PyObject *obj) Py_DECREF(dirfunc); if (result == NULL) return NULL; - - /* result must be a list */ - /* XXX(gbrandl): could also check if all items are strings */ - if (!PyList_Check(result)) { - PyErr_Format(PyExc_TypeError, - "__dir__() must return a list, not %.200s", - Py_TYPE(result)->tp_name); - Py_DECREF(result); - result = NULL; + /* return sorted(result) */ + sorted = PySequence_List(result); + Py_DECREF(result); + if (sorted == NULL) + return NULL; + if (PyList_Sort(sorted)) { + Py_DECREF(sorted); + return NULL; } - - return result; + return sorted; } /* Implementation of dir() -- if obj is NULL, returns the names in the current @@ -1249,31 +1251,13 @@ _dir_object(PyObject *obj) PyObject * PyObject_Dir(PyObject *obj) { - PyObject * result; - - if (obj == NULL) - /* no object -- introspect the locals */ - result = _dir_locals(); - else - /* object -- introspect the object */ - result = _dir_object(obj); - - assert(result == NULL || PyList_Check(result)); - - if (result != NULL && PyList_Sort(result) != 0) { - /* sorting the list failed */ - Py_DECREF(result); - result = NULL; - } - - return result; + return (obj == NULL) ? _dir_locals() : _dir_object(obj); } /* -NoObject is usable as a non-NULL undefined value, used by the macro None. +None is as a non-NULL undefined value. There is (and should be!) no way to create other objects of this type, so there is exactly one (which is indestructible, by the way). -(XXX This type and the type of NotImplemented below should be unified.) */ /* ARGSUSED */ diff --git a/Python/dynload_win.c b/Python/dynload_win.c index 9869f6a..932a637 100644 --- a/Python/dynload_win.c +++ b/Python/dynload_win.c @@ -185,28 +185,19 @@ dl_funcptr _PyImport_GetDynLoadWindows(const char *shortname, { HINSTANCE hDLL = NULL; - wchar_t pathbuf[260]; unsigned int old_mode; ULONG_PTR cookie = 0; - /* We use LoadLibraryEx so Windows looks for dependent DLLs - in directory of pathname first. However, Windows95 - can sometimes not work correctly unless the absolute - path is used. If GetFullPathName() fails, the LoadLibrary - will certainly fail too, so use its error code */ - + /* Don't display a message box when Python can't load a DLL */ old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); - if (GetFullPathNameW(PyUnicode_AS_UNICODE(pathname), - sizeof(pathbuf) / sizeof(pathbuf[0]), - pathbuf, - NULL)) { - ULONG_PTR cookie = _Py_ActivateActCtx(); - /* XXX This call doesn't exist in Windows CE */ - hDLL = LoadLibraryExW(PyUnicode_AS_UNICODE(pathname), NULL, - LOAD_WITH_ALTERED_SEARCH_PATH); - _Py_DeactivateActCtx(cookie); - } + cookie = _Py_ActivateActCtx(); + /* We use LoadLibraryEx so Windows looks for dependent DLLs + in directory of pathname first. */ + /* XXX This call doesn't exist in Windows CE */ + hDLL = LoadLibraryExW(PyUnicode_AS_UNICODE(pathname), NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + _Py_DeactivateActCtx(cookie); /* restore old error mode settings */ SetErrorMode(old_mode); @@ -1,13 +1,13 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for python 3.3. +# Generated by GNU Autoconf 2.67 for python 3.3. # # Report bugs to <http://bugs.python.org/>. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -319,7 +319,7 @@ $as_echo X"$as_dir" | test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p @@ -359,19 +359,19 @@ else fi # as_fn_arith -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. +# script with STATUS, using 1 if that was 0. as_fn_error () { - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -533,7 +533,7 @@ test -n "$DJDIR" || exec 7<&0 </dev/null exec 6>&1 # Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` @@ -833,8 +833,9 @@ do fi case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. @@ -879,7 +880,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -905,7 +906,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1109,7 +1110,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1125,7 +1126,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1155,8 +1156,8 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information." + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" ;; *=*) @@ -1164,7 +1165,7 @@ Try \`$0 --help' for more information." # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1182,13 +1183,13 @@ done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error "missing argument to $ac_option" + as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; - fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1211,7 +1212,7 @@ do [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac - as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' @@ -1225,8 +1226,8 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1241,9 +1242,9 @@ test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error "working directory cannot be determined" + as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error "pwd does not report name of working directory" + as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. @@ -1282,11 +1283,11 @@ else fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then @@ -1326,7 +1327,7 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages + -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files @@ -1511,9 +1512,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF python configure 3.3 -generated by GNU Autoconf 2.65 +generated by GNU Autoconf 2.67 -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1629,7 +1630,7 @@ $as_echo "$ac_try_echo"; } >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } >/dev/null && { + test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : @@ -1653,10 +1654,10 @@ fi ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1692,7 +1693,7 @@ if ac_fn_c_try_cpp "$LINENO"; then : else ac_header_preproc=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } @@ -1715,17 +1716,15 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( cat <<\_ASBOX -## -------------------------------------- ## +( $as_echo "## -------------------------------------- ## ## Report this to http://bugs.python.org/ ## -## -------------------------------------- ## -_ASBOX +## -------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1789,7 +1788,7 @@ ac_fn_c_check_header_compile () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1820,7 +1819,7 @@ ac_fn_c_check_type () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1874,7 +1873,7 @@ ac_fn_c_find_uintX_t () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1904,8 +1903,7 @@ if ac_fn_c_try_compile "$LINENO"; then : esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - eval as_val=\$$3 - if test "x$as_val" = x""no; then : + if eval test \"x\$"$3"\" = x"no"; then : else break @@ -1928,7 +1926,7 @@ ac_fn_c_find_intX_t () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1979,8 +1977,7 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - eval as_val=\$$3 - if test "x$as_val" = x""no; then : + if eval test \"x\$"$3"\" = x"no"; then : else break @@ -2180,7 +2177,7 @@ ac_fn_c_check_func () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2248,7 +2245,7 @@ ac_fn_c_check_member () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } -if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$4+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2296,15 +2293,18 @@ $as_echo "$ac_res" >&6; } } # ac_fn_c_check_member -# ac_fn_c_check_decl LINENO SYMBOL VAR -# ------------------------------------ -# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5 -$as_echo_n "checking whether $2 is declared... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2313,8 +2313,12 @@ $4 int main () { -#ifndef $2 - (void) $2; +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif #endif ; @@ -2339,7 +2343,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 3.3, which was -generated by GNU Autoconf 2.65. Invocation command line was +generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ @@ -2449,11 +2453,9 @@ trap 'exit_status=$? { echo - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( @@ -2487,11 +2489,9 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo for ac_var in $ac_subst_vars do @@ -2504,11 +2504,9 @@ _ASBOX echo if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## + $as_echo "## ------------------- ## ## File substitutions. ## -## ------------------- ## -_ASBOX +## ------------------- ##" echo for ac_var in $ac_subst_files do @@ -2522,11 +2520,9 @@ _ASBOX fi if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo cat confdefs.h echo @@ -2581,7 +2577,12 @@ _ACEOF ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site @@ -2596,7 +2597,11 @@ do { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5 ; } fi done @@ -2672,7 +2677,7 @@ if $ac_cache_corrupted; then $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## @@ -2832,7 +2837,7 @@ if test "${enable_universalsdk+set}" = set; then : UNIVERSALSDK=$enableval if test ! -d "${UNIVERSALSDK}" then - as_fn_error "--enable-universalsdk specifies non-existing SDK: ${UNIVERSALSDK}" "$LINENO" 5 + as_fn_error $? "--enable-universalsdk specifies non-existing SDK: ${UNIVERSALSDK}" "$LINENO" 5 fi ;; esac @@ -3224,7 +3229,7 @@ $as_echo "$without_gcc" >&6; } # If the user switches compilers, we can't believe the cache if test ! -z "$ac_cv_prog_CC" -a ! -z "$CC" -a "$CC" != "$ac_cv_prog_CC" then - as_fn_error "cached CC is different -- throw away $cache_file + as_fn_error $? "cached CC is different -- throw away $cache_file (it is also a good idea to do 'make clean' before compiling)" "$LINENO" 5 fi @@ -3534,8 +3539,8 @@ fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "no acceptable C compiler found in \$PATH -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -3649,9 +3654,8 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "C compiler cannot create executables -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -3693,8 +3697,8 @@ done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -3751,9 +3755,9 @@ $as_echo "$ac_try_echo"; } >&5 else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot run C compiled programs. +as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details." "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi @@ -3804,8 +3808,8 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of object files: cannot compile -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi @@ -4288,7 +4292,7 @@ else # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4304,11 +4308,11 @@ else ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi @@ -4347,7 +4351,7 @@ else # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4363,18 +4367,18 @@ else ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c @@ -4435,7 +4439,7 @@ esac done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then - as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP @@ -4501,7 +4505,7 @@ esac done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then - as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP @@ -4633,8 +4637,7 @@ do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -5252,16 +5255,22 @@ bsdos*|hp*|HP*) esac ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - for ac_t in install-sh install.sh shtool; do - if test -f "$ac_dir/$ac_t"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/$ac_t -c" - break 2 - fi - done + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi done if test -z "$ac_aux_dir"; then - as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, @@ -5599,7 +5608,7 @@ $as_echo "$CC" >&6; } ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" else - as_fn_error "proper usage is --with-universal-arch=32-bit|64-bit|all|intel|3-way" "$LINENO" 5 + as_fn_error $? "proper usage is --with-universal-arch=32-bit|64-bit|all|intel|3-way" "$LINENO" 5 fi @@ -6087,8 +6096,7 @@ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -6102,7 +6110,7 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval "test \"\${$as_ac_Header+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6129,8 +6137,7 @@ fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF @@ -6655,9 +6662,8 @@ else if test "$ac_cv_type_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (int) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (int) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_int=0 fi @@ -6689,9 +6695,8 @@ else if test "$ac_cv_type_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (long) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_long=0 fi @@ -6723,9 +6728,8 @@ else if test "$ac_cv_type_void_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (void *) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_void_p=0 fi @@ -6757,9 +6761,8 @@ else if test "$ac_cv_type_short" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (short) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (short) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_short=0 fi @@ -6791,9 +6794,8 @@ else if test "$ac_cv_type_float" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (float) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (float) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_float=0 fi @@ -6825,9 +6827,8 @@ else if test "$ac_cv_type_double" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (double) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (double) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_double=0 fi @@ -6859,9 +6860,8 @@ else if test "$ac_cv_type_fpos_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (fpos_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (fpos_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_fpos_t=0 fi @@ -6893,9 +6893,8 @@ else if test "$ac_cv_type_size_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (size_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (size_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_size_t=0 fi @@ -6927,9 +6926,8 @@ else if test "$ac_cv_type_pid_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (pid_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (pid_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_pid_t=0 fi @@ -6988,9 +6986,8 @@ else if test "$ac_cv_type_long_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (long long) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long long) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_long_long=0 fi @@ -7050,9 +7047,8 @@ else if test "$ac_cv_type_long_double" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (long double) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long double) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_long_double=0 fi @@ -7113,9 +7109,8 @@ else if test "$ac_cv_type__Bool" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (_Bool) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (_Bool) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof__Bool=0 fi @@ -7162,9 +7157,8 @@ else if test "$ac_cv_type_uintptr_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (uintptr_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (uintptr_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_uintptr_t=0 fi @@ -7204,9 +7198,8 @@ else if test "$ac_cv_type_off_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (off_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (off_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_off_t=0 fi @@ -7267,9 +7260,8 @@ else if test "$ac_cv_type_time_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (time_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (time_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_time_t=0 fi @@ -7340,9 +7332,8 @@ else if test "$ac_cv_type_pthread_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (pthread_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (pthread_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_pthread_t=0 fi @@ -7429,7 +7420,7 @@ fi MACOSX_DEFAULT_ARCH="ppc" ;; *) - as_fn_error "Unexpected output of 'arch' on OSX" "$LINENO" 5 + as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5 ;; esac else @@ -7441,7 +7432,7 @@ fi MACOSX_DEFAULT_ARCH="ppc64" ;; *) - as_fn_error "Unexpected output of 'arch' on OSX" "$LINENO" 5 + as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5 ;; esac @@ -7467,7 +7458,7 @@ $as_echo "#define WITH_NEXT_FRAMEWORK 1" >>confdefs.h $as_echo "yes" >&6; } if test $enable_shared = "yes" then - as_fn_error "Specifying both --enable-shared and --enable-framework is not supported, use only --enable-framework instead" "$LINENO" 5 + as_fn_error $? "Specifying both --enable-shared and --enable-framework is not supported, use only --enable-framework instead" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 @@ -8307,12 +8298,12 @@ if test "${with_dbmliborder+set}" = set; then : withval=$with_dbmliborder; if test x$with_dbmliborder = xyes then -as_fn_error "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 +as_fn_error $? "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 else for db in `echo $with_dbmliborder | sed 's/:/ /g'`; do if test x$db != xndbm && test x$db != xgdbm && test x$db != xbdb then - as_fn_error "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 + as_fn_error $? "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 fi done fi @@ -9285,7 +9276,7 @@ if test "x$ac_cv_header_valgrind_valgrind_h" = x""yes; then : $as_echo "#define WITH_VALGRIND 1" >>confdefs.h else - as_fn_error "Valgrind support requested but headers not available" "$LINENO" 5 + as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 fi @@ -9365,8 +9356,8 @@ $as_echo "MACHDEP_OBJS" >&6; } for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat \ fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \ - futimens futimes \ - gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ + futimens futimes gai_strerror \ + getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ if_nameindex \ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ @@ -9384,8 +9375,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -10408,8 +10398,7 @@ for ac_func in fseek64 fseeko fstatvfs ftell64 ftello statvfs do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -10418,25 +10407,44 @@ fi done -for ac_func in dup2 getcwd strdup -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" +if test "x$ac_cv_func_dup2" = x""yes; then : + $as_echo "#define HAVE_DUP2 1" >>confdefs.h else case " $LIBOBJS " in - *" $ac_func.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" + *" dup2.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dup2.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" +if test "x$ac_cv_func_getcwd" = x""yes; then : + $as_echo "#define HAVE_GETCWD 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" getcwd.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS getcwd.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" +if test "x$ac_cv_func_strdup" = x""yes; then : + $as_echo "#define HAVE_STRDUP 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" strdup.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strdup.$ac_objext" ;; esac fi -done for ac_func in getpgrp @@ -11649,7 +11657,7 @@ elif test "$withval" != yes then LIBM=$withval { $as_echo "$as_me:${as_lineno-$LINENO}: result: set LIBM=\"$withval\"" >&5 $as_echo "set LIBM=\"$withval\"" >&6; } -else as_fn_error "proper usage is --with-libm=STRING" "$LINENO" 5 +else as_fn_error $? "proper usage is --with-libm=STRING" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 @@ -11673,7 +11681,7 @@ elif test "$withval" != yes then LIBC=$withval { $as_echo "$as_me:${as_lineno-$LINENO}: result: set LIBC=\"$withval\"" >&5 $as_echo "set LIBC=\"$withval\"" >&6; } -else as_fn_error "proper usage is --with-libc=STRING" "$LINENO" 5 +else as_fn_error $? "proper usage is --with-libc=STRING" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 @@ -11923,8 +11931,7 @@ for ac_func in acosh asinh atanh copysign erf erfc expm1 finite gamma do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -11936,8 +11943,7 @@ for ac_func in hypot lgamma log1p log2 round tgamma do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -12200,7 +12206,7 @@ no) 15|30) ;; *) - as_fn_error "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; + as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_big_digits" >&5 $as_echo "$enable_big_digits" >&6; } @@ -12251,9 +12257,8 @@ else if test "$ac_cv_type_wchar_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (wchar_t) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (wchar_t) +See \`config.log' for more details" "$LINENO" 5 ; } else ac_cv_sizeof_wchar_t=0 fi @@ -12622,8 +12627,8 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) - as_fn_error "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac @@ -12884,7 +12889,7 @@ else have_readline=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13058,7 +13063,7 @@ else have_readline=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13980,6 +13985,7 @@ DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' @@ -14142,19 +14148,19 @@ export LANGUAGE (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. +# script with STATUS, using 1 if that was 0. as_fn_error () { - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -14350,7 +14356,7 @@ $as_echo X"$as_dir" | test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p @@ -14404,7 +14410,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by python $as_me 3.3, which was -generated by GNU Autoconf 2.65. Invocation command line was +generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14466,10 +14472,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 3.3 -configured by $0, generated by GNU Autoconf 2.65, +configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -14485,11 +14491,16 @@ ac_need_defaults=: while test $# != 0 do case $1 in - --*=*) + --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; *) ac_option=$1 ac_optarg=$2 @@ -14511,6 +14522,7 @@ do $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; @@ -14523,7 +14535,7 @@ do ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - as_fn_error "ambiguous option: \`$1' + as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; @@ -14532,7 +14544,7 @@ Try \`$0 --help' for more information.";; ac_cs_silent=: ;; # This is an error. - -*) as_fn_error "unrecognized option: \`$1' + -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" @@ -14591,7 +14603,7 @@ do "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Modules/ld_so_aix") CONFIG_FILES="$CONFIG_FILES Modules/ld_so_aix" ;; - *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done @@ -14628,7 +14640,7 @@ $debug || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -14645,7 +14657,7 @@ if test "x$ac_cr" = x; then fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\r' + ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi @@ -14659,18 +14671,18 @@ _ACEOF echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14759,20 +14771,28 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || as_fn_error "could not setup config files machinery" "$LINENO" 5 + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// s/^[^=]*=[ ]*$// }' fi @@ -14800,7 +14820,7 @@ for ac_last_try in false false :; do if test -z "$ac_t"; then break elif $ac_last_try; then - as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14885,7 +14905,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error "could not setup config headers machinery" "$LINENO" 5 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" @@ -14898,7 +14918,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -14926,7 +14946,7 @@ do [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" @@ -14953,7 +14973,7 @@ $as_echo "$as_me: creating $ac_file" >&6;} case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -15084,22 +15104,22 @@ s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&5 +which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&2;} +which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # @@ -15110,19 +15130,19 @@ which seems to be undefined. Please make sure it is defined." >&2;} $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error "could not create -" "$LINENO" 5 + || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; @@ -15142,7 +15162,7 @@ _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || - as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. @@ -15163,7 +15183,7 @@ if test "$no_create" != yes; then exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit $? + $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 diff --git a/configure.in b/configure.in index 274c68d..e0b2ecb 100644 --- a/configure.in +++ b/configure.in @@ -2541,8 +2541,8 @@ AC_MSG_RESULT(MACHDEP_OBJS) AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat \ fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \ - futimens futimes \ - gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ + futimens futimes gai_strerror \ + getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \ getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ if_nameindex \ initgroups kill killpg lchmod lchown lockf linkat lstat lutimes mbrtowc mkdirat mkfifo \ diff --git a/pyconfig.h.in b/pyconfig.h.in index 6c45460..4935077 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -305,6 +305,9 @@ /* Define this if you have flockfile(), getc_unlocked(), and funlockfile() */ #undef HAVE_GETC_UNLOCKED +/* Define to 1 if you have the `getgrouplist' function. */ +#undef HAVE_GETGROUPLIST + /* Define to 1 if you have the `getgroups' function. */ #undef HAVE_GETGROUPS @@ -1045,10 +1045,15 @@ class PyBuildExt(build_ext): else: sqlite_extra_link_args = () + include_dirs = ["Modules/_sqlite"] + # Only include the directory where sqlite was found if it does + # not already exist in set include directories, otherwise you + # can end up with a bad search path order. + if sqlite_incdir not in self.compiler.include_dirs: + include_dirs.append(sqlite_incdir) exts.append(Extension('_sqlite3', sqlite_srcs, define_macros=sqlite_defines, - include_dirs=["Modules/_sqlite", - sqlite_incdir], + include_dirs=include_dirs, library_dirs=sqlite_libdir, runtime_library_dirs=sqlite_libdir, extra_link_args=sqlite_extra_link_args, @@ -1775,6 +1780,13 @@ class PyBuildInstall(install): install.initialize_options(self) self.warn_dir=0 + # Customize subcommands to not install an egg-info file for Python + sub_commands = [('install_lib', install.has_lib), + ('install_headers', install.has_headers), + ('install_scripts', install.has_scripts), + ('install_data', install.has_data)] + + class PyBuildInstallLib(install_lib): # Do exactly what install_lib does but make sure correct access modes get # set on installed directories and files. All installed files with get |