mirror of https://github.com/python/cpython
Issue #23731: Implement PEP 488.
The concept of .pyo files no longer exists. Now .pyc files have an optional `opt-` tag which specifies if any extra optimizations beyond the peepholer were applied.
This commit is contained in:
parent
a63cc21234
commit
f299abdafa
|
@ -183,9 +183,9 @@ Importing Modules
|
|||
|
||||
.. c:function:: long PyImport_GetMagicNumber()
|
||||
|
||||
Return the magic number for Python bytecode files (a.k.a. :file:`.pyc` and
|
||||
:file:`.pyo` files). The magic number should be present in the first four bytes
|
||||
of the bytecode file, in little-endian byte order. Returns -1 on error.
|
||||
Return the magic number for Python bytecode files (a.k.a. :file:`.pyc` file).
|
||||
The magic number should be present in the first four bytes of the bytecode
|
||||
file, in little-endian byte order. Returns -1 on error.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Return value of -1 upon failure.
|
||||
|
|
|
@ -1193,12 +1193,12 @@ other utility module.
|
|||
|
||||
.. function:: byte_compile(py_files[, optimize=0, force=0, prefix=None, base_dir=None, verbose=1, dry_run=0, direct=None])
|
||||
|
||||
Byte-compile a collection of Python source files to either :file:`.pyc` or
|
||||
:file:`.pyo` files in a :file:`__pycache__` subdirectory (see :pep:`3147`).
|
||||
Byte-compile a collection of Python source files to :file:`.pyc` files in a
|
||||
:file:`__pycache__` subdirectory (see :pep:`3147` and :pep:`488`).
|
||||
*py_files* is a list of files to compile; any files that don't end in
|
||||
:file:`.py` are silently skipped. *optimize* must be one of the following:
|
||||
|
||||
* ``0`` - don't optimize (generate :file:`.pyc`)
|
||||
* ``0`` - don't optimize
|
||||
* ``1`` - normal optimization (like ``python -O``)
|
||||
* ``2`` - extra optimization (like ``python -OO``)
|
||||
|
||||
|
@ -1222,10 +1222,13 @@ other utility module.
|
|||
doing, leave it set to ``None``.
|
||||
|
||||
.. versionchanged:: 3.2.3
|
||||
Create ``.pyc`` or ``.pyo`` files with an :func:`import magic tag
|
||||
Create ``.pyc`` files with an :func:`import magic tag
|
||||
<imp.get_tag>` in their name, in a :file:`__pycache__` subdirectory
|
||||
instead of files without tag in the current directory.
|
||||
|
||||
.. versionchanged: 3.5
|
||||
Create ``.pyc`` files according to :pep:`488`.
|
||||
|
||||
|
||||
.. function:: rfc822_escape(header)
|
||||
|
||||
|
|
|
@ -156,8 +156,8 @@ module
|
|||
|
||||
pure Python module
|
||||
a module written in Python and contained in a single :file:`.py` file (and
|
||||
possibly associated :file:`.pyc` and/or :file:`.pyo` files). Sometimes referred
|
||||
to as a "pure module."
|
||||
possibly associated :file:`.pyc` files). Sometimes referred to as a
|
||||
"pure module."
|
||||
|
||||
extension module
|
||||
a module written in the low-level language of the Python implementation: C/C++
|
||||
|
@ -210,5 +210,3 @@ distribution root
|
|||
the top-level directory of your source tree (or source distribution); the
|
||||
directory where :file:`setup.py` exists. Generally :file:`setup.py` will be
|
||||
run from this directory.
|
||||
|
||||
|
||||
|
|
|
@ -93,6 +93,10 @@ compile Python sources.
|
|||
.. versionchanged:: 3.5
|
||||
``-q`` option was changed to a multilevel value.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
``-b`` will always produce a byte-code file ending in ``.pyc``, never
|
||||
``.pyo``.
|
||||
|
||||
|
||||
There is no command-line option to control the optimization level used by the
|
||||
:func:`compile` function, because the Python interpreter itself already
|
||||
|
@ -150,6 +154,10 @@ Public functions
|
|||
.. versionchanged:: 3.5
|
||||
*quiet* parameter was changed to a multilevel value.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
The *legacy* parameter only writes out ``.pyc`` files, not ``.pyo`` files
|
||||
no matter what the value of *optimize* is.
|
||||
|
||||
.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1)
|
||||
|
||||
Compile the file with path *fullname*.
|
||||
|
@ -182,6 +190,10 @@ Public functions
|
|||
.. versionchanged:: 3.5
|
||||
*quiet* parameter was changed to a multilevel value.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
The *legacy* parameter only writes out ``.pyc`` files, not ``.pyo`` files
|
||||
no matter what the value of *optimize* is.
|
||||
|
||||
.. function:: compile_path(skip_curdir=True, maxlevels=0, force=False, quiet=0, legacy=False, optimize=-1)
|
||||
|
||||
Byte-compile all the :file:`.py` files found along ``sys.path``. If
|
||||
|
@ -196,6 +208,10 @@ Public functions
|
|||
.. versionchanged:: 3.5
|
||||
*quiet* parameter was changed to a multilevel value.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
The *legacy* parameter only writes out ``.pyc`` files, not ``.pyo`` files
|
||||
no matter what the value of *optimize* is.
|
||||
|
||||
To force a recompile of all the :file:`.py` files in the :file:`Lib/`
|
||||
subdirectory and all its subdirectories::
|
||||
|
||||
|
|
|
@ -203,11 +203,9 @@ file paths.
|
|||
value would be ``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2.
|
||||
The ``cpython-32`` string comes from the current magic tag (see
|
||||
:func:`get_tag`; if :attr:`sys.implementation.cache_tag` is not defined then
|
||||
:exc:`NotImplementedError` will be raised). The returned path will end in
|
||||
``.pyc`` when ``__debug__`` is ``True`` or ``.pyo`` for an optimized Python
|
||||
(i.e. ``__debug__`` is ``False``). By passing in ``True`` or ``False`` for
|
||||
*debug_override* you can override the system's value for ``__debug__`` for
|
||||
extension selection.
|
||||
:exc:`NotImplementedError` will be raised). By passing in ``True`` or
|
||||
``False`` for *debug_override* you can override the system's value for
|
||||
``__debug__``, leading to optimized bytecode.
|
||||
|
||||
*path* need not exist.
|
||||
|
||||
|
@ -218,6 +216,9 @@ file paths.
|
|||
.. deprecated:: 3.4
|
||||
Use :func:`importlib.util.cache_from_source` instead.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
The *debug_override* parameter no longer creates a ``.pyo`` file.
|
||||
|
||||
|
||||
.. function:: source_from_cache(path)
|
||||
|
||||
|
|
|
@ -711,6 +711,9 @@ find and load modules.
|
|||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. deprecated:: 3.5
|
||||
Use :attr:`BYTECODE_SUFFIXES` instead.
|
||||
|
||||
.. attribute:: OPTIMIZED_BYTECODE_SUFFIXES
|
||||
|
||||
A list of strings representing the file suffixes for optimized bytecode
|
||||
|
@ -718,14 +721,19 @@ find and load modules.
|
|||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. deprecated:: 3.5
|
||||
Use :attr:`BYTECODE_SUFFIXES` instead.
|
||||
|
||||
.. attribute:: BYTECODE_SUFFIXES
|
||||
|
||||
A list of strings representing the recognized file suffixes for bytecode
|
||||
modules. Set to either :attr:`DEBUG_BYTECODE_SUFFIXES` or
|
||||
:attr:`OPTIMIZED_BYTECODE_SUFFIXES` based on whether ``__debug__`` is true.
|
||||
modules (including the leading dot).
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
The value is no longer dependent on ``__debug__``.
|
||||
|
||||
.. attribute:: EXTENSION_SUFFIXES
|
||||
|
||||
A list of strings representing the recognized file suffixes for
|
||||
|
@ -1074,23 +1082,37 @@ an :term:`importer`.
|
|||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. function:: cache_from_source(path, debug_override=None)
|
||||
.. function:: cache_from_source(path, debug_override=None, *, optimization=None)
|
||||
|
||||
Return the :pep:`3147` path to the byte-compiled file associated with the
|
||||
source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return
|
||||
Return the :pep:`3147`/:pep:`488` path to the byte-compiled file associated
|
||||
with the source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return
|
||||
value would be ``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2.
|
||||
The ``cpython-32`` string comes from the current magic tag (see
|
||||
:func:`get_tag`; if :attr:`sys.implementation.cache_tag` is not defined then
|
||||
:exc:`NotImplementedError` will be raised). The returned path will end in
|
||||
``.pyc`` when ``__debug__`` is ``True`` or ``.pyo`` for an optimized Python
|
||||
(i.e. ``__debug__`` is ``False``). By passing in ``True`` or ``False`` for
|
||||
*debug_override* you can override the system's value for ``__debug__`` for
|
||||
extension selection.
|
||||
:exc:`NotImplementedError` will be raised).
|
||||
|
||||
*path* need not exist.
|
||||
The *optimization* parameter is used to specify the optimization level of the
|
||||
bytecode file. An empty string represents no optimization, so
|
||||
``/foo/bar/baz.py`` with an *optimization* of ``''`` will result in a
|
||||
bytecode path of ``/foo/bar/__pycache__/baz.cpython-32.pyc``. ``None`` causes
|
||||
the interpter's optimization level to be used. Any other value's string
|
||||
representation being used, so ``/foo/bar/baz.py`` with an *optimization* of
|
||||
``2`` will lead to the bytecode path of
|
||||
``/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc``. The string representation
|
||||
of *optimization* can only be alphanumeric, else :exc:`ValueError` is raised.
|
||||
|
||||
The *debug_override* parameter is deprecated and can be used to override
|
||||
the system's value for ``__debug__``. A ``True`` value is the equivalent of
|
||||
setting *optimization* to the empty string. A ``False`` value is the same as
|
||||
setting *optimization* to ``1``. If both *debug_override* an *optimization*
|
||||
are not ``None`` then :exc:`TypeError` is raised.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. versionchanged ::3.5
|
||||
The *optimization* parameter was added and the *debug_override* parameter
|
||||
was deprecated.
|
||||
|
||||
|
||||
.. function:: source_from_cache(path)
|
||||
|
||||
|
@ -1098,7 +1120,7 @@ an :term:`importer`.
|
|||
file path. For example, if *path* is
|
||||
``/foo/bar/__pycache__/baz.cpython-32.pyc`` the returned path would be
|
||||
``/foo/bar/baz.py``. *path* need not exist, however if it does not conform
|
||||
to :pep:`3147` format, a ``ValueError`` is raised. If
|
||||
to :pep:`3147` or :pep`488` format, a ``ValueError`` is raised. If
|
||||
:attr:`sys.implementation.cache_tag` is not defined,
|
||||
:exc:`NotImplementedError` is raised.
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ byte-code cache files in the directory containing the source code.
|
|||
.. function:: compile(file, cfile=None, dfile=None, doraise=False, optimize=-1)
|
||||
|
||||
Compile a source file to byte-code and write out the byte-code cache file.
|
||||
The source code is loaded from the file name *file*. The byte-code is
|
||||
written to *cfile*, which defaults to the :PEP:`3147` path, ending in
|
||||
``.pyc`` (``.pyo`` if optimization is enabled in the current interpreter).
|
||||
The source code is loaded from the file name *file*. The byte-code is
|
||||
written to *cfile*, which defaults to the :pep:`3147`/:pep`488` path, ending
|
||||
in ``.pyc``.
|
||||
For example, if *file* is ``/foo/bar/baz.py`` *cfile* will default to
|
||||
``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2. If *dfile* is
|
||||
specified, it is used as the name of the source file in error messages when
|
||||
|
@ -68,7 +68,7 @@ byte-code cache files in the directory containing the source code.
|
|||
.. function:: main(args=None)
|
||||
|
||||
Compile several source files. The files named in *args* (or on the command
|
||||
line, if *args* is ``None``) are compiled and the resulting bytecode is
|
||||
line, if *args* is ``None``) are compiled and the resulting byte-code is
|
||||
cached in the normal manner. This function does not search a directory
|
||||
structure to locate source files; it only compiles files named explicitly.
|
||||
If ``'-'`` is the only parameter in args, the list of files is taken from
|
||||
|
@ -86,4 +86,3 @@ could not be compiled.
|
|||
|
||||
Module :mod:`compileall`
|
||||
Utilities to compile all Python source files in a directory tree.
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ always available.
|
|||
|
||||
.. data:: dont_write_bytecode
|
||||
|
||||
If this is true, Python won't try to write ``.pyc`` or ``.pyo`` files on the
|
||||
If this is true, Python won't try to write ``.pyc`` files on the
|
||||
import of source modules. This value is initially set to ``True`` or
|
||||
``False`` depending on the :option:`-B` command line option and the
|
||||
:envvar:`PYTHONDONTWRITEBYTECODE` environment variable, but you can set it
|
||||
|
@ -1231,4 +1231,3 @@ always available.
|
|||
.. rubric:: Citations
|
||||
|
||||
.. [C99] ISO/IEC 9899:1999. "Programming languages -- C." A public draft of this standard is available at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf\ .
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ Filter
|
|||
Filter on traces of memory blocks.
|
||||
|
||||
See the :func:`fnmatch.fnmatch` function for the syntax of
|
||||
*filename_pattern*. The ``'.pyc'`` and ``'.pyo'`` file extensions are
|
||||
*filename_pattern*. The ``'.pyc'`` file extension is
|
||||
replaced with ``'.py'``.
|
||||
|
||||
Examples:
|
||||
|
@ -374,6 +374,10 @@ Filter
|
|||
:mod:`tracemalloc` module
|
||||
* ``Filter(False, "<unknown>")`` excludes empty tracebacks
|
||||
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
The ``'.pyo'`` file extension is no longer replaced with ``'.py'``.
|
||||
|
||||
.. attribute:: inclusive
|
||||
|
||||
If *inclusive* is ``True`` (include), only trace memory blocks allocated
|
||||
|
@ -631,4 +635,3 @@ Traceback
|
|||
obj = Object()
|
||||
File "test.py", line 12
|
||||
tb = tracemalloc.get_object_traceback(f())
|
||||
|
||||
|
|
|
@ -405,8 +405,7 @@ The :class:`PyZipFile` constructor takes the same parameters as the
|
|||
archive.
|
||||
|
||||
If the *optimize* parameter to :class:`PyZipFile` was not given or ``-1``,
|
||||
the corresponding file is a :file:`\*.pyo` file if available, else a
|
||||
:file:`\*.pyc` file, compiling if necessary.
|
||||
the corresponding file is a :file:`\*.pyc` file, compiling if necessary.
|
||||
|
||||
If the *optimize* parameter to :class:`PyZipFile` was ``0``, ``1`` or
|
||||
``2``, only files with that optimization level (see :func:`compile`) are
|
||||
|
@ -569,4 +568,3 @@ Instances have the following attributes:
|
|||
.. attribute:: ZipInfo.file_size
|
||||
|
||||
Size of the uncompressed file.
|
||||
|
||||
|
|
|
@ -20,10 +20,10 @@ subdirectory. For example, the path :file:`example.zip/lib/` would only
|
|||
import from the :file:`lib/` subdirectory within the archive.
|
||||
|
||||
Any files may be present in the ZIP archive, but only files :file:`.py` and
|
||||
:file:`.py[co]` are available for import. ZIP import of dynamic modules
|
||||
:file:`.pyc` are available for import. ZIP import of dynamic modules
|
||||
(:file:`.pyd`, :file:`.so`) is disallowed. Note that if an archive only contains
|
||||
:file:`.py` files, Python will not attempt to modify the archive by adding the
|
||||
corresponding :file:`.pyc` or :file:`.pyo` file, meaning that if a ZIP archive
|
||||
corresponding :file:`.pyc` file, meaning that if a ZIP archive
|
||||
doesn't contain :file:`.pyc` files, importing may be rather slow.
|
||||
|
||||
ZIP archives with an archive comment are currently not supported.
|
||||
|
@ -161,4 +161,3 @@ Here is an example that imports a module from a ZIP archive - note that the
|
|||
>>> import jwzthreading
|
||||
>>> jwzthreading.__file__
|
||||
'example.zip/jwzthreading.py'
|
||||
|
||||
|
|
|
@ -646,7 +646,7 @@ path entry finder that knows how to handle that particular kind of path.
|
|||
|
||||
The default set of path entry finders implement all the semantics for finding
|
||||
modules on the file system, handling special file types such as Python source
|
||||
code (``.py`` files), Python byte code (``.pyc`` and ``.pyo`` files) and
|
||||
code (``.py`` files), Python byte code (``.pyc`` files) and
|
||||
shared libraries (e.g. ``.so`` files). When supported by the :mod:`zipimport`
|
||||
module in the standard library, the default path entry finders also handle
|
||||
loading all of these file types (other than shared libraries) from zipfiles.
|
||||
|
|
|
@ -216,15 +216,15 @@ Some tips for experts:
|
|||
statements, the ``-OO`` switch removes both assert statements and __doc__
|
||||
strings. Since some programs may rely on having these available, you should
|
||||
only use this option if you know what you're doing. "Optimized" modules have
|
||||
a .pyo rather than a .pyc suffix and are usually smaller. Future releases may
|
||||
an ``opt-`` tag and are usually smaller. Future releases may
|
||||
change the effects of optimization.
|
||||
|
||||
* A program doesn't run any faster when it is read from a ``.pyc`` or ``.pyo``
|
||||
* A program doesn't run any faster when it is read from a ``.pyc``
|
||||
file than when it is read from a ``.py`` file; the only thing that's faster
|
||||
about ``.pyc`` or ``.pyo`` files is the speed with which they are loaded.
|
||||
about ``.pyc`` files is the speed with which they are loaded.
|
||||
|
||||
* The module :mod:`compileall` can create .pyc files (or .pyo files when
|
||||
:option:`-O` is used) for all modules in a directory.
|
||||
* The module :mod:`compileall` can create .pyc files for all modules in a
|
||||
directory.
|
||||
|
||||
* There is more detail on this process, including a flow chart of the
|
||||
decisions, in PEP 3147.
|
||||
|
@ -548,4 +548,3 @@ modules found in a package.
|
|||
.. [#] In fact function definitions are also 'statements' that are 'executed'; the
|
||||
execution of a module-level function definition enters the function name in
|
||||
the module's global symbol table.
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ Miscellaneous options
|
|||
|
||||
.. cmdoption:: -B
|
||||
|
||||
If given, Python won't try to write ``.pyc`` or ``.pyo`` files on the
|
||||
If given, Python won't try to write ``.pyc``` files on the
|
||||
import of source modules. See also :envvar:`PYTHONDONTWRITEBYTECODE`.
|
||||
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ of available options is shown below.
|
|||
| | launcher is also installed. | |
|
||||
+---------------------------+--------------------------------------+--------------------------+
|
||||
| CompileAll | Compile all ``.py`` files to | 0 |
|
||||
| | ``.pyc`` and ``.pyo``. | |
|
||||
| | ``.pyc``. | |
|
||||
+---------------------------+--------------------------------------+--------------------------+
|
||||
| PrependPath | Add install and Scripts directories | 0 |
|
||||
| | tho :envvar:`PATH` and ``.PY`` to | |
|
||||
|
@ -451,7 +451,7 @@ From file associations
|
|||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The launcher should have been associated with Python files (i.e. ``.py``,
|
||||
``.pyw``, ``.pyc``, ``.pyo`` files) when it was installed. This means that
|
||||
``.pyw``, ``.pyc`` files) when it was installed. This means that
|
||||
when you double-click on one of these files from Windows explorer the launcher
|
||||
will be used, and therefore you can use the same facilities described above to
|
||||
have the script specify the version which should be used.
|
||||
|
@ -796,5 +796,3 @@ Other resources
|
|||
|
||||
:pep:`397` - Python launcher for Windows
|
||||
The proposal for the launcher to be included in the Python distribution.
|
||||
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ Implementation improvements:
|
|||
``surrogateescape`` error handler, instead of the ``strict`` error handler
|
||||
(:issue:`19977`).
|
||||
|
||||
* :pep:`488`, the elimination of ``.pyo`` files.
|
||||
|
||||
Significantly Improved Library Modules:
|
||||
|
||||
* None yet.
|
||||
|
@ -195,6 +197,24 @@ environment will be used.
|
|||
|
||||
:pep:`486` -- Make the Python Launcher aware of virtual environments
|
||||
|
||||
|
||||
PEP 488: Elimination of PYO files
|
||||
---------------------------------
|
||||
|
||||
:pep:`488` does away with the concept of ``.pyo`` files. This means that
|
||||
``.pyc`` files represent both unoptimized and optimized bytecode. To prevent
|
||||
the need to constantly regenerate bytecode files, ``.pyc`` files now have an
|
||||
optional ``opt-`` tag in their name when the bytecode is optimized. This has
|
||||
the side-effect of no more bytecode file name clashes when running under either
|
||||
``-O`` or ``-OO``, thus allowing unoptimized, ``-O``, and ``-OO`` bytecode files
|
||||
to all exist simultaneously. :func:`importlib.util.cache_from_source` has an
|
||||
updated API to help with this change.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:pep:`488` -- Elimination of PYO files
|
||||
|
||||
|
||||
Other Language Changes
|
||||
======================
|
||||
|
||||
|
@ -535,7 +555,7 @@ The following performance enhancements have been added:
|
|||
``FindFirstFile``/``FindNextFile`` system calls. (Contributed by
|
||||
Ben Hoyt with help from Victor Stinner in :issue:`23605`.)
|
||||
|
||||
* Construction of ``bytes(int)`` (filled by zero bytes) is faster and use less
|
||||
* Construction of ``bytes(int)`` (filled by zero bytes) is faster and uses less
|
||||
memory for large objects. ``calloc()`` is used instead of ``malloc()`` to
|
||||
allocate memory for these objects.
|
||||
|
||||
|
@ -630,6 +650,8 @@ removed:
|
|||
3.4, and has now been removed.
|
||||
(Contributed by Matt Chaput in :issue:`6623`.)
|
||||
|
||||
* The concept of ``.pyo`` files has been removed.
|
||||
|
||||
* The JoinableQueue class in the provisional asyncio module was deprecated
|
||||
in 3.4.4 and is now removed (:issue:`23464`).
|
||||
|
||||
|
@ -759,6 +781,17 @@ Changes in the Python API
|
|||
*LegalChars* parameter of :func:`~http.cookies.Morsel.set` is deprecated and
|
||||
is now ignored. (:issue:`2211`)
|
||||
|
||||
* :pep:`488` has removed ``.pyo`` files from Python and introduced the optional
|
||||
``opt-`` tag in ``.pyc`` file names. The
|
||||
:func:`importlib.util.cache_from_source` has gained an *optimization*
|
||||
parameter to help control the ``opt-`` tag. Because of this, the
|
||||
*debug_override* parameter of the function is now deprecated. `.pyo` files
|
||||
are also no longer supported as a file argument to the Python interpreter and
|
||||
thus serve no purpose when distributed on their own (i.e. sourcless code
|
||||
distribution). Due to the fact that the magic number for bytecode has changed
|
||||
in Python 3.5, all old `.pyo` files from previous versions of Python are
|
||||
invalid regardless of this PEP.
|
||||
|
||||
Changes in the C API
|
||||
--------------------
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""Module/script to byte-compile all .py files to .pyc (or .pyo) files.
|
||||
"""Module/script to byte-compile all .py files to .pyc files.
|
||||
|
||||
When called as a script with arguments, this compiles the directories
|
||||
given as arguments recursively; the -l option prevents it from
|
||||
|
@ -118,11 +118,12 @@ def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
|||
return success
|
||||
if os.path.isfile(fullname):
|
||||
if legacy:
|
||||
cfile = fullname + ('c' if __debug__ else 'o')
|
||||
cfile = fullname + 'c'
|
||||
else:
|
||||
if optimize >= 0:
|
||||
opt = optimize if optimize >= 1 else ''
|
||||
cfile = importlib.util.cache_from_source(
|
||||
fullname, debug_override=not optimize)
|
||||
fullname, optimization=opt)
|
||||
else:
|
||||
cfile = importlib.util.cache_from_source(fullname)
|
||||
cache_dir = os.path.dirname(cfile)
|
||||
|
|
|
@ -314,10 +314,10 @@ class build_py (Command):
|
|||
if include_bytecode:
|
||||
if self.compile:
|
||||
outputs.append(importlib.util.cache_from_source(
|
||||
filename, debug_override=True))
|
||||
filename, optimization=''))
|
||||
if self.optimize > 0:
|
||||
outputs.append(importlib.util.cache_from_source(
|
||||
filename, debug_override=False))
|
||||
filename, optimization=self.optimize))
|
||||
|
||||
outputs += [
|
||||
os.path.join(build_dir, filename)
|
||||
|
|
|
@ -22,15 +22,15 @@ class install_lib(Command):
|
|||
# possible scenarios:
|
||||
# 1) no compilation at all (--no-compile --no-optimize)
|
||||
# 2) compile .pyc only (--compile --no-optimize; default)
|
||||
# 3) compile .pyc and "level 1" .pyo (--compile --optimize)
|
||||
# 4) compile "level 1" .pyo only (--no-compile --optimize)
|
||||
# 5) compile .pyc and "level 2" .pyo (--compile --optimize-more)
|
||||
# 6) compile "level 2" .pyo only (--no-compile --optimize-more)
|
||||
# 3) compile .pyc and "opt-1" .pyc (--compile --optimize)
|
||||
# 4) compile "opt-1" .pyc only (--no-compile --optimize)
|
||||
# 5) compile .pyc and "opt-2" .pyc (--compile --optimize-more)
|
||||
# 6) compile "opt-2" .pyc only (--no-compile --optimize-more)
|
||||
#
|
||||
# The UI for this is two option, 'compile' and 'optimize'.
|
||||
# The UI for this is two options, 'compile' and 'optimize'.
|
||||
# 'compile' is strictly boolean, and only decides whether to
|
||||
# generate .pyc files. 'optimize' is three-way (0, 1, or 2), and
|
||||
# decides both whether to generate .pyo files and what level of
|
||||
# decides both whether to generate .pyc files and what level of
|
||||
# optimization to use.
|
||||
|
||||
user_options = [
|
||||
|
@ -166,10 +166,10 @@ class install_lib(Command):
|
|||
continue
|
||||
if self.compile:
|
||||
bytecode_files.append(importlib.util.cache_from_source(
|
||||
py_file, debug_override=True))
|
||||
py_file, optimization=''))
|
||||
if self.optimize > 0:
|
||||
bytecode_files.append(importlib.util.cache_from_source(
|
||||
py_file, debug_override=False))
|
||||
py_file, optimization=self.optimize))
|
||||
|
||||
return bytecode_files
|
||||
|
||||
|
|
|
@ -120,8 +120,8 @@ class BuildPyTestCase(support.TempdirManager,
|
|||
found = os.listdir(cmd.build_lib)
|
||||
self.assertEqual(sorted(found), ['__pycache__', 'boiledeggs.py'])
|
||||
found = os.listdir(os.path.join(cmd.build_lib, '__pycache__'))
|
||||
self.assertEqual(sorted(found),
|
||||
['boiledeggs.%s.pyo' % sys.implementation.cache_tag])
|
||||
expect = 'boiledeggs.{}.opt-1.pyc'.format(sys.implementation.cache_tag)
|
||||
self.assertEqual(sorted(found), [expect])
|
||||
|
||||
def test_dir_in_package_data(self):
|
||||
"""
|
||||
|
|
|
@ -44,12 +44,11 @@ class InstallLibTestCase(support.TempdirManager,
|
|||
f = os.path.join(project_dir, 'foo.py')
|
||||
self.write_file(f, '# python file')
|
||||
cmd.byte_compile([f])
|
||||
pyc_file = importlib.util.cache_from_source('foo.py',
|
||||
debug_override=True)
|
||||
pyo_file = importlib.util.cache_from_source('foo.py',
|
||||
debug_override=False)
|
||||
pyc_file = importlib.util.cache_from_source('foo.py', optimization='')
|
||||
pyc_opt_file = importlib.util.cache_from_source('foo.py',
|
||||
optimization=cmd.optimize)
|
||||
self.assertTrue(os.path.exists(pyc_file))
|
||||
self.assertTrue(os.path.exists(pyo_file))
|
||||
self.assertTrue(os.path.exists(pyc_opt_file))
|
||||
|
||||
def test_get_outputs(self):
|
||||
project_dir, dist = self.create_dist()
|
||||
|
@ -66,8 +65,8 @@ class InstallLibTestCase(support.TempdirManager,
|
|||
cmd.distribution.packages = ['spam']
|
||||
cmd.distribution.script_name = 'setup.py'
|
||||
|
||||
# get_outputs should return 4 elements: spam/__init__.py, .pyc and
|
||||
# .pyo, foo.import-tag-abiflags.so / foo.pyd
|
||||
# get_outputs should return 4 elements: spam/__init__.py and .pyc,
|
||||
# foo.import-tag-abiflags.so / foo.pyd
|
||||
outputs = cmd.get_outputs()
|
||||
self.assertEqual(len(outputs), 4, outputs)
|
||||
|
||||
|
|
|
@ -322,11 +322,11 @@ def byte_compile (py_files,
|
|||
prefix=None, base_dir=None,
|
||||
verbose=1, dry_run=0,
|
||||
direct=None):
|
||||
"""Byte-compile a collection of Python source files to either .pyc
|
||||
or .pyo files in a __pycache__ subdirectory. 'py_files' is a list
|
||||
"""Byte-compile a collection of Python source files to .pyc
|
||||
files in a __pycache__ subdirectory. 'py_files' is a list
|
||||
of files to compile; any files that don't end in ".py" are silently
|
||||
skipped. 'optimize' must be one of the following:
|
||||
0 - don't optimize (generate .pyc)
|
||||
0 - don't optimize
|
||||
1 - normal optimization (like "python -O")
|
||||
2 - extra optimization (like "python -OO")
|
||||
If 'force' is true, all files are recompiled regardless of
|
||||
|
@ -438,8 +438,9 @@ byte_compile(files, optimize=%r, force=%r,
|
|||
# cfile - byte-compiled file
|
||||
# dfile - purported source filename (same as 'file' by default)
|
||||
if optimize >= 0:
|
||||
opt = '' if optimize == 0 else optimize
|
||||
cfile = importlib.util.cache_from_source(
|
||||
file, debug_override=not optimize)
|
||||
file, optimization=opt)
|
||||
else:
|
||||
cfile = importlib.util.cache_from_source(file)
|
||||
dfile = file
|
||||
|
|
|
@ -1051,7 +1051,7 @@ class DocTestFinder:
|
|||
filename = None
|
||||
else:
|
||||
filename = getattr(module, '__file__', module.__name__)
|
||||
if filename[-4:] in (".pyc", ".pyo"):
|
||||
if filename[-4:] == ".pyc":
|
||||
filename = filename[:-1]
|
||||
return self._parser.get_doctest(docstring, globs, name,
|
||||
filename, lineno)
|
||||
|
@ -2378,7 +2378,7 @@ def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None,
|
|||
continue
|
||||
if not test.filename:
|
||||
filename = module.__file__
|
||||
if filename[-4:] in (".pyc", ".pyo"):
|
||||
if filename[-4:] == ".pyc":
|
||||
filename = filename[:-1]
|
||||
test.filename = filename
|
||||
suite.addTest(DocTestCase(test, **options))
|
||||
|
|
19
Lib/imp.py
19
Lib/imp.py
|
@ -58,24 +58,23 @@ def new_module(name):
|
|||
def get_magic():
|
||||
"""**DEPRECATED**
|
||||
|
||||
Return the magic number for .pyc or .pyo files.
|
||||
Return the magic number for .pyc files.
|
||||
"""
|
||||
return util.MAGIC_NUMBER
|
||||
|
||||
|
||||
def get_tag():
|
||||
"""Return the magic tag for .pyc or .pyo files."""
|
||||
"""Return the magic tag for .pyc files."""
|
||||
return sys.implementation.cache_tag
|
||||
|
||||
|
||||
def cache_from_source(path, debug_override=None):
|
||||
"""**DEPRECATED**
|
||||
|
||||
Given the path to a .py file, return the path to its .pyc/.pyo file.
|
||||
Given the path to a .py file, return the path to its .pyc file.
|
||||
|
||||
The .py file does not need to exist; this simply returns the path to the
|
||||
.pyc/.pyo file calculated as if the .py file were imported. The extension
|
||||
will be .pyc unless sys.flags.optimize is non-zero, then it will be .pyo.
|
||||
.pyc file calculated as if the .py file were imported.
|
||||
|
||||
If debug_override is not None, then it must be a boolean and is used in
|
||||
place of sys.flags.optimize.
|
||||
|
@ -83,16 +82,18 @@ def cache_from_source(path, debug_override=None):
|
|||
If sys.implementation.cache_tag is None then NotImplementedError is raised.
|
||||
|
||||
"""
|
||||
return util.cache_from_source(path, debug_override)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore')
|
||||
return util.cache_from_source(path, debug_override)
|
||||
|
||||
|
||||
def source_from_cache(path):
|
||||
"""**DEPRECATED**
|
||||
|
||||
Given the path to a .pyc./.pyo file, return the path to its .py file.
|
||||
Given the path to a .pyc. file, return the path to its .py file.
|
||||
|
||||
The .pyc/.pyo file does not need to exist; this simply returns the path to
|
||||
the .py file calculated to correspond to the .pyc/.pyo file. If path does
|
||||
The .pyc file does not need to exist; this simply returns the path to
|
||||
the .py file calculated to correspond to the .pyc file. If path does
|
||||
not conform to PEP 3147 format, ValueError will be raised. If
|
||||
sys.implementation.cache_tag is None then NotImplementedError is raised.
|
||||
|
||||
|
|
|
@ -429,45 +429,64 @@ MAGIC_NUMBER = (3320).to_bytes(2, 'little') + b'\r\n'
|
|||
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
||||
|
||||
_PYCACHE = '__pycache__'
|
||||
_OPT = 'opt-'
|
||||
|
||||
SOURCE_SUFFIXES = ['.py'] # _setup() adds .pyw as needed.
|
||||
|
||||
DEBUG_BYTECODE_SUFFIXES = ['.pyc']
|
||||
OPTIMIZED_BYTECODE_SUFFIXES = ['.pyo']
|
||||
BYTECODE_SUFFIXES = ['.pyc']
|
||||
# Deprecated.
|
||||
DEBUG_BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES = BYTECODE_SUFFIXES
|
||||
|
||||
def cache_from_source(path, debug_override=None):
|
||||
"""Given the path to a .py file, return the path to its .pyc/.pyo file.
|
||||
def cache_from_source(path, debug_override=None, *, optimization=None):
|
||||
"""Given the path to a .py file, return the path to its .pyc file.
|
||||
|
||||
The .py file does not need to exist; this simply returns the path to the
|
||||
.pyc/.pyo file calculated as if the .py file were imported. The extension
|
||||
will be .pyc unless sys.flags.optimize is non-zero, then it will be .pyo.
|
||||
.pyc file calculated as if the .py file were imported.
|
||||
|
||||
If debug_override is not None, then it must be a boolean and is used in
|
||||
place of sys.flags.optimize.
|
||||
The 'optimization' parameter controls the presumed optimization level of
|
||||
the bytecode file. If 'optimization' is not None, the string representation
|
||||
of the argument is taken and verified to be alphanumeric (else ValueError
|
||||
is raised).
|
||||
|
||||
The debug_override parameter is deprecated. If debug_override is not None,
|
||||
a True value is the same as setting 'optimization' to the empty string
|
||||
while a False value is equivalent to setting 'optimization' to '1'.
|
||||
|
||||
If sys.implementation.cache_tag is None then NotImplementedError is raised.
|
||||
|
||||
"""
|
||||
debug = not sys.flags.optimize if debug_override is None else debug_override
|
||||
if debug:
|
||||
suffixes = DEBUG_BYTECODE_SUFFIXES
|
||||
else:
|
||||
suffixes = OPTIMIZED_BYTECODE_SUFFIXES
|
||||
if debug_override is not None:
|
||||
_warnings.warn('the debug_override parameter is deprecated; use '
|
||||
"'optimization' instead", DeprecationWarning)
|
||||
if optimization is not None:
|
||||
message = 'debug_override or optimization must be set to None'
|
||||
raise TypeError(message)
|
||||
optimization = '' if debug_override else 1
|
||||
head, tail = _path_split(path)
|
||||
base, sep, rest = tail.rpartition('.')
|
||||
tag = sys.implementation.cache_tag
|
||||
if tag is None:
|
||||
raise NotImplementedError('sys.implementation.cache_tag is None')
|
||||
filename = ''.join([(base if base else rest), sep, tag, suffixes[0]])
|
||||
return _path_join(head, _PYCACHE, filename)
|
||||
almost_filename = ''.join([(base if base else rest), sep, tag])
|
||||
if optimization is None:
|
||||
if sys.flags.optimize == 0:
|
||||
optimization = ''
|
||||
else:
|
||||
optimization = sys.flags.optimize
|
||||
optimization = str(optimization)
|
||||
if optimization != '':
|
||||
if not optimization.isalnum():
|
||||
raise ValueError('{!r} is not alphanumeric'.format(optimization))
|
||||
almost_filename = '{}.{}{}'.format(almost_filename, _OPT, optimization)
|
||||
return _path_join(head, _PYCACHE, almost_filename + BYTECODE_SUFFIXES[0])
|
||||
|
||||
|
||||
def source_from_cache(path):
|
||||
"""Given the path to a .pyc./.pyo file, return the path to its .py file.
|
||||
"""Given the path to a .pyc. file, return the path to its .py file.
|
||||
|
||||
The .pyc/.pyo file does not need to exist; this simply returns the path to
|
||||
the .py file calculated to correspond to the .pyc/.pyo file. If path does
|
||||
not conform to PEP 3147 format, ValueError will be raised. If
|
||||
The .pyc file does not need to exist; this simply returns the path to
|
||||
the .py file calculated to correspond to the .pyc file. If path does
|
||||
not conform to PEP 3147/488 format, ValueError will be raised. If
|
||||
sys.implementation.cache_tag is None then NotImplementedError is raised.
|
||||
|
||||
"""
|
||||
|
@ -478,9 +497,19 @@ def source_from_cache(path):
|
|||
if pycache != _PYCACHE:
|
||||
raise ValueError('{} not bottom-level directory in '
|
||||
'{!r}'.format(_PYCACHE, path))
|
||||
if pycache_filename.count('.') != 2:
|
||||
raise ValueError('expected only 2 dots in '
|
||||
dot_count = pycache_filename.count('.')
|
||||
if dot_count not in {2, 3}:
|
||||
raise ValueError('expected only 2 or 3 dots in '
|
||||
'{!r}'.format(pycache_filename))
|
||||
elif dot_count == 3:
|
||||
optimization = pycache_filename.rsplit('.', 2)[-2]
|
||||
if not optimization.startswith(_OPT):
|
||||
raise ValueError("optimization portion of filename does not start "
|
||||
"with {!r}".format(_OPT))
|
||||
opt_level = optimization[len(_OPT):]
|
||||
if not opt_level.isalnum():
|
||||
raise ValueError("optimization level {!r} is not an alphanumeric "
|
||||
"value".format(optimization))
|
||||
base_filename = pycache_filename.partition('.')[0]
|
||||
return _path_join(head, base_filename + SOURCE_SUFFIXES[0])
|
||||
|
||||
|
@ -2337,15 +2366,10 @@ def _setup(sys_module, _imp_module):
|
|||
modules, those two modules must be explicitly passed in.
|
||||
|
||||
"""
|
||||
global _imp, sys, BYTECODE_SUFFIXES
|
||||
global _imp, sys
|
||||
_imp = _imp_module
|
||||
sys = sys_module
|
||||
|
||||
if sys.flags.optimize:
|
||||
BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES
|
||||
else:
|
||||
BYTECODE_SUFFIXES = DEBUG_BYTECODE_SUFFIXES
|
||||
|
||||
# Set up the spec for existing builtin/frozen modules.
|
||||
module_type = type(sys)
|
||||
for name, module in sys.modules.items():
|
||||
|
|
|
@ -223,7 +223,7 @@ class ModuleFinder:
|
|||
if not m.__path__:
|
||||
return
|
||||
modules = {}
|
||||
# 'suffixes' used to be a list hardcoded to [".py", ".pyc", ".pyo"].
|
||||
# 'suffixes' used to be a list hardcoded to [".py", ".pyc"].
|
||||
# But we must also collect Python extension modules - although
|
||||
# we cannot separate normal dlls from Python extensions.
|
||||
suffixes = []
|
||||
|
|
|
@ -361,7 +361,7 @@ class Directory:
|
|||
# [(logical, 0, filehash.IntegerData(1),
|
||||
# filehash.IntegerData(2), filehash.IntegerData(3),
|
||||
# filehash.IntegerData(4))])
|
||||
# Automatically remove .pyc/.pyo files on uninstall (2)
|
||||
# Automatically remove .pyc files on uninstall (2)
|
||||
# XXX: adding so many RemoveFile entries makes installer unbelievably
|
||||
# slow. So instead, we have to use wildcard remove entries
|
||||
if file.endswith(".py"):
|
||||
|
@ -382,10 +382,9 @@ class Directory:
|
|||
return files
|
||||
|
||||
def remove_pyc(self):
|
||||
"Remove .pyc/.pyo files on uninstall"
|
||||
"Remove .pyc files on uninstall"
|
||||
add_data(self.db, "RemoveFile",
|
||||
[(self.component+"c", self.component, "*.pyc", self.logical, 2),
|
||||
(self.component+"o", self.component, "*.pyo", self.logical, 2)])
|
||||
[(self.component+"c", self.component, "*.pyc", self.logical, 2)])
|
||||
|
||||
class Binary:
|
||||
def __init__(self, fname):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""Routine to "compile" a .py file to a .pyc (or .pyo) file.
|
||||
"""Routine to "compile" a .py file to a .pyc file.
|
||||
|
||||
This module has intimate knowledge of the format of .pyc files.
|
||||
"""
|
||||
|
@ -67,7 +67,7 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
|
|||
|
||||
:param file: The source file name.
|
||||
:param cfile: The target byte compiled file name. When not given, this
|
||||
defaults to the PEP 3147 location.
|
||||
defaults to the PEP 3147/PEP 488 location.
|
||||
:param dfile: Purported file name, i.e. the file name that shows up in
|
||||
error messages. Defaults to the source file name.
|
||||
:param doraise: Flag indicating whether or not an exception should be
|
||||
|
@ -85,12 +85,12 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
|
|||
Note that it isn't necessary to byte-compile Python modules for
|
||||
execution efficiency -- Python itself byte-compiles a module when
|
||||
it is loaded, and if it can, writes out the bytecode to the
|
||||
corresponding .pyc (or .pyo) file.
|
||||
corresponding .pyc file.
|
||||
|
||||
However, if a Python installation is shared between users, it is a
|
||||
good idea to byte-compile all modules upon installation, since
|
||||
other users may not be able to write in the source directories,
|
||||
and thus they won't be able to write the .pyc/.pyo file, and then
|
||||
and thus they won't be able to write the .pyc file, and then
|
||||
they would be byte-compiling every module each time it is loaded.
|
||||
This can slow down program start-up considerably.
|
||||
|
||||
|
@ -105,8 +105,9 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
|
|||
"""
|
||||
if cfile is None:
|
||||
if optimize >= 0:
|
||||
optimization = optimize if optimize >= 1 else ''
|
||||
cfile = importlib.util.cache_from_source(file,
|
||||
debug_override=not optimize)
|
||||
optimization=optimization)
|
||||
else:
|
||||
cfile = importlib.util.cache_from_source(file)
|
||||
if os.path.islink(cfile):
|
||||
|
|
|
@ -213,7 +213,7 @@ def classify_class_attrs(object):
|
|||
def ispackage(path):
|
||||
"""Guess whether a path refers to a package directory."""
|
||||
if os.path.isdir(path):
|
||||
for ext in ('.py', '.pyc', '.pyo'):
|
||||
for ext in ('.py', '.pyc'):
|
||||
if os.path.isfile(os.path.join(path, '__init__' + ext)):
|
||||
return True
|
||||
return False
|
||||
|
|
|
@ -376,36 +376,32 @@ def rmtree(path):
|
|||
pass
|
||||
|
||||
def make_legacy_pyc(source):
|
||||
"""Move a PEP 3147 pyc/pyo file to its legacy pyc/pyo location.
|
||||
|
||||
The choice of .pyc or .pyo extension is done based on the __debug__ flag
|
||||
value.
|
||||
"""Move a PEP 3147/488 pyc file to its legacy pyc location.
|
||||
|
||||
:param source: The file system path to the source file. The source file
|
||||
does not need to exist, however the PEP 3147 pyc file must exist.
|
||||
does not need to exist, however the PEP 3147/488 pyc file must exist.
|
||||
:return: The file system path to the legacy pyc file.
|
||||
"""
|
||||
pyc_file = importlib.util.cache_from_source(source)
|
||||
up_one = os.path.dirname(os.path.abspath(source))
|
||||
legacy_pyc = os.path.join(up_one, source + ('c' if __debug__ else 'o'))
|
||||
legacy_pyc = os.path.join(up_one, source + 'c')
|
||||
os.rename(pyc_file, legacy_pyc)
|
||||
return legacy_pyc
|
||||
|
||||
def forget(modname):
|
||||
"""'Forget' a module was ever imported.
|
||||
|
||||
This removes the module from sys.modules and deletes any PEP 3147 or
|
||||
legacy .pyc and .pyo files.
|
||||
This removes the module from sys.modules and deletes any PEP 3147/488 or
|
||||
legacy .pyc files.
|
||||
"""
|
||||
unload(modname)
|
||||
for dirname in sys.path:
|
||||
source = os.path.join(dirname, modname + '.py')
|
||||
# It doesn't matter if they exist or not, unlink all possible
|
||||
# combinations of PEP 3147 and legacy pyc and pyo files.
|
||||
# combinations of PEP 3147/488 and legacy pyc files.
|
||||
unlink(source + 'c')
|
||||
unlink(source + 'o')
|
||||
unlink(importlib.util.cache_from_source(source, debug_override=True))
|
||||
unlink(importlib.util.cache_from_source(source, debug_override=False))
|
||||
for opt in ('', 1, 2):
|
||||
unlink(importlib.util.cache_from_source(source, optimization=opt))
|
||||
|
||||
# Check whether a gui is actually available
|
||||
def _is_gui_available():
|
||||
|
|
|
@ -425,7 +425,7 @@ if 1:
|
|||
|
||||
def test_compile_ast(self):
|
||||
fname = __file__
|
||||
if fname.lower().endswith(('pyc', 'pyo')):
|
||||
if fname.lower().endswith('pyc'):
|
||||
fname = fname[:-1]
|
||||
with open(fname, 'r') as f:
|
||||
fcontents = f.read()
|
||||
|
|
|
@ -101,16 +101,16 @@ class CompileallTests(unittest.TestCase):
|
|||
def test_optimize(self):
|
||||
# make sure compiling with different optimization settings than the
|
||||
# interpreter's creates the correct file names
|
||||
optimize = 1 if __debug__ else 0
|
||||
optimize, opt = (1, 1) if __debug__ else (0, '')
|
||||
compileall.compile_dir(self.directory, quiet=True, optimize=optimize)
|
||||
cached = importlib.util.cache_from_source(self.source_path,
|
||||
debug_override=not optimize)
|
||||
optimization=opt)
|
||||
self.assertTrue(os.path.isfile(cached))
|
||||
cached2 = importlib.util.cache_from_source(self.source_path2,
|
||||
debug_override=not optimize)
|
||||
optimization=opt)
|
||||
self.assertTrue(os.path.isfile(cached2))
|
||||
cached3 = importlib.util.cache_from_source(self.source_path3,
|
||||
debug_override=not optimize)
|
||||
optimization=opt)
|
||||
self.assertTrue(os.path.isfile(cached3))
|
||||
|
||||
@mock.patch('compileall.ProcessPoolExecutor')
|
||||
|
@ -237,11 +237,11 @@ class CommandLineTests(unittest.TestCase):
|
|||
self.assertNotIn(b'Listing ', quiet)
|
||||
|
||||
# Ensure that the default behavior of compileall's CLI is to create
|
||||
# PEP 3147 pyc/pyo files.
|
||||
# PEP 3147/PEP 488 pyc files.
|
||||
for name, ext, switch in [
|
||||
('normal', 'pyc', []),
|
||||
('optimize', 'pyo', ['-O']),
|
||||
('doubleoptimize', 'pyo', ['-OO']),
|
||||
('optimize', 'opt-1.pyc', ['-O']),
|
||||
('doubleoptimize', 'opt-2.pyc', ['-OO']),
|
||||
]:
|
||||
def f(self, ext=ext, switch=switch):
|
||||
script_helper.assert_python_ok(*(switch +
|
||||
|
@ -258,13 +258,12 @@ class CommandLineTests(unittest.TestCase):
|
|||
|
||||
def test_legacy_paths(self):
|
||||
# Ensure that with the proper switch, compileall leaves legacy
|
||||
# pyc/pyo files, and no __pycache__ directory.
|
||||
# pyc files, and no __pycache__ directory.
|
||||
self.assertRunOK('-b', '-q', self.pkgdir)
|
||||
# Verify the __pycache__ directory contents.
|
||||
self.assertFalse(os.path.exists(self.pkgdir_cachedir))
|
||||
opt = 'c' if __debug__ else 'o'
|
||||
expected = sorted(['__init__.py', '__init__.py' + opt, 'bar.py',
|
||||
'bar.py' + opt])
|
||||
expected = sorted(['__init__.py', '__init__.pyc', 'bar.py',
|
||||
'bar.pyc'])
|
||||
self.assertEqual(sorted(os.listdir(self.pkgdir)), expected)
|
||||
|
||||
def test_multiple_runs(self):
|
||||
|
|
|
@ -111,7 +111,6 @@ class ImportTests(unittest.TestCase):
|
|||
del sys.path[0]
|
||||
support.unlink(temp_mod_name + '.py')
|
||||
support.unlink(temp_mod_name + '.pyc')
|
||||
support.unlink(temp_mod_name + '.pyo')
|
||||
|
||||
def test_issue5604(self):
|
||||
# Test cannot cover imp.load_compiled function.
|
||||
|
@ -194,7 +193,7 @@ class ImportTests(unittest.TestCase):
|
|||
self.assertEqual(package.b, 2)
|
||||
finally:
|
||||
del sys.path[0]
|
||||
for ext in ('.py', '.pyc', '.pyo'):
|
||||
for ext in ('.py', '.pyc'):
|
||||
support.unlink(temp_mod_name + ext)
|
||||
support.unlink(init_file_name + ext)
|
||||
support.rmtree(test_package_name)
|
||||
|
@ -346,56 +345,6 @@ class PEP3147Tests(unittest.TestCase):
|
|||
'qux.{}.pyc'.format(self.tag))
|
||||
self.assertEqual(imp.cache_from_source(path, True), expect)
|
||||
|
||||
def test_cache_from_source_no_cache_tag(self):
|
||||
# Non cache tag means NotImplementedError.
|
||||
with support.swap_attr(sys.implementation, 'cache_tag', None):
|
||||
with self.assertRaises(NotImplementedError):
|
||||
imp.cache_from_source('whatever.py')
|
||||
|
||||
def test_cache_from_source_no_dot(self):
|
||||
# Directory with a dot, filename without dot.
|
||||
path = os.path.join('foo.bar', 'file')
|
||||
expect = os.path.join('foo.bar', '__pycache__',
|
||||
'file{}.pyc'.format(self.tag))
|
||||
self.assertEqual(imp.cache_from_source(path, True), expect)
|
||||
|
||||
def test_cache_from_source_optimized(self):
|
||||
# Given the path to a .py file, return the path to its PEP 3147
|
||||
# defined .pyo file (i.e. under __pycache__).
|
||||
path = os.path.join('foo', 'bar', 'baz', 'qux.py')
|
||||
expect = os.path.join('foo', 'bar', 'baz', '__pycache__',
|
||||
'qux.{}.pyo'.format(self.tag))
|
||||
self.assertEqual(imp.cache_from_source(path, False), expect)
|
||||
|
||||
def test_cache_from_source_cwd(self):
|
||||
path = 'foo.py'
|
||||
expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag))
|
||||
self.assertEqual(imp.cache_from_source(path, True), expect)
|
||||
|
||||
def test_cache_from_source_override(self):
|
||||
# When debug_override is not None, it can be any true-ish or false-ish
|
||||
# value.
|
||||
path = os.path.join('foo', 'bar', 'baz.py')
|
||||
partial_expect = os.path.join('foo', 'bar', '__pycache__',
|
||||
'baz.{}.py'.format(self.tag))
|
||||
self.assertEqual(imp.cache_from_source(path, []), partial_expect + 'o')
|
||||
self.assertEqual(imp.cache_from_source(path, [17]),
|
||||
partial_expect + 'c')
|
||||
# However if the bool-ishness can't be determined, the exception
|
||||
# propagates.
|
||||
class Bearish:
|
||||
def __bool__(self): raise RuntimeError
|
||||
with self.assertRaises(RuntimeError):
|
||||
imp.cache_from_source('/foo/bar/baz.py', Bearish())
|
||||
|
||||
@unittest.skipUnless(os.sep == '\\' and os.altsep == '/',
|
||||
'test meaningful only where os.altsep is defined')
|
||||
def test_sep_altsep_and_sep_cache_from_source(self):
|
||||
# Windows path and PEP 3147 where sep is right of altsep.
|
||||
self.assertEqual(
|
||||
imp.cache_from_source('\\foo\\bar\\baz/qux.py', True),
|
||||
'\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag))
|
||||
|
||||
@unittest.skipUnless(sys.implementation.cache_tag is not None,
|
||||
'requires sys.implementation.cache_tag to not be '
|
||||
'None')
|
||||
|
@ -407,68 +356,6 @@ class PEP3147Tests(unittest.TestCase):
|
|||
expect = os.path.join('foo', 'bar', 'baz', 'qux.py')
|
||||
self.assertEqual(imp.source_from_cache(path), expect)
|
||||
|
||||
def test_source_from_cache_no_cache_tag(self):
|
||||
# If sys.implementation.cache_tag is None, raise NotImplementedError.
|
||||
path = os.path.join('blah', '__pycache__', 'whatever.pyc')
|
||||
with support.swap_attr(sys.implementation, 'cache_tag', None):
|
||||
with self.assertRaises(NotImplementedError):
|
||||
imp.source_from_cache(path)
|
||||
|
||||
def test_source_from_cache_bad_path(self):
|
||||
# When the path to a pyc file is not in PEP 3147 format, a ValueError
|
||||
# is raised.
|
||||
self.assertRaises(
|
||||
ValueError, imp.source_from_cache, '/foo/bar/bazqux.pyc')
|
||||
|
||||
def test_source_from_cache_no_slash(self):
|
||||
# No slashes at all in path -> ValueError
|
||||
self.assertRaises(
|
||||
ValueError, imp.source_from_cache, 'foo.cpython-32.pyc')
|
||||
|
||||
def test_source_from_cache_too_few_dots(self):
|
||||
# Too few dots in final path component -> ValueError
|
||||
self.assertRaises(
|
||||
ValueError, imp.source_from_cache, '__pycache__/foo.pyc')
|
||||
|
||||
def test_source_from_cache_too_many_dots(self):
|
||||
# Too many dots in final path component -> ValueError
|
||||
self.assertRaises(
|
||||
ValueError, imp.source_from_cache,
|
||||
'__pycache__/foo.cpython-32.foo.pyc')
|
||||
|
||||
def test_source_from_cache_no__pycache__(self):
|
||||
# Another problem with the path -> ValueError
|
||||
self.assertRaises(
|
||||
ValueError, imp.source_from_cache,
|
||||
'/foo/bar/foo.cpython-32.foo.pyc')
|
||||
|
||||
def test_package___file__(self):
|
||||
try:
|
||||
m = __import__('pep3147')
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
self.fail("pep3147 module already exists: %r" % (m,))
|
||||
# Test that a package's __file__ points to the right source directory.
|
||||
os.mkdir('pep3147')
|
||||
sys.path.insert(0, os.curdir)
|
||||
def cleanup():
|
||||
if sys.path[0] == os.curdir:
|
||||
del sys.path[0]
|
||||
shutil.rmtree('pep3147')
|
||||
self.addCleanup(cleanup)
|
||||
# Touch the __init__.py file.
|
||||
support.create_empty_file('pep3147/__init__.py')
|
||||
importlib.invalidate_caches()
|
||||
expected___file__ = os.sep.join(('.', 'pep3147', '__init__.py'))
|
||||
m = __import__('pep3147')
|
||||
self.assertEqual(m.__file__, expected___file__, (m.__file__, m.__path__, sys.path, sys.path_importer_cache))
|
||||
# Ensure we load the pyc file.
|
||||
support.unload('pep3147')
|
||||
m = __import__('pep3147')
|
||||
support.unload('pep3147')
|
||||
self.assertEqual(m.__file__, expected___file__, (m.__file__, m.__path__, sys.path, sys.path_importer_cache))
|
||||
|
||||
|
||||
class NullImporterTests(unittest.TestCase):
|
||||
@unittest.skipIf(support.TESTFN_UNENCODABLE is None,
|
||||
|
|
|
@ -32,7 +32,6 @@ skip_if_dont_write_bytecode = unittest.skipIf(
|
|||
def remove_files(name):
|
||||
for f in (name + ".py",
|
||||
name + ".pyc",
|
||||
name + ".pyo",
|
||||
name + ".pyw",
|
||||
name + "$py.class"):
|
||||
unlink(f)
|
||||
|
@ -84,7 +83,6 @@ class ImportTests(unittest.TestCase):
|
|||
def test_with_extension(ext):
|
||||
# The extension is normally ".py", perhaps ".pyw".
|
||||
source = TESTFN + ext
|
||||
pyo = TESTFN + ".pyo"
|
||||
if is_jython:
|
||||
pyc = TESTFN + "$py.class"
|
||||
else:
|
||||
|
@ -115,7 +113,6 @@ class ImportTests(unittest.TestCase):
|
|||
forget(TESTFN)
|
||||
unlink(source)
|
||||
unlink(pyc)
|
||||
unlink(pyo)
|
||||
|
||||
sys.path.insert(0, os.curdir)
|
||||
try:
|
||||
|
@ -138,7 +135,7 @@ class ImportTests(unittest.TestCase):
|
|||
f.write(']')
|
||||
|
||||
try:
|
||||
# Compile & remove .py file; we only need .pyc (or .pyo).
|
||||
# Compile & remove .py file; we only need .pyc.
|
||||
# Bytecode must be relocated from the PEP 3147 bytecode-only location.
|
||||
py_compile.compile(filename)
|
||||
finally:
|
||||
|
@ -252,7 +249,7 @@ class ImportTests(unittest.TestCase):
|
|||
importlib.invalidate_caches()
|
||||
mod = __import__(TESTFN)
|
||||
base, ext = os.path.splitext(mod.__file__)
|
||||
self.assertIn(ext, ('.pyc', '.pyo'))
|
||||
self.assertEqual(ext, '.pyc')
|
||||
finally:
|
||||
del sys.path[0]
|
||||
remove_files(TESTFN)
|
||||
|
@ -328,7 +325,7 @@ class ImportTests(unittest.TestCase):
|
|||
|
||||
@skip_if_dont_write_bytecode
|
||||
class FilePermissionTests(unittest.TestCase):
|
||||
# tests for file mode on cached .pyc/.pyo files
|
||||
# tests for file mode on cached .pyc files
|
||||
|
||||
@unittest.skipUnless(os.name == 'posix',
|
||||
"test meaningful only on posix systems")
|
||||
|
@ -339,7 +336,7 @@ class FilePermissionTests(unittest.TestCase):
|
|||
module = __import__(name)
|
||||
if not os.path.exists(cached_path):
|
||||
self.fail("__import__ did not result in creation of "
|
||||
"either a .pyc or .pyo file")
|
||||
"a .pyc file")
|
||||
stat_info = os.stat(cached_path)
|
||||
|
||||
# Check that the umask is respected, and the executable bits
|
||||
|
@ -358,7 +355,7 @@ class FilePermissionTests(unittest.TestCase):
|
|||
__import__(name)
|
||||
if not os.path.exists(cached_path):
|
||||
self.fail("__import__ did not result in creation of "
|
||||
"either a .pyc or .pyo file")
|
||||
"a .pyc file")
|
||||
stat_info = os.stat(cached_path)
|
||||
|
||||
self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(mode))
|
||||
|
@ -373,7 +370,7 @@ class FilePermissionTests(unittest.TestCase):
|
|||
__import__(name)
|
||||
if not os.path.exists(cached_path):
|
||||
self.fail("__import__ did not result in creation of "
|
||||
"either a .pyc or .pyo file")
|
||||
"a .pyc file")
|
||||
stat_info = os.stat(cached_path)
|
||||
|
||||
expected = mode | 0o200 # Account for fix for issue #6074
|
||||
|
@ -404,10 +401,7 @@ class FilePermissionTests(unittest.TestCase):
|
|||
unlink(path)
|
||||
unload(name)
|
||||
importlib.invalidate_caches()
|
||||
if __debug__:
|
||||
bytecode_only = path + "c"
|
||||
else:
|
||||
bytecode_only = path + "o"
|
||||
bytecode_only = path + "c"
|
||||
os.rename(importlib.util.cache_from_source(path), bytecode_only)
|
||||
m = __import__(name)
|
||||
self.assertEqual(m.x, 'rewritten')
|
||||
|
@ -631,9 +625,7 @@ class OverridingImportBuiltinTests(unittest.TestCase):
|
|||
|
||||
|
||||
class PycacheTests(unittest.TestCase):
|
||||
# Test the various PEP 3147 related behaviors.
|
||||
|
||||
tag = sys.implementation.cache_tag
|
||||
# Test the various PEP 3147/488-related behaviors.
|
||||
|
||||
def _clean(self):
|
||||
forget(TESTFN)
|
||||
|
@ -658,9 +650,10 @@ class PycacheTests(unittest.TestCase):
|
|||
self.assertFalse(os.path.exists('__pycache__'))
|
||||
__import__(TESTFN)
|
||||
self.assertTrue(os.path.exists('__pycache__'))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
'__pycache__', '{}.{}.py{}'.format(
|
||||
TESTFN, self.tag, 'c' if __debug__ else 'o'))))
|
||||
pyc_path = importlib.util.cache_from_source(self.source)
|
||||
self.assertTrue(os.path.exists(pyc_path),
|
||||
'bytecode file {!r} for {!r} does not '
|
||||
'exist'.format(pyc_path, TESTFN))
|
||||
|
||||
@unittest.skipUnless(os.name == 'posix',
|
||||
"test meaningful only on posix systems")
|
||||
|
@ -673,8 +666,10 @@ class PycacheTests(unittest.TestCase):
|
|||
with temp_umask(0o222):
|
||||
__import__(TESTFN)
|
||||
self.assertTrue(os.path.exists('__pycache__'))
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
'__pycache__', '{}.{}.pyc'.format(TESTFN, self.tag))))
|
||||
pyc_path = importlib.util.cache_from_source(self.source)
|
||||
self.assertFalse(os.path.exists(pyc_path),
|
||||
'bytecode file {!r} for {!r} '
|
||||
'exists'.format(pyc_path, TESTFN))
|
||||
|
||||
@skip_if_dont_write_bytecode
|
||||
def test_missing_source(self):
|
||||
|
|
|
@ -5,6 +5,7 @@ machinery = util.import_importlib('importlib.machinery')
|
|||
importlib_util = util.import_importlib('importlib.util')
|
||||
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
from test import support
|
||||
import types
|
||||
|
@ -562,7 +563,8 @@ class PEP3147Tests:
|
|||
path = os.path.join('foo', 'bar', 'baz', 'qux.py')
|
||||
expect = os.path.join('foo', 'bar', 'baz', '__pycache__',
|
||||
'qux.{}.pyc'.format(self.tag))
|
||||
self.assertEqual(self.util.cache_from_source(path, True), expect)
|
||||
self.assertEqual(self.util.cache_from_source(path, optimization=''),
|
||||
expect)
|
||||
|
||||
def test_cache_from_source_no_cache_tag(self):
|
||||
# No cache tag means NotImplementedError.
|
||||
|
@ -575,43 +577,103 @@ class PEP3147Tests:
|
|||
path = os.path.join('foo.bar', 'file')
|
||||
expect = os.path.join('foo.bar', '__pycache__',
|
||||
'file{}.pyc'.format(self.tag))
|
||||
self.assertEqual(self.util.cache_from_source(path, True), expect)
|
||||
self.assertEqual(self.util.cache_from_source(path, optimization=''),
|
||||
expect)
|
||||
|
||||
def test_cache_from_source_optimized(self):
|
||||
# Given the path to a .py file, return the path to its PEP 3147
|
||||
# defined .pyo file (i.e. under __pycache__).
|
||||
def test_cache_from_source_debug_override(self):
|
||||
# Given the path to a .py file, return the path to its PEP 3147/PEP 488
|
||||
# defined .pyc file (i.e. under __pycache__).
|
||||
path = os.path.join('foo', 'bar', 'baz', 'qux.py')
|
||||
expect = os.path.join('foo', 'bar', 'baz', '__pycache__',
|
||||
'qux.{}.pyo'.format(self.tag))
|
||||
self.assertEqual(self.util.cache_from_source(path, False), expect)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore')
|
||||
self.assertEqual(self.util.cache_from_source(path, False),
|
||||
self.util.cache_from_source(path, optimization=1))
|
||||
self.assertEqual(self.util.cache_from_source(path, True),
|
||||
self.util.cache_from_source(path, optimization=''))
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('error')
|
||||
with self.assertRaises(DeprecationWarning):
|
||||
self.util.cache_from_source(path, False)
|
||||
with self.assertRaises(DeprecationWarning):
|
||||
self.util.cache_from_source(path, True)
|
||||
|
||||
def test_cache_from_source_cwd(self):
|
||||
path = 'foo.py'
|
||||
expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag))
|
||||
self.assertEqual(self.util.cache_from_source(path, True), expect)
|
||||
self.assertEqual(self.util.cache_from_source(path, optimization=''),
|
||||
expect)
|
||||
|
||||
def test_cache_from_source_override(self):
|
||||
# When debug_override is not None, it can be any true-ish or false-ish
|
||||
# value.
|
||||
path = os.path.join('foo', 'bar', 'baz.py')
|
||||
partial_expect = os.path.join('foo', 'bar', '__pycache__',
|
||||
'baz.{}.py'.format(self.tag))
|
||||
self.assertEqual(self.util.cache_from_source(path, []), partial_expect + 'o')
|
||||
self.assertEqual(self.util.cache_from_source(path, [17]),
|
||||
partial_expect + 'c')
|
||||
# However if the bool-ishness can't be determined, the exception
|
||||
# propagates.
|
||||
class Bearish:
|
||||
def __bool__(self): raise RuntimeError
|
||||
with self.assertRaises(RuntimeError):
|
||||
self.util.cache_from_source('/foo/bar/baz.py', Bearish())
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore')
|
||||
self.assertEqual(self.util.cache_from_source(path, []),
|
||||
self.util.cache_from_source(path, optimization=1))
|
||||
self.assertEqual(self.util.cache_from_source(path, [17]),
|
||||
self.util.cache_from_source(path, optimization=''))
|
||||
with self.assertRaises(RuntimeError):
|
||||
self.util.cache_from_source('/foo/bar/baz.py', Bearish())
|
||||
|
||||
|
||||
def test_cache_from_source_optimization_empty_string(self):
|
||||
# Setting 'optimization' to '' leads to no optimization tag (PEP 488).
|
||||
path = 'foo.py'
|
||||
expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag))
|
||||
self.assertEqual(self.util.cache_from_source(path, optimization=''),
|
||||
expect)
|
||||
|
||||
def test_cache_from_source_optimization_None(self):
|
||||
# Setting 'optimization' to None uses the interpreter's optimization.
|
||||
# (PEP 488)
|
||||
path = 'foo.py'
|
||||
optimization_level = sys.flags.optimize
|
||||
almost_expect = os.path.join('__pycache__', 'foo.{}'.format(self.tag))
|
||||
if optimization_level == 0:
|
||||
expect = almost_expect + '.pyc'
|
||||
elif optimization_level <= 2:
|
||||
expect = almost_expect + '.opt-{}.pyc'.format(optimization_level)
|
||||
else:
|
||||
msg = '{!r} is a non-standard optimization level'.format(optimization_level)
|
||||
self.skipTest(msg)
|
||||
self.assertEqual(self.util.cache_from_source(path, optimization=None),
|
||||
expect)
|
||||
|
||||
def test_cache_from_source_optimization_set(self):
|
||||
# The 'optimization' parameter accepts anything that has a string repr
|
||||
# that passes str.alnum().
|
||||
path = 'foo.py'
|
||||
valid_characters = string.ascii_letters + string.digits
|
||||
almost_expect = os.path.join('__pycache__', 'foo.{}'.format(self.tag))
|
||||
got = self.util.cache_from_source(path, optimization=valid_characters)
|
||||
# Test all valid characters are accepted.
|
||||
self.assertEqual(got,
|
||||
almost_expect + '.opt-{}.pyc'.format(valid_characters))
|
||||
# str() should be called on argument.
|
||||
self.assertEqual(self.util.cache_from_source(path, optimization=42),
|
||||
almost_expect + '.opt-42.pyc')
|
||||
# Invalid characters raise ValueError.
|
||||
with self.assertRaises(ValueError):
|
||||
self.util.cache_from_source(path, optimization='path/is/bad')
|
||||
|
||||
def test_cache_from_source_debug_override_optimization_both_set(self):
|
||||
# Can only set one of the optimization-related parameters.
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore')
|
||||
with self.assertRaises(TypeError):
|
||||
self.util.cache_from_source('foo.py', False, optimization='')
|
||||
|
||||
@unittest.skipUnless(os.sep == '\\' and os.altsep == '/',
|
||||
'test meaningful only where os.altsep is defined')
|
||||
def test_sep_altsep_and_sep_cache_from_source(self):
|
||||
# Windows path and PEP 3147 where sep is right of altsep.
|
||||
self.assertEqual(
|
||||
self.util.cache_from_source('\\foo\\bar\\baz/qux.py', True),
|
||||
self.util.cache_from_source('\\foo\\bar\\baz/qux.py', optimization=''),
|
||||
'\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag))
|
||||
|
||||
@unittest.skipUnless(sys.implementation.cache_tag is not None,
|
||||
|
@ -649,7 +711,12 @@ class PEP3147Tests:
|
|||
ValueError, self.util.source_from_cache, '__pycache__/foo.pyc')
|
||||
|
||||
def test_source_from_cache_too_many_dots(self):
|
||||
# Too many dots in final path component -> ValueError
|
||||
with self.assertRaises(ValueError):
|
||||
self.util.source_from_cache(
|
||||
'__pycache__/foo.cpython-32.opt-1.foo.pyc')
|
||||
|
||||
def test_source_from_cache_not_opt(self):
|
||||
# Non-`opt-` path component -> ValueError
|
||||
self.assertRaises(
|
||||
ValueError, self.util.source_from_cache,
|
||||
'__pycache__/foo.cpython-32.foo.pyc')
|
||||
|
@ -660,6 +727,17 @@ class PEP3147Tests:
|
|||
ValueError, self.util.source_from_cache,
|
||||
'/foo/bar/foo.cpython-32.foo.pyc')
|
||||
|
||||
def test_source_from_cache_optimized_bytecode(self):
|
||||
# Optimized bytecode is not an issue.
|
||||
path = os.path.join('__pycache__', 'foo.{}.opt-1.pyc'.format(self.tag))
|
||||
self.assertEqual(self.util.source_from_cache(path), 'foo.py')
|
||||
|
||||
def test_source_from_cache_missing_optimization(self):
|
||||
# An empty optimization level is a no-no.
|
||||
path = os.path.join('__pycache__', 'foo.{}.opt-.pyc'.format(self.tag))
|
||||
with self.assertRaises(ValueError):
|
||||
self.util.source_from_cache(path)
|
||||
|
||||
|
||||
(Frozen_PEP3147Tests,
|
||||
Source_PEP3147Tests
|
||||
|
|
|
@ -119,6 +119,10 @@ class PyCompileTests(unittest.TestCase):
|
|||
self.assertTrue(os.path.exists(cache_path))
|
||||
self.assertFalse(os.path.exists(pyc_path))
|
||||
|
||||
def test_optimization_path(self):
|
||||
# Specifying optimized bytecode should lead to a path reflecting that.
|
||||
self.assertIn('opt-2', py_compile.compile(self.source_path, optimize=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -269,7 +269,7 @@ class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin):
|
|||
if verbose > 1: print(ex) # Persist with cleaning up
|
||||
|
||||
def _fix_ns_for_legacy_pyc(self, ns, alter_sys):
|
||||
char_to_add = "c" if __debug__ else "o"
|
||||
char_to_add = "c"
|
||||
ns["__file__"] += char_to_add
|
||||
ns["__cached__"] = ns["__file__"]
|
||||
spec = ns["__spec__"]
|
||||
|
|
|
@ -13,8 +13,8 @@ from test.tracedmodules import testmod
|
|||
#------------------------------- Utilities -----------------------------------#
|
||||
|
||||
def fix_ext_py(filename):
|
||||
"""Given a .pyc/.pyo filename converts it to the appropriate .py"""
|
||||
if filename.endswith(('.pyc', '.pyo')):
|
||||
"""Given a .pyc filename converts it to the appropriate .py"""
|
||||
if filename.endswith('.pyc'):
|
||||
filename = filename[:-1]
|
||||
return filename
|
||||
|
||||
|
|
|
@ -660,11 +660,9 @@ class TestFilters(unittest.TestCase):
|
|||
self.assertFalse(fnmatch('abcdd', 'a*c*e'))
|
||||
self.assertFalse(fnmatch('abcbdefef', 'a*bd*eg'))
|
||||
|
||||
# replace .pyc and .pyo suffix with .py
|
||||
# replace .pyc suffix with .py
|
||||
self.assertTrue(fnmatch('a.pyc', 'a.py'))
|
||||
self.assertTrue(fnmatch('a.pyo', 'a.py'))
|
||||
self.assertTrue(fnmatch('a.py', 'a.pyc'))
|
||||
self.assertTrue(fnmatch('a.py', 'a.pyo'))
|
||||
|
||||
if os.name == 'nt':
|
||||
# case insensitive
|
||||
|
@ -674,7 +672,6 @@ class TestFilters(unittest.TestCase):
|
|||
self.assertTrue(fnmatch('a.pyc', 'a.PY'))
|
||||
self.assertTrue(fnmatch('a.PYO', 'a.py'))
|
||||
self.assertTrue(fnmatch('a.py', 'a.PYC'))
|
||||
self.assertTrue(fnmatch('a.PY', 'a.pyo'))
|
||||
else:
|
||||
# case sensitive
|
||||
self.assertFalse(fnmatch('aBC', 'ABc'))
|
||||
|
@ -683,7 +680,6 @@ class TestFilters(unittest.TestCase):
|
|||
self.assertFalse(fnmatch('a.pyc', 'a.PY'))
|
||||
self.assertFalse(fnmatch('a.PYO', 'a.py'))
|
||||
self.assertFalse(fnmatch('a.py', 'a.PYC'))
|
||||
self.assertFalse(fnmatch('a.PY', 'a.pyo'))
|
||||
|
||||
if os.name == 'nt':
|
||||
# normalize alternate separator "/" to the standard separator "\"
|
||||
|
|
|
@ -689,7 +689,7 @@ class PyZipFileTests(unittest.TestCase):
|
|||
self.requiresWriteAccess(os.path.dirname(__file__))
|
||||
with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
|
||||
fn = __file__
|
||||
if fn.endswith('.pyc') or fn.endswith('.pyo'):
|
||||
if fn.endswith('.pyc'):
|
||||
path_split = fn.split(os.sep)
|
||||
if os.altsep is not None:
|
||||
path_split.extend(fn.split(os.altsep))
|
||||
|
@ -706,7 +706,7 @@ class PyZipFileTests(unittest.TestCase):
|
|||
|
||||
with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
|
||||
fn = __file__
|
||||
if fn.endswith(('.pyc', '.pyo')):
|
||||
if fn.endswith('.pyc'):
|
||||
fn = fn[:-1]
|
||||
|
||||
zipfp.writepy(fn, "testpackage")
|
||||
|
@ -762,10 +762,8 @@ class PyZipFileTests(unittest.TestCase):
|
|||
import email
|
||||
packagedir = os.path.dirname(email.__file__)
|
||||
self.requiresWriteAccess(packagedir)
|
||||
# use .pyc if running test in optimization mode,
|
||||
# use .pyo if running test in debug mode
|
||||
optlevel = 1 if __debug__ else 0
|
||||
ext = '.pyo' if optlevel == 1 else '.pyc'
|
||||
ext = '.pyc'
|
||||
|
||||
with TemporaryFile() as t, \
|
||||
zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp:
|
||||
|
@ -839,11 +837,10 @@ class PyZipFileTests(unittest.TestCase):
|
|||
self.assertIn("SyntaxError", s.getvalue())
|
||||
|
||||
# as it will not have compiled the python file, it will
|
||||
# include the .py file not .pyc or .pyo
|
||||
# include the .py file not .pyc
|
||||
names = zipfp.namelist()
|
||||
self.assertIn('mod1.py', names)
|
||||
self.assertNotIn('mod1.pyc', names)
|
||||
self.assertNotIn('mod1.pyo', names)
|
||||
|
||||
finally:
|
||||
rmtree(TESTFN2)
|
||||
|
|
|
@ -51,7 +51,7 @@ TESTPACK2 = "ziptestpackage2"
|
|||
TEMP_ZIP = os.path.abspath("junk95142.zip")
|
||||
|
||||
pyc_file = importlib.util.cache_from_source(TESTMOD + '.py')
|
||||
pyc_ext = ('.pyc' if __debug__ else '.pyo')
|
||||
pyc_ext = '.pyc'
|
||||
|
||||
|
||||
class ImportHooksBaseTestCase(unittest.TestCase):
|
||||
|
|
|
@ -1852,7 +1852,7 @@ class Tk(Misc, Wm):
|
|||
import os
|
||||
baseName = os.path.basename(sys.argv[0])
|
||||
baseName, ext = os.path.splitext(baseName)
|
||||
if ext not in ('.py', '.pyc', '.pyo'):
|
||||
if ext not in ('.py', '.pyc'):
|
||||
baseName = baseName + ext
|
||||
interactive = 0
|
||||
self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
|
||||
|
|
|
@ -16,7 +16,7 @@ this_dir_path = os.path.abspath(os.path.dirname(__file__))
|
|||
|
||||
def is_package(path):
|
||||
for name in os.listdir(path):
|
||||
if name in ('__init__.py', '__init__.pyc', '__init.pyo'):
|
||||
if name in ('__init__.py', '__init__.pyc'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -305,7 +305,7 @@ class CoverageResults:
|
|||
if self.is_ignored_filename(filename):
|
||||
continue
|
||||
|
||||
if filename.endswith((".pyc", ".pyo")):
|
||||
if filename.endswith(".pyc"):
|
||||
filename = filename[:-1]
|
||||
|
||||
if coverdir is None:
|
||||
|
|
|
@ -297,7 +297,7 @@ class _Traces(Sequence):
|
|||
|
||||
def _normalize_filename(filename):
|
||||
filename = os.path.normcase(filename)
|
||||
if filename.endswith(('.pyc', '.pyo')):
|
||||
if filename.endswith('.pyc'):
|
||||
filename = filename[:-1]
|
||||
return filename
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@ from . import case, suite, util
|
|||
|
||||
__unittest = True
|
||||
|
||||
# what about .pyc or .pyo (etc)
|
||||
# what about .pyc (etc)
|
||||
# we would need to avoid loading the same tests multiple times
|
||||
# from '.py', '.pyc' *and* '.pyo'
|
||||
# from '.py', *and* '.pyc'
|
||||
VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE)
|
||||
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ def warn(message, category=None, stacklevel=1):
|
|||
filename = globals.get('__file__')
|
||||
if filename:
|
||||
fnl = filename.lower()
|
||||
if fnl.endswith((".pyc", ".pyo")):
|
||||
if fnl.endswith(".pyc"):
|
||||
filename = filename[:-1]
|
||||
else:
|
||||
if module == "__main__":
|
||||
|
|
|
@ -1731,7 +1731,7 @@ class PyZipFile(ZipFile):
|
|||
the modules into the archive. If pathname is a plain
|
||||
directory, listdir *.py and enter all modules. Else, pathname
|
||||
must be a Python *.py file and the module will be put into the
|
||||
archive. Added modules are always module.pyo or module.pyc.
|
||||
archive. Added modules are always module.pyc.
|
||||
This method will compile the module.py into module.pyc if
|
||||
necessary.
|
||||
If filterfunc(pathname) is given, it is called with every argument.
|
||||
|
@ -1824,46 +1824,59 @@ class PyZipFile(ZipFile):
|
|||
|
||||
file_py = pathname + ".py"
|
||||
file_pyc = pathname + ".pyc"
|
||||
file_pyo = pathname + ".pyo"
|
||||
pycache_pyc = importlib.util.cache_from_source(file_py, True)
|
||||
pycache_pyo = importlib.util.cache_from_source(file_py, False)
|
||||
pycache_opt0 = importlib.util.cache_from_source(file_py, optimization='')
|
||||
pycache_opt1 = importlib.util.cache_from_source(file_py, optimization=1)
|
||||
pycache_opt2 = importlib.util.cache_from_source(file_py, optimization=2)
|
||||
if self._optimize == -1:
|
||||
# legacy mode: use whatever file is present
|
||||
if (os.path.isfile(file_pyo) and
|
||||
os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime):
|
||||
# Use .pyo file.
|
||||
arcname = fname = file_pyo
|
||||
elif (os.path.isfile(file_pyc) and
|
||||
if (os.path.isfile(file_pyc) and
|
||||
os.stat(file_pyc).st_mtime >= os.stat(file_py).st_mtime):
|
||||
# Use .pyc file.
|
||||
arcname = fname = file_pyc
|
||||
elif (os.path.isfile(pycache_pyc) and
|
||||
os.stat(pycache_pyc).st_mtime >= os.stat(file_py).st_mtime):
|
||||
elif (os.path.isfile(pycache_opt0) and
|
||||
os.stat(pycache_opt0).st_mtime >= os.stat(file_py).st_mtime):
|
||||
# Use the __pycache__/*.pyc file, but write it to the legacy pyc
|
||||
# file name in the archive.
|
||||
fname = pycache_pyc
|
||||
fname = pycache_opt0
|
||||
arcname = file_pyc
|
||||
elif (os.path.isfile(pycache_pyo) and
|
||||
os.stat(pycache_pyo).st_mtime >= os.stat(file_py).st_mtime):
|
||||
# Use the __pycache__/*.pyo file, but write it to the legacy pyo
|
||||
elif (os.path.isfile(pycache_opt1) and
|
||||
os.stat(pycache_opt1).st_mtime >= os.stat(file_py).st_mtime):
|
||||
# Use the __pycache__/*.pyc file, but write it to the legacy pyc
|
||||
# file name in the archive.
|
||||
fname = pycache_pyo
|
||||
arcname = file_pyo
|
||||
fname = pycache_opt1
|
||||
arcname = file_pyc
|
||||
elif (os.path.isfile(pycache_opt2) and
|
||||
os.stat(pycache_opt2).st_mtime >= os.stat(file_py).st_mtime):
|
||||
# Use the __pycache__/*.pyc file, but write it to the legacy pyc
|
||||
# file name in the archive.
|
||||
fname = pycache_opt2
|
||||
arcname = file_pyc
|
||||
else:
|
||||
# Compile py into PEP 3147 pyc file.
|
||||
if _compile(file_py):
|
||||
fname = (pycache_pyc if __debug__ else pycache_pyo)
|
||||
arcname = (file_pyc if __debug__ else file_pyo)
|
||||
if sys.flags.optimize == 0:
|
||||
fname = pycache_opt0
|
||||
elif sys.flags.optimize == 1:
|
||||
fname = pycache_opt1
|
||||
else:
|
||||
fname = pycache_opt2
|
||||
arcname = file_pyc
|
||||
else:
|
||||
fname = arcname = file_py
|
||||
else:
|
||||
# new mode: use given optimization level
|
||||
if self._optimize == 0:
|
||||
fname = pycache_pyc
|
||||
fname = pycache_opt0
|
||||
arcname = file_pyc
|
||||
else:
|
||||
fname = pycache_pyo
|
||||
arcname = file_pyo
|
||||
arcname = file_pyc
|
||||
if self._optimize == 1:
|
||||
fname = pycache_opt1
|
||||
elif self._optimize == 2:
|
||||
fname = pycache_opt2
|
||||
else:
|
||||
msg = "invalid value for 'optimize': {!r}".format(self._optimize)
|
||||
raise ValueError(msg)
|
||||
if not (os.path.isfile(fname) and
|
||||
os.stat(fname).st_mtime >= os.stat(file_py).st_mtime):
|
||||
if not _compile(file_py, optimize=self._optimize):
|
||||
|
|
|
@ -1263,7 +1263,12 @@ libinstall: build_all $(srcdir)/Lib/$(PLATDIR) $(srcdir)/Modules/xxmodule.c
|
|||
-d $(LIBDEST) -f \
|
||||
-x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \
|
||||
$(DESTDIR)$(LIBDEST)
|
||||
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
|
||||
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
|
||||
$(PYTHON_FOR_BUILD) -Wi -OO $(DESTDIR)$(LIBDEST)/compileall.py \
|
||||
-d $(LIBDEST) -f \
|
||||
-x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \
|
||||
$(DESTDIR)$(LIBDEST)
|
||||
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
|
||||
$(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \
|
||||
-d $(LIBDEST)/site-packages -f \
|
||||
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
|
||||
|
@ -1271,6 +1276,10 @@ libinstall: build_all $(srcdir)/Lib/$(PLATDIR) $(srcdir)/Modules/xxmodule.c
|
|||
$(PYTHON_FOR_BUILD) -Wi -O $(DESTDIR)$(LIBDEST)/compileall.py \
|
||||
-d $(LIBDEST)/site-packages -f \
|
||||
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
|
||||
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
|
||||
$(PYTHON_FOR_BUILD) -Wi -OO $(DESTDIR)$(LIBDEST)/compileall.py \
|
||||
-d $(LIBDEST)/site-packages -f \
|
||||
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
|
||||
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
|
||||
$(PYTHON_FOR_BUILD) -m lib2to3.pgen2.driver $(DESTDIR)$(LIBDEST)/lib2to3/Grammar.txt
|
||||
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
|
||||
|
|
|
@ -10,6 +10,8 @@ Release date: XXX
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #23731: Implement PEP 488: removal of .pyo files.
|
||||
|
||||
- Issue #23726: Don't enable GC for user subclasses of non-GC types that
|
||||
don't add any new fields. Patch by Eugene Toder.
|
||||
|
||||
|
|
|
@ -104,10 +104,10 @@ Python is also adaptable as an extension language for existing
|
|||
applications.
|
||||
See the internal documentation for hints.
|
||||
.PP
|
||||
Documentation for installed Python modules and packages can be
|
||||
viewed by running the
|
||||
Documentation for installed Python modules and packages can be
|
||||
viewed by running the
|
||||
.B pydoc
|
||||
program.
|
||||
program.
|
||||
.SH COMMAND LINE OPTIONS
|
||||
.TP
|
||||
.B \-B
|
||||
|
@ -150,23 +150,20 @@ Further restrictions may be imposed to prevent the user from injecting
|
|||
malicious code.
|
||||
.TP
|
||||
.BI "\-m " module-name
|
||||
Searches
|
||||
.I sys.path
|
||||
for the named module and runs the corresponding
|
||||
.I .py
|
||||
Searches
|
||||
.I sys.path
|
||||
for the named module and runs the corresponding
|
||||
.I .py
|
||||
file as a script.
|
||||
.TP
|
||||
.B \-O
|
||||
Turn on basic optimizations. This changes the filename extension for
|
||||
compiled (bytecode) files from
|
||||
.I .pyc
|
||||
to \fI.pyo\fP. Given twice, causes docstrings to be discarded.
|
||||
Turn on basic optimizations. Given twice, causes docstrings to be discarded.
|
||||
.TP
|
||||
.B \-OO
|
||||
Discard docstrings in addition to the \fB-O\fP optimizations.
|
||||
.TP
|
||||
.B \-q
|
||||
Do not print the version and copyright messages. These messages are
|
||||
Do not print the version and copyright messages. These messages are
|
||||
also suppressed in non-interactive mode.
|
||||
.TP
|
||||
.B \-s
|
||||
|
@ -193,7 +190,7 @@ The text I/O layer will still be line-buffered.
|
|||
.B \-v
|
||||
Print a message each time a module is initialized, showing the place
|
||||
(filename or built-in module) from which it is loaded. When given
|
||||
twice, print a message for each file that is checked for when
|
||||
twice, print a message for each file that is checked for when
|
||||
searching for a module. Also provides information on module cleanup
|
||||
at exit.
|
||||
.TP
|
||||
|
@ -418,7 +415,7 @@ the \fB\-u\fP option.
|
|||
.IP PYTHONVERBOSE
|
||||
If this is set to a non-empty string it is equivalent to specifying
|
||||
the \fB\-v\fP option. If set to an integer, it is equivalent to
|
||||
specifying \fB\-v\fP multiple times.
|
||||
specifying \fB\-v\fP multiple times.
|
||||
.IP PYTHONWARNINGS
|
||||
If this is set to a comma-separated string it is equivalent to
|
||||
specifying the \fB\-W\fP option for each separate value.
|
||||
|
|
|
@ -170,14 +170,14 @@ isfile(wchar_t *filename) /* Is file, not directory */
|
|||
|
||||
|
||||
static int
|
||||
ismodule(wchar_t *filename) /* Is module -- check for .pyc/.pyo too */
|
||||
ismodule(wchar_t *filename) /* Is module -- check for .pyc too */
|
||||
{
|
||||
if (isfile(filename))
|
||||
return 1;
|
||||
|
||||
/* Check for the compiled version of prefix. */
|
||||
if (wcslen(filename) < MAXPATHLEN) {
|
||||
wcscat(filename, Py_OptimizeFlag ? L"o" : L"c");
|
||||
wcscat(filename, L"c");
|
||||
if (isfile(filename))
|
||||
return 1;
|
||||
}
|
||||
|
@ -891,4 +891,3 @@ Py_GetProgramFullPath(void)
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -20,15 +20,13 @@ _Py_IDENTIFIER(replace);
|
|||
|
||||
/* zip_searchorder defines how we search for a module in the Zip
|
||||
archive: we first search for a package __init__, then for
|
||||
non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
|
||||
non-package .pyc, and .py entries. The .pyc entries
|
||||
are swapped by initzipimport() if we run in optimized mode. Also,
|
||||
'/' is replaced by SEP there. */
|
||||
static struct st_zip_searchorder zip_searchorder[] = {
|
||||
{"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
|
||||
{"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
|
||||
{"/__init__.py", IS_PACKAGE | IS_SOURCE},
|
||||
{".pyc", IS_BYTECODE},
|
||||
{".pyo", IS_BYTECODE},
|
||||
{".py", IS_SOURCE},
|
||||
{"", 0}
|
||||
};
|
||||
|
@ -1318,7 +1316,7 @@ parse_dostime(int dostime, int dosdate)
|
|||
return mktime(&stm);
|
||||
}
|
||||
|
||||
/* Given a path to a .pyc or .pyo file in the archive, return the
|
||||
/* Given a path to a .pyc file in the archive, return the
|
||||
modification time of the matching .py file, or 0 if no source
|
||||
is available. */
|
||||
static time_t
|
||||
|
@ -1481,17 +1479,6 @@ PyInit_zipimport(void)
|
|||
/* Correct directory separator */
|
||||
zip_searchorder[0].suffix[0] = SEP;
|
||||
zip_searchorder[1].suffix[0] = SEP;
|
||||
zip_searchorder[2].suffix[0] = SEP;
|
||||
if (Py_OptimizeFlag) {
|
||||
/* Reverse *.pyc and *.pyo */
|
||||
struct st_zip_searchorder tmp;
|
||||
tmp = zip_searchorder[0];
|
||||
zip_searchorder[0] = zip_searchorder[1];
|
||||
zip_searchorder[1] = tmp;
|
||||
tmp = zip_searchorder[3];
|
||||
zip_searchorder[3] = zip_searchorder[4];
|
||||
zip_searchorder[4] = tmp;
|
||||
}
|
||||
|
||||
mod = PyModule_Create(&zipimportmodule);
|
||||
if (mod == NULL)
|
||||
|
|
|
@ -563,13 +563,12 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
|
|||
data = PyUnicode_DATA(*filename);
|
||||
|
||||
#define ascii_lower(c) ((c <= 127) ? Py_TOLOWER(c) : 0)
|
||||
/* if filename.lower().endswith((".pyc", ".pyo")): */
|
||||
/* if filename.lower().endswith(".pyc"): */
|
||||
if (len >= 4 &&
|
||||
PyUnicode_READ(kind, data, len-4) == '.' &&
|
||||
ascii_lower(PyUnicode_READ(kind, data, len-3)) == 'p' &&
|
||||
ascii_lower(PyUnicode_READ(kind, data, len-2)) == 'y' &&
|
||||
(ascii_lower(PyUnicode_READ(kind, data, len-1)) == 'c' ||
|
||||
ascii_lower(PyUnicode_READ(kind, data, len-1)) == 'o'))
|
||||
ascii_lower(PyUnicode_READ(kind, data, len-1)) == 'c')
|
||||
{
|
||||
*filename = PyUnicode_Substring(*filename, 0,
|
||||
PyUnicode_GET_LENGTH(*filename)-1);
|
||||
|
|
8517
Python/importlib.h
8517
Python/importlib.h
File diff suppressed because it is too large
Load Diff
|
@ -265,7 +265,7 @@ PyRun_InteractiveOneFlags(FILE *fp, const char *filename_str, PyCompilerFlags *f
|
|||
static int
|
||||
maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit)
|
||||
{
|
||||
if (strcmp(ext, ".pyc") == 0 || strcmp(ext, ".pyo") == 0)
|
||||
if (strcmp(ext, ".pyc") == 0)
|
||||
return 1;
|
||||
|
||||
/* Only look into the file if we are allowed to close it, since
|
||||
|
@ -371,9 +371,6 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
|
|||
fprintf(stderr, "python: Can't reopen .pyc file\n");
|
||||
goto done;
|
||||
}
|
||||
/* Turn on optimization if a .pyo file is given */
|
||||
if (strcmp(ext, ".pyo") == 0)
|
||||
Py_OptimizeFlag = 1;
|
||||
|
||||
if (set_main_loader(d, filename, "SourcelessFileLoader") < 0) {
|
||||
fprintf(stderr, "python: failed to set __main__.__loader__\n");
|
||||
|
|
Loading…
Reference in New Issue