summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBarry Warsaw <barry@python.org>2023-04-28 23:17:58 (GMT)
committerGitHub <noreply@github.com>2023-04-28 23:17:58 (GMT)
commite1f14643dc0e6024f8df9ae975c3b05912a3cb28 (patch)
tree00bb66f68cadb9457a2a9486873ecf13be0241d6
parent79b9db9295a5a1607a0b4b10a8b4b72567eaf1ef (diff)
downloadcpython-e1f14643dc0e6024f8df9ae975c3b05912a3cb28.zip
cpython-e1f14643dc0e6024f8df9ae975c3b05912a3cb28.tar.gz
cpython-e1f14643dc0e6024f8df9ae975c3b05912a3cb28.tar.bz2
gh-98040: Remove just the `imp` module (#98573)
-rw-r--r--Doc/c-api/import.rst2
-rw-r--r--Doc/library/functions.rst1
-rw-r--r--Doc/library/imp.rst411
-rw-r--r--Doc/library/superseded.rst1
-rw-r--r--Doc/library/sys.rst4
-rw-r--r--Doc/reference/import.rst3
-rw-r--r--Doc/tools/.nitignore1
-rw-r--r--Doc/whatsnew/3.12.rst5
-rw-r--r--Lib/imp.py346
-rw-r--r--Lib/pkgutil.py183
-rwxr-xr-xLib/pydoc.py2
-rw-r--r--Lib/runpy.py7
-rw-r--r--Lib/test/test_imp.py524
-rw-r--r--Lib/test/test_importlib/util.py5
-rw-r--r--Lib/test/test_pkgutil.py8
-rw-r--r--Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst1
-rw-r--r--Modules/_testmultiphase.c12
-rw-r--r--Python/import.c8
-rwxr-xr-xPython/makeopcodetargets.py30
-rw-r--r--Python/pylifecycle.c7
-rw-r--r--Python/stdlib_module_names.h1
-rw-r--r--Tools/build/generate_stdlib_module_names.py2
-rw-r--r--Tools/c-analyzer/TODO1
-rw-r--r--Tools/importbench/importbench.py14
24 files changed, 41 insertions, 1538 deletions
diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
index a51619d..474a648 100644
--- a/Doc/c-api/import.rst
+++ b/Doc/c-api/import.rst
@@ -188,6 +188,8 @@ Importing Modules
.. versionchanged:: 3.3
Uses :func:`imp.source_from_cache()` in calculating the source path if
only the bytecode path is provided.
+ .. versionchanged:: 3.12
+ No longer uses the removed ``imp`` module.
.. c:function:: long PyImport_GetMagicNumber()
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index 7792e59..a5e86ef 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -1987,7 +1987,6 @@ are always available. They are listed here in alphabetical order.
.. index::
statement: import
- module: imp
.. note::
diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst
deleted file mode 100644
index 000793a..0000000
--- a/Doc/library/imp.rst
+++ /dev/null
@@ -1,411 +0,0 @@
-:mod:`imp` --- Access the :ref:`import <importsystem>` internals
-================================================================
-
-.. module:: imp
- :synopsis: Access the implementation of the import statement.
- :deprecated:
-
-**Source code:** :source:`Lib/imp.py`
-
-.. deprecated-removed:: 3.4 3.12
- The :mod:`imp` module is deprecated in favor of :mod:`importlib`.
-
-.. index:: statement: import
-
---------------
-
-This module provides an interface to the mechanisms used to implement the
-:keyword:`import` statement. It defines the following constants and functions:
-
-
-.. function:: get_magic()
-
- .. index:: pair: file; byte-code
-
- Return the magic string value used to recognize byte-compiled code files
- (:file:`.pyc` files). (This value may be different for each Python version.)
-
- .. deprecated:: 3.4
- Use :attr:`importlib.util.MAGIC_NUMBER` instead.
-
-
-.. function:: get_suffixes()
-
- Return a list of 3-element tuples, each describing a particular type of
- module. Each triple has the form ``(suffix, mode, type)``, where *suffix* is
- a string to be appended to the module name to form the filename to search
- for, *mode* is the mode string to pass to the built-in :func:`open` function
- to open the file (this can be ``'r'`` for text files or ``'rb'`` for binary
- files), and *type* is the file type, which has one of the values
- :const:`PY_SOURCE`, :const:`PY_COMPILED`, or :const:`C_EXTENSION`, described
- below.
-
- .. deprecated:: 3.3
- Use the constants defined on :mod:`importlib.machinery` instead.
-
-
-.. function:: find_module(name[, path])
-
- Try to find the module *name*. If *path* is omitted or ``None``, the list of
- directory names given by ``sys.path`` is searched, but first a few special
- places are searched: the function tries to find a built-in module with the
- given name (:const:`C_BUILTIN`), then a frozen module (:const:`PY_FROZEN`),
- and on some systems some other places are looked in as well (on Windows, it
- looks in the registry which may point to a specific file).
-
- Otherwise, *path* must be a list of directory names; each directory is
- searched for files with any of the suffixes returned by :func:`get_suffixes`
- above. Invalid names in the list are silently ignored (but all list items
- must be strings).
-
- If search is successful, the return value is a 3-element tuple ``(file,
- pathname, description)``:
-
- *file* is an open :term:`file object` positioned at the beginning, *pathname*
- is the pathname of the file found, and *description* is a 3-element tuple as
- contained in the list returned by :func:`get_suffixes` describing the kind of
- module found.
-
- If the module is built-in or frozen then *file* and *pathname* are both ``None``
- and the *description* tuple contains empty strings for its suffix and mode;
- the module type is indicated as given in parentheses above. If the search
- is unsuccessful, :exc:`ImportError` is raised. Other exceptions indicate
- problems with the arguments or environment.
-
- If the module is a package, *file* is ``None``, *pathname* is the package
- path and the last item in the *description* tuple is :const:`PKG_DIRECTORY`.
-
- This function does not handle hierarchical module names (names containing
- dots). In order to find *P.M*, that is, submodule *M* of package *P*, use
- :func:`find_module` and :func:`load_module` to find and load package *P*, and
- then use :func:`find_module` with the *path* argument set to ``P.__path__``.
- When *P* itself has a dotted name, apply this recipe recursively.
-
- .. deprecated:: 3.3
- Use :func:`importlib.util.find_spec` instead unless Python 3.3
- compatibility is required, in which case use
- :func:`importlib.find_loader`. For example usage of the former case,
- see the :ref:`importlib-examples` section of the :mod:`importlib`
- documentation.
-
-
-.. function:: load_module(name, file, pathname, description)
-
- Load a module that was previously found by :func:`find_module` (or by an
- otherwise conducted search yielding compatible results). This function does
- more than importing the module: if the module was already imported, it will
- reload the module! The *name* argument indicates the full
- module name (including the package name, if this is a submodule of a
- package). The *file* argument is an open file, and *pathname* is the
- corresponding file name; these can be ``None`` and ``''``, respectively, when
- the module is a package or not being loaded from a file. The *description*
- argument is a tuple, as would be returned by :func:`get_suffixes`, describing
- what kind of module must be loaded.
-
- If the load is successful, the return value is the module object; otherwise,
- an exception (usually :exc:`ImportError`) is raised.
-
- **Important:** the caller is responsible for closing the *file* argument, if
- it was not ``None``, even when an exception is raised. This is best done
- using a :keyword:`try` ... :keyword:`finally` statement.
-
- .. deprecated:: 3.3
- If previously used in conjunction with :func:`imp.find_module` then
- consider using :func:`importlib.import_module`, otherwise use the loader
- returned by the replacement you chose for :func:`imp.find_module`. If you
- called :func:`imp.load_module` and related functions directly with file
- path arguments then use a combination of
- :func:`importlib.util.spec_from_file_location` and
- :func:`importlib.util.module_from_spec`. See the :ref:`importlib-examples`
- section of the :mod:`importlib` documentation for details of the various
- approaches.
-
-
-.. function:: new_module(name)
-
- Return a new empty module object called *name*. This object is *not* inserted
- in ``sys.modules``.
-
- .. deprecated:: 3.4
- Use :func:`importlib.util.module_from_spec` instead.
-
-
-.. function:: reload(module)
-
- Reload a previously imported *module*. The argument must be a module object, so
- it must have been successfully imported before. This is useful if you have
- edited the module source file using an external editor and want to try out the
- new version without leaving the Python interpreter. The return value is the
- module object (the same as the *module* argument).
-
- When ``reload(module)`` is executed:
-
- * Python modules' code is recompiled and the module-level code reexecuted,
- defining a new set of objects which are bound to names in the module's
- dictionary. The ``init`` function of extension modules is not called a second
- time.
-
- * As with all other objects in Python the old objects are only reclaimed after
- their reference counts drop to zero.
-
- * The names in the module namespace are updated to point to any new or changed
- objects.
-
- * Other references to the old objects (such as names external to the module) are
- not rebound to refer to the new objects and must be updated in each namespace
- where they occur if that is desired.
-
- There are a number of other caveats:
-
- When a module is reloaded, its dictionary (containing the module's global
- variables) is retained. Redefinitions of names will override the old
- definitions, so this is generally not a problem. If the new version of a module
- does not define a name that was defined by the old version, the old definition
- remains. This feature can be used to the module's advantage if it maintains a
- global table or cache of objects --- with a :keyword:`try` statement it can test
- for the table's presence and skip its initialization if desired::
-
- try:
- cache
- except NameError:
- cache = {}
-
- It is legal though generally not very useful to reload built-in or dynamically
- loaded modules, except for :mod:`sys`, :mod:`__main__` and :mod:`builtins`.
- In many cases, however, extension modules are not designed to be initialized
- more than once, and may fail in arbitrary ways when reloaded.
-
- If a module imports objects from another module using :keyword:`from` ...
- :keyword:`import` ..., calling :func:`reload` for the other module does not
- redefine the objects imported from it --- one way around this is to re-execute
- the :keyword:`!from` statement, another is to use :keyword:`!import` and qualified
- names (*module*.*name*) instead.
-
- If a module instantiates instances of a class, reloading the module that defines
- the class does not affect the method definitions of the instances --- they
- continue to use the old class definition. The same is true for derived classes.
-
- .. versionchanged:: 3.3
- Relies on both ``__name__`` and ``__loader__`` being defined on the module
- being reloaded instead of just ``__name__``.
-
- .. deprecated:: 3.4
- Use :func:`importlib.reload` instead.
-
-
-The following functions are conveniences for handling :pep:`3147` byte-compiled
-file paths.
-
-.. versionadded:: 3.2
-
-.. function:: cache_from_source(path, debug_override=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
- 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). 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.
-
- .. versionchanged:: 3.3
- If :attr:`sys.implementation.cache_tag` is ``None``, then
- :exc:`NotImplementedError` is raised.
-
- .. 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)
-
- Given the *path* to a :pep:`3147` file name, return the associated source code
- 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 :exc:`ValueError` is raised. If
- :attr:`sys.implementation.cache_tag` is not defined,
- :exc:`NotImplementedError` is raised.
-
- .. versionchanged:: 3.3
- Raise :exc:`NotImplementedError` when
- :attr:`sys.implementation.cache_tag` is not defined.
-
- .. deprecated:: 3.4
- Use :func:`importlib.util.source_from_cache` instead.
-
-
-.. function:: get_tag()
-
- Return the :pep:`3147` magic tag string matching this version of Python's
- magic number, as returned by :func:`get_magic`.
-
- .. deprecated:: 3.4
- Use :attr:`sys.implementation.cache_tag` directly starting
- in Python 3.3.
-
-
-The following functions help interact with the import system's internal
-locking mechanism. Locking semantics of imports are an implementation
-detail which may vary from release to release. However, Python ensures
-that circular imports work without any deadlocks.
-
-
-.. function:: lock_held()
-
- Return ``True`` if the global import lock is currently held, else
- ``False``. On platforms without threads, always return ``False``.
-
- On platforms with threads, a thread executing an import first holds a
- global import lock, then sets up a per-module lock for the rest of the
- import. This blocks other threads from importing the same module until
- the original import completes, preventing other threads from seeing
- incomplete module objects constructed by the original thread. An
- exception is made for circular imports, which by construction have to
- expose an incomplete module object at some point.
-
- .. versionchanged:: 3.3
- The locking scheme has changed to per-module locks for
- the most part. A global import lock is kept for some critical tasks,
- such as initializing the per-module locks.
-
- .. deprecated:: 3.4
-
-
-.. function:: acquire_lock()
-
- Acquire the interpreter's global import lock for the current thread.
- This lock should be used by import hooks to ensure thread-safety when
- importing modules.
-
- Once a thread has acquired the import lock, the same thread may acquire it
- again without blocking; the thread must release it once for each time it has
- acquired it.
-
- On platforms without threads, this function does nothing.
-
- .. versionchanged:: 3.3
- The locking scheme has changed to per-module locks for
- the most part. A global import lock is kept for some critical tasks,
- such as initializing the per-module locks.
-
- .. deprecated:: 3.4
-
-
-.. function:: release_lock()
-
- Release the interpreter's global import lock. On platforms without
- threads, this function does nothing.
-
- .. versionchanged:: 3.3
- The locking scheme has changed to per-module locks for
- the most part. A global import lock is kept for some critical tasks,
- such as initializing the per-module locks.
-
- .. deprecated:: 3.4
-
-
-The following constants with integer values, defined in this module, are used
-to indicate the search result of :func:`find_module`.
-
-
-.. data:: PY_SOURCE
-
- The module was found as a source file.
-
- .. deprecated:: 3.3
-
-
-.. data:: PY_COMPILED
-
- The module was found as a compiled code object file.
-
- .. deprecated:: 3.3
-
-
-.. data:: C_EXTENSION
-
- The module was found as dynamically loadable shared library.
-
- .. deprecated:: 3.3
-
-
-.. data:: PKG_DIRECTORY
-
- The module was found as a package directory.
-
- .. deprecated:: 3.3
-
-
-.. data:: C_BUILTIN
-
- The module was found as a built-in module.
-
- .. deprecated:: 3.3
-
-
-.. data:: PY_FROZEN
-
- The module was found as a frozen module.
-
- .. deprecated:: 3.3
-
-
-.. class:: NullImporter(path_string)
-
- The :class:`NullImporter` type is a :pep:`302` import hook that handles
- non-directory path strings by failing to find any modules. Calling this type
- with an existing directory or empty string raises :exc:`ImportError`.
- Otherwise, a :class:`NullImporter` instance is returned.
-
- Instances have only one method:
-
- .. method:: NullImporter.find_module(fullname [, path])
-
- This method always returns ``None``, indicating that the requested module could
- not be found.
-
- .. versionchanged:: 3.3
- ``None`` is inserted into ``sys.path_importer_cache`` instead of an
- instance of :class:`NullImporter`.
-
- .. deprecated:: 3.4
- Insert ``None`` into ``sys.path_importer_cache`` instead.
-
-
-.. _examples-imp:
-
-Examples
---------
-
-The following function emulates what was the standard import statement up to
-Python 1.4 (no hierarchical module names). (This *implementation* wouldn't work
-in that version, since :func:`find_module` has been extended and
-:func:`load_module` has been added in 1.4.) ::
-
- import imp
- import sys
-
- def __import__(name, globals=None, locals=None, fromlist=None):
- # Fast path: see if the module has already been imported.
- try:
- return sys.modules[name]
- except KeyError:
- pass
-
- # If any of the following calls raises an exception,
- # there's a problem we can't handle -- let the caller handle it.
-
- fp, pathname, description = imp.find_module(name)
-
- try:
- return imp.load_module(name, fp, pathname, description)
- finally:
- # Since we may exit via an exception, close fp explicitly.
- if fp:
- fp.close()
diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst
index 8786e22..aaf66ea 100644
--- a/Doc/library/superseded.rst
+++ b/Doc/library/superseded.rst
@@ -17,7 +17,6 @@ backwards compatibility. They have been superseded by other modules.
chunk.rst
crypt.rst
imghdr.rst
- imp.rst
mailcap.rst
msilib.rst
nis.rst
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index 7324f31..7c0e851 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -1253,10 +1253,6 @@ always available.
Originally specified in :pep:`302`.
- .. versionchanged:: 3.3
- ``None`` is stored instead of :class:`imp.NullImporter` when no finder
- is found.
-
.. data:: platform
diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst
index b22b525..57eb540 100644
--- a/Doc/reference/import.rst
+++ b/Doc/reference/import.rst
@@ -1077,4 +1077,5 @@ methods to finders and loaders.
.. [#fnpic] In legacy code, it is possible to find instances of
:class:`imp.NullImporter` in the :data:`sys.path_importer_cache`. It
is recommended that code be changed to use ``None`` instead. See
- :ref:`portingpythoncode` for more details.
+ :ref:`portingpythoncode` for more details. Note that the ``imp`` module
+ was removed in Python 3.12.
diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore
index f335017..1d3503b 100644
--- a/Doc/tools/.nitignore
+++ b/Doc/tools/.nitignore
@@ -149,7 +149,6 @@ Doc/library/http.cookiejar.rst
Doc/library/http.cookies.rst
Doc/library/http.server.rst
Doc/library/idle.rst
-Doc/library/imp.rst
Doc/library/importlib.resources.abc.rst
Doc/library/importlib.resources.rst
Doc/library/importlib.rst
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 2915005..a75e88c 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -961,11 +961,14 @@ Removed
completed:
* References to, and support for ``module_repr()`` has been eradicated.
-
+ (Contributed by Barry Warsaw in :gh:`97850`.)
* ``importlib.util.set_package`` has been removed.
(Contributed by Brett Cannon in :gh:`65961`.)
+* The ``imp`` module has been removed. (Contributed by Barry Warsaw in
+ :gh:`98040`.)
+
* Removed the ``suspicious`` rule from the documentation Makefile, and
removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint
<https://github.com/sphinx-contrib/sphinx-lint>`_.
diff --git a/Lib/imp.py b/Lib/imp.py
deleted file mode 100644
index fe850f6..0000000
--- a/Lib/imp.py
+++ /dev/null
@@ -1,346 +0,0 @@
-"""This module provides the components needed to build your own __import__
-function. Undocumented functions are obsolete.
-
-In most cases it is preferred you consider using the importlib module's
-functionality over this module.
-
-"""
-# (Probably) need to stay in _imp
-from _imp import (lock_held, acquire_lock, release_lock,
- get_frozen_object, is_frozen_package,
- init_frozen, is_builtin, is_frozen,
- _fix_co_filename, _frozen_module_names)
-try:
- from _imp import create_dynamic
-except ImportError:
- # Platform doesn't support dynamic loading.
- create_dynamic = None
-
-from importlib._bootstrap import _ERR_MSG, _exec, _load, _builtin_from_name
-from importlib._bootstrap_external import SourcelessFileLoader
-
-from importlib import machinery
-from importlib import util
-import importlib
-import os
-import sys
-import tokenize
-import types
-import warnings
-
-warnings.warn("the imp module is deprecated in favour of importlib and slated "
- "for removal in Python 3.12; "
- "see the module's documentation for alternative uses",
- DeprecationWarning, stacklevel=2)
-
-# DEPRECATED
-SEARCH_ERROR = 0
-PY_SOURCE = 1
-PY_COMPILED = 2
-C_EXTENSION = 3
-PY_RESOURCE = 4
-PKG_DIRECTORY = 5
-C_BUILTIN = 6
-PY_FROZEN = 7
-PY_CODERESOURCE = 8
-IMP_HOOK = 9
-
-
-def new_module(name):
- """**DEPRECATED**
-
- Create a new module.
-
- The module is not entered into sys.modules.
-
- """
- return types.ModuleType(name)
-
-
-def get_magic():
- """**DEPRECATED**
-
- Return the magic number for .pyc files.
- """
- return util.MAGIC_NUMBER
-
-
-def get_tag():
- """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 file.
-
- The .py file does not need to exist; this simply returns the path to the
- .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.
-
- If sys.implementation.cache_tag is None then NotImplementedError is raised.
-
- """
- 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. file, return the path to its .py file.
-
- 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.
-
- """
- return util.source_from_cache(path)
-
-
-def get_suffixes():
- """**DEPRECATED**"""
- extensions = [(s, 'rb', C_EXTENSION) for s in machinery.EXTENSION_SUFFIXES]
- source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES]
- bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES]
-
- return extensions + source + bytecode
-
-
-class NullImporter:
-
- """**DEPRECATED**
-
- Null import object.
-
- """
-
- def __init__(self, path):
- if path == '':
- raise ImportError('empty pathname', path='')
- elif os.path.isdir(path):
- raise ImportError('existing directory', path=path)
-
- def find_module(self, fullname):
- """Always returns None."""
- return None
-
-
-class _HackedGetData:
-
- """Compatibility support for 'file' arguments of various load_*()
- functions."""
-
- def __init__(self, fullname, path, file=None):
- super().__init__(fullname, path)
- self.file = file
-
- def get_data(self, path):
- """Gross hack to contort loader to deal w/ load_*()'s bad API."""
- if self.file and path == self.path:
- # The contract of get_data() requires us to return bytes. Reopen the
- # file in binary mode if needed.
- if not self.file.closed:
- file = self.file
- if 'b' not in file.mode:
- file.close()
- if self.file.closed:
- self.file = file = open(self.path, 'rb')
-
- with file:
- return file.read()
- else:
- return super().get_data(path)
-
-
-class _LoadSourceCompatibility(_HackedGetData, machinery.SourceFileLoader):
-
- """Compatibility support for implementing load_source()."""
-
-
-def load_source(name, pathname, file=None):
- loader = _LoadSourceCompatibility(name, pathname, file)
- spec = util.spec_from_file_location(name, pathname, loader=loader)
- if name in sys.modules:
- module = _exec(spec, sys.modules[name])
- else:
- module = _load(spec)
- # To allow reloading to potentially work, use a non-hacked loader which
- # won't rely on a now-closed file object.
- module.__loader__ = machinery.SourceFileLoader(name, pathname)
- module.__spec__.loader = module.__loader__
- return module
-
-
-class _LoadCompiledCompatibility(_HackedGetData, SourcelessFileLoader):
-
- """Compatibility support for implementing load_compiled()."""
-
-
-def load_compiled(name, pathname, file=None):
- """**DEPRECATED**"""
- loader = _LoadCompiledCompatibility(name, pathname, file)
- spec = util.spec_from_file_location(name, pathname, loader=loader)
- if name in sys.modules:
- module = _exec(spec, sys.modules[name])
- else:
- module = _load(spec)
- # To allow reloading to potentially work, use a non-hacked loader which
- # won't rely on a now-closed file object.
- module.__loader__ = SourcelessFileLoader(name, pathname)
- module.__spec__.loader = module.__loader__
- return module
-
-
-def load_package(name, path):
- """**DEPRECATED**"""
- if os.path.isdir(path):
- extensions = (machinery.SOURCE_SUFFIXES[:] +
- machinery.BYTECODE_SUFFIXES[:])
- for extension in extensions:
- init_path = os.path.join(path, '__init__' + extension)
- if os.path.exists(init_path):
- path = init_path
- break
- else:
- raise ValueError('{!r} is not a package'.format(path))
- spec = util.spec_from_file_location(name, path,
- submodule_search_locations=[])
- if name in sys.modules:
- return _exec(spec, sys.modules[name])
- else:
- return _load(spec)
-
-
-def load_module(name, file, filename, details):
- """**DEPRECATED**
-
- Load a module, given information returned by find_module().
-
- The module name must include the full package name, if any.
-
- """
- suffix, mode, type_ = details
- if mode and (not mode.startswith('r') or '+' in mode):
- raise ValueError('invalid file open mode {!r}'.format(mode))
- elif file is None and type_ in {PY_SOURCE, PY_COMPILED}:
- msg = 'file object required for import (type code {})'.format(type_)
- raise ValueError(msg)
- elif type_ == PY_SOURCE:
- return load_source(name, filename, file)
- elif type_ == PY_COMPILED:
- return load_compiled(name, filename, file)
- elif type_ == C_EXTENSION and load_dynamic is not None:
- if file is None:
- with open(filename, 'rb') as opened_file:
- return load_dynamic(name, filename, opened_file)
- else:
- return load_dynamic(name, filename, file)
- elif type_ == PKG_DIRECTORY:
- return load_package(name, filename)
- elif type_ == C_BUILTIN:
- return init_builtin(name)
- elif type_ == PY_FROZEN:
- return init_frozen(name)
- else:
- msg = "Don't know how to import {} (type code {})".format(name, type_)
- raise ImportError(msg, name=name)
-
-
-def find_module(name, path=None):
- """**DEPRECATED**
-
- Search for a module.
-
- If path is omitted or None, search for a built-in, frozen or special
- module and continue search in sys.path. The module name cannot
- contain '.'; to search for a submodule of a package, pass the
- submodule name and the package's __path__.
-
- """
- if not isinstance(name, str):
- raise TypeError("'name' must be a str, not {}".format(type(name)))
- elif not isinstance(path, (type(None), list)):
- # Backwards-compatibility
- raise RuntimeError("'path' must be None or a list, "
- "not {}".format(type(path)))
-
- if path is None:
- if is_builtin(name):
- return None, None, ('', '', C_BUILTIN)
- elif is_frozen(name):
- return None, None, ('', '', PY_FROZEN)
- else:
- path = sys.path
-
- for entry in path:
- package_directory = os.path.join(entry, name)
- for suffix in ['.py', machinery.BYTECODE_SUFFIXES[0]]:
- package_file_name = '__init__' + suffix
- file_path = os.path.join(package_directory, package_file_name)
- if os.path.isfile(file_path):
- return None, package_directory, ('', '', PKG_DIRECTORY)
- for suffix, mode, type_ in get_suffixes():
- file_name = name + suffix
- file_path = os.path.join(entry, file_name)
- if os.path.isfile(file_path):
- break
- else:
- continue
- break # Break out of outer loop when breaking out of inner loop.
- else:
- raise ImportError(_ERR_MSG.format(name), name=name)
-
- encoding = None
- if 'b' not in mode:
- with open(file_path, 'rb') as file:
- encoding = tokenize.detect_encoding(file.readline)[0]
- file = open(file_path, mode, encoding=encoding)
- return file, file_path, (suffix, mode, type_)
-
-
-def reload(module):
- """**DEPRECATED**
-
- Reload the module and return it.
-
- The module must have been successfully imported before.
-
- """
- return importlib.reload(module)
-
-
-def init_builtin(name):
- """**DEPRECATED**
-
- Load and return a built-in module by name, or None is such module doesn't
- exist
- """
- try:
- return _builtin_from_name(name)
- except ImportError:
- return None
-
-
-if create_dynamic:
- def load_dynamic(name, path, file=None):
- """**DEPRECATED**
-
- Load an extension module.
- """
- import importlib.machinery
- loader = importlib.machinery.ExtensionFileLoader(name, path)
-
- # Issue #24748: Skip the sys.modules check in _load_module_shim;
- # always load new extension
- spec = importlib.util.spec_from_file_location(
- name, path, loader=loader)
- return _load(spec)
-
-else:
- load_dynamic = None
diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py
index 56731de..fb977ea 100644
--- a/Lib/pkgutil.py
+++ b/Lib/pkgutil.py
@@ -14,7 +14,7 @@ import warnings
__all__ = [
'get_importer', 'iter_importers', 'get_loader', 'find_loader',
'walk_packages', 'iter_modules', 'get_data',
- 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
+ 'read_code', 'extend_path',
'ModuleInfo',
]
@@ -185,187 +185,6 @@ iter_importer_modules.register(
importlib.machinery.FileFinder, _iter_file_finder_modules)
-def _import_imp():
- global imp
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- imp = importlib.import_module('imp')
-
-class ImpImporter:
- """PEP 302 Finder that wraps Python's "classic" import algorithm
-
- ImpImporter(dirname) produces a PEP 302 finder that searches that
- directory. ImpImporter(None) produces a PEP 302 finder that searches
- the current sys.path, plus any modules that are frozen or built-in.
-
- Note that ImpImporter does not currently support being used by placement
- on sys.meta_path.
- """
-
- def __init__(self, path=None):
- global imp
- warnings.warn("This emulation is deprecated and slated for removal "
- "in Python 3.12; use 'importlib' instead",
- DeprecationWarning)
- _import_imp()
- self.path = path
-
- def find_module(self, fullname, path=None):
- # Note: we ignore 'path' argument since it is only used via meta_path
- subname = fullname.split(".")[-1]
- if subname != fullname and self.path is None:
- return None
- if self.path is None:
- path = None
- else:
- path = [os.path.realpath(self.path)]
- try:
- file, filename, etc = imp.find_module(subname, path)
- except ImportError:
- return None
- return ImpLoader(fullname, file, filename, etc)
-
- def iter_modules(self, prefix=''):
- if self.path is None or not os.path.isdir(self.path):
- return
-
- yielded = {}
- import inspect
- try:
- filenames = os.listdir(self.path)
- except OSError:
- # ignore unreadable directories like import does
- filenames = []
- filenames.sort() # handle packages before same-named modules
-
- for fn in filenames:
- modname = inspect.getmodulename(fn)
- if modname=='__init__' or modname in yielded:
- continue
-
- path = os.path.join(self.path, fn)
- ispkg = False
-
- if not modname and os.path.isdir(path) and '.' not in fn:
- modname = fn
- try:
- dircontents = os.listdir(path)
- except OSError:
- # ignore unreadable directories like import does
- dircontents = []
- for fn in dircontents:
- subname = inspect.getmodulename(fn)
- if subname=='__init__':
- ispkg = True
- break
- else:
- continue # not a package
-
- if modname and '.' not in modname:
- yielded[modname] = 1
- yield prefix + modname, ispkg
-
-
-class ImpLoader:
- """PEP 302 Loader that wraps Python's "classic" import algorithm
- """
- code = source = None
-
- def __init__(self, fullname, file, filename, etc):
- warnings.warn("This emulation is deprecated and slated for removal in "
- "Python 3.12; use 'importlib' instead",
- DeprecationWarning)
- _import_imp()
- self.file = file
- self.filename = filename
- self.fullname = fullname
- self.etc = etc
-
- def load_module(self, fullname):
- self._reopen()
- try:
- mod = imp.load_module(fullname, self.file, self.filename, self.etc)
- finally:
- if self.file:
- self.file.close()
- # Note: we don't set __loader__ because we want the module to look
- # normal; i.e. this is just a wrapper for standard import machinery
- return mod
-
- def get_data(self, pathname):
- with open(pathname, "rb") as file:
- return file.read()
-
- def _reopen(self):
- if self.file and self.file.closed:
- mod_type = self.etc[2]
- if mod_type==imp.PY_SOURCE:
- self.file = open(self.filename, 'r')
- elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
- self.file = open(self.filename, 'rb')
-
- def _fix_name(self, fullname):
- if fullname is None:
- fullname = self.fullname
- elif fullname != self.fullname:
- raise ImportError("Loader for module %s cannot handle "
- "module %s" % (self.fullname, fullname))
- return fullname
-
- def is_package(self, fullname):
- fullname = self._fix_name(fullname)
- return self.etc[2]==imp.PKG_DIRECTORY
-
- def get_code(self, fullname=None):
- fullname = self._fix_name(fullname)
- if self.code is None:
- mod_type = self.etc[2]
- if mod_type==imp.PY_SOURCE:
- source = self.get_source(fullname)
- self.code = compile(source, self.filename, 'exec')
- elif mod_type==imp.PY_COMPILED:
- self._reopen()
- try:
- self.code = read_code(self.file)
- finally:
- self.file.close()
- elif mod_type==imp.PKG_DIRECTORY:
- self.code = self._get_delegate().get_code()
- return self.code
-
- def get_source(self, fullname=None):
- fullname = self._fix_name(fullname)
- if self.source is None:
- mod_type = self.etc[2]
- if mod_type==imp.PY_SOURCE:
- self._reopen()
- try:
- self.source = self.file.read()
- finally:
- self.file.close()
- elif mod_type==imp.PY_COMPILED:
- if os.path.exists(self.filename[:-1]):
- with open(self.filename[:-1], 'r') as f:
- self.source = f.read()
- elif mod_type==imp.PKG_DIRECTORY:
- self.source = self._get_delegate().get_source()
- return self.source
-
- def _get_delegate(self):
- finder = ImpImporter(self.filename)
- spec = _get_spec(finder, '__init__')
- return spec.loader
-
- def get_filename(self, fullname=None):
- fullname = self._fix_name(fullname)
- mod_type = self.etc[2]
- if mod_type==imp.PKG_DIRECTORY:
- return self._get_delegate().get_filename()
- elif mod_type in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
- return self.filename
- return None
-
-
try:
import zipimport
from zipimport import zipimporter
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index 78d8fd5..1c3443f 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -512,7 +512,7 @@ class Doc:
basedir = os.path.normcase(basedir)
if (isinstance(object, type(os)) and
- (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
+ (object.__name__ in ('errno', 'exceptions', 'gc',
'marshal', 'posix', 'signal', 'sys',
'_thread', 'zipimport') or
(file.startswith(basedir) and
diff --git a/Lib/runpy.py b/Lib/runpy.py
index 54fc136..42f896c 100644
--- a/Lib/runpy.py
+++ b/Lib/runpy.py
@@ -279,12 +279,7 @@ def run_path(path_name, init_globals=None, run_name=None):
pkg_name = run_name.rpartition(".")[0]
from pkgutil import get_importer
importer = get_importer(path_name)
- # Trying to avoid importing imp so as to not consume the deprecation warning.
- is_NullImporter = False
- if type(importer).__module__ == 'imp':
- if type(importer).__name__ == 'NullImporter':
- is_NullImporter = True
- if isinstance(importer, type(None)) or is_NullImporter:
+ if isinstance(importer, type(None)):
# Not a valid sys.path entry, so run the code directly
# execfile() doesn't help as we want to allow compiled files
code, fname = _get_code_from_file(run_name, path_name)
diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py
deleted file mode 100644
index 80abc72..0000000
--- a/Lib/test/test_imp.py
+++ /dev/null
@@ -1,524 +0,0 @@
-import gc
-import importlib
-import importlib.util
-import os
-import os.path
-import py_compile
-import sys
-from test import support
-from test.support import import_helper
-from test.support import os_helper
-from test.support import script_helper
-from test.support import warnings_helper
-import unittest
-import warnings
-imp = warnings_helper.import_deprecated('imp')
-import _imp
-
-
-OS_PATH_NAME = os.path.__name__
-
-
-def requires_load_dynamic(meth):
- """Decorator to skip a test if not running under CPython or lacking
- imp.load_dynamic()."""
- meth = support.cpython_only(meth)
- return unittest.skipIf(getattr(imp, 'load_dynamic', None) is None,
- 'imp.load_dynamic() required')(meth)
-
-
-class LockTests(unittest.TestCase):
-
- """Very basic test of import lock functions."""
-
- def verify_lock_state(self, expected):
- self.assertEqual(imp.lock_held(), expected,
- "expected imp.lock_held() to be %r" % expected)
- def testLock(self):
- LOOPS = 50
-
- # The import lock may already be held, e.g. if the test suite is run
- # via "import test.autotest".
- lock_held_at_start = imp.lock_held()
- self.verify_lock_state(lock_held_at_start)
-
- for i in range(LOOPS):
- imp.acquire_lock()
- self.verify_lock_state(True)
-
- for i in range(LOOPS):
- imp.release_lock()
-
- # The original state should be restored now.
- self.verify_lock_state(lock_held_at_start)
-
- if not lock_held_at_start:
- try:
- imp.release_lock()
- except RuntimeError:
- pass
- else:
- self.fail("release_lock() without lock should raise "
- "RuntimeError")
-
-class ImportTests(unittest.TestCase):
- def setUp(self):
- mod = importlib.import_module('test.encoded_modules')
- self.test_strings = mod.test_strings
- self.test_path = mod.__path__
-
- # test_import_encoded_module moved to test_source_encoding.py
-
- def test_find_module_encoding(self):
- for mod, encoding, _ in self.test_strings:
- with imp.find_module('module_' + mod, self.test_path)[0] as fd:
- self.assertEqual(fd.encoding, encoding)
-
- path = [os.path.dirname(__file__)]
- with self.assertRaises(SyntaxError):
- imp.find_module('badsyntax_pep3120', path)
-
- def test_issue1267(self):
- for mod, encoding, _ in self.test_strings:
- fp, filename, info = imp.find_module('module_' + mod,
- self.test_path)
- with fp:
- self.assertNotEqual(fp, None)
- self.assertEqual(fp.encoding, encoding)
- self.assertEqual(fp.tell(), 0)
- self.assertEqual(fp.readline(), '# test %s encoding\n'
- % encoding)
-
- fp, filename, info = imp.find_module("tokenize")
- with fp:
- self.assertNotEqual(fp, None)
- self.assertEqual(fp.encoding, "utf-8")
- self.assertEqual(fp.tell(), 0)
- self.assertEqual(fp.readline(),
- '"""Tokenization help for Python programs.\n')
-
- def test_issue3594(self):
- temp_mod_name = 'test_imp_helper'
- sys.path.insert(0, '.')
- try:
- with open(temp_mod_name + '.py', 'w', encoding="latin-1") as file:
- file.write("# coding: cp1252\nu = 'test.test_imp'\n")
- file, filename, info = imp.find_module(temp_mod_name)
- file.close()
- self.assertEqual(file.encoding, 'cp1252')
- finally:
- del sys.path[0]
- os_helper.unlink(temp_mod_name + '.py')
- os_helper.unlink(temp_mod_name + '.pyc')
-
- def test_issue5604(self):
- # Test cannot cover imp.load_compiled function.
- # Martin von Loewis note what shared library cannot have non-ascii
- # character because init_xxx function cannot be compiled
- # and issue never happens for dynamic modules.
- # But sources modified to follow generic way for processing paths.
-
- # the return encoding could be uppercase or None
- fs_encoding = sys.getfilesystemencoding()
-
- # covers utf-8 and Windows ANSI code pages
- # one non-space symbol from every page
- # (http://en.wikipedia.org/wiki/Code_page)
- known_locales = {
- 'utf-8' : b'\xc3\xa4',
- 'cp1250' : b'\x8C',
- 'cp1251' : b'\xc0',
- 'cp1252' : b'\xc0',
- 'cp1253' : b'\xc1',
- 'cp1254' : b'\xc0',
- 'cp1255' : b'\xe0',
- 'cp1256' : b'\xe0',
- 'cp1257' : b'\xc0',
- 'cp1258' : b'\xc0',
- }
-
- if sys.platform == 'darwin':
- self.assertEqual(fs_encoding, 'utf-8')
- # Mac OS X uses the Normal Form D decomposition
- # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
- special_char = b'a\xcc\x88'
- else:
- special_char = known_locales.get(fs_encoding)
-
- if not special_char:
- self.skipTest("can't run this test with %s as filesystem encoding"
- % fs_encoding)
- decoded_char = special_char.decode(fs_encoding)
- temp_mod_name = 'test_imp_helper_' + decoded_char
- test_package_name = 'test_imp_helper_package_' + decoded_char
- init_file_name = os.path.join(test_package_name, '__init__.py')
- try:
- # if the curdir is not in sys.path the test fails when run with
- # ./python ./Lib/test/regrtest.py test_imp
- sys.path.insert(0, os.curdir)
- with open(temp_mod_name + '.py', 'w', encoding="utf-8") as file:
- file.write('a = 1\n')
- file, filename, info = imp.find_module(temp_mod_name)
- with file:
- self.assertIsNotNone(file)
- self.assertTrue(filename[:-3].endswith(temp_mod_name))
- self.assertEqual(info[0], '.py')
- self.assertEqual(info[1], 'r')
- self.assertEqual(info[2], imp.PY_SOURCE)
-
- mod = imp.load_module(temp_mod_name, file, filename, info)
- self.assertEqual(mod.a, 1)
-
- with warnings.catch_warnings():
- warnings.simplefilter('ignore')
- mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
- self.assertEqual(mod.a, 1)
-
- with warnings.catch_warnings():
- warnings.simplefilter('ignore')
- if not sys.dont_write_bytecode:
- mod = imp.load_compiled(
- temp_mod_name,
- imp.cache_from_source(temp_mod_name + '.py'))
- self.assertEqual(mod.a, 1)
-
- if not os.path.exists(test_package_name):
- os.mkdir(test_package_name)
- with open(init_file_name, 'w', encoding="utf-8") as file:
- file.write('b = 2\n')
- with warnings.catch_warnings():
- warnings.simplefilter('ignore')
- package = imp.load_package(test_package_name, test_package_name)
- self.assertEqual(package.b, 2)
- finally:
- del sys.path[0]
- for ext in ('.py', '.pyc'):
- os_helper.unlink(temp_mod_name + ext)
- os_helper.unlink(init_file_name + ext)
- os_helper.rmtree(test_package_name)
- os_helper.rmtree('__pycache__')
-
- def test_issue9319(self):
- path = os.path.dirname(__file__)
- self.assertRaises(SyntaxError,
- imp.find_module, "badsyntax_pep3120", [path])
-
- def test_load_from_source(self):
- # Verify that the imp module can correctly load and find .py files
- # XXX (ncoghlan): It would be nice to use import_helper.CleanImport
- # here, but that breaks because the os module registers some
- # handlers in copy_reg on import. Since CleanImport doesn't
- # revert that registration, the module is left in a broken
- # state after reversion. Reinitialising the module contents
- # and just reverting os.environ to its previous state is an OK
- # workaround
- with import_helper.CleanImport('os', 'os.path', OS_PATH_NAME):
- import os
- orig_path = os.path
- orig_getenv = os.getenv
- with os_helper.EnvironmentVarGuard():
- x = imp.find_module("os")
- self.addCleanup(x[0].close)
- new_os = imp.load_module("os", *x)
- self.assertIs(os, new_os)
- self.assertIs(orig_path, new_os.path)
- self.assertIsNot(orig_getenv, new_os.getenv)
-
- @requires_load_dynamic
- def test_issue15828_load_extensions(self):
- # Issue 15828 picked up that the adapter between the old imp API
- # and importlib couldn't handle C extensions
- example = "_heapq"
- x = imp.find_module(example)
- file_ = x[0]
- if file_ is not None:
- self.addCleanup(file_.close)
- mod = imp.load_module(example, *x)
- self.assertEqual(mod.__name__, example)
-
- @requires_load_dynamic
- def test_issue16421_multiple_modules_in_one_dll(self):
- # Issue 16421: loading several modules from the same compiled file fails
- m = '_testimportmultiple'
- fileobj, pathname, description = imp.find_module(m)
- fileobj.close()
- mod0 = imp.load_dynamic(m, pathname)
- mod1 = imp.load_dynamic('_testimportmultiple_foo', pathname)
- mod2 = imp.load_dynamic('_testimportmultiple_bar', pathname)
- self.assertEqual(mod0.__name__, m)
- self.assertEqual(mod1.__name__, '_testimportmultiple_foo')
- self.assertEqual(mod2.__name__, '_testimportmultiple_bar')
- with self.assertRaises(ImportError):
- imp.load_dynamic('nonexistent', pathname)
-
- @requires_load_dynamic
- def test_load_dynamic_ImportError_path(self):
- # Issue #1559549 added `name` and `path` attributes to ImportError
- # in order to provide better detail. Issue #10854 implemented those
- # attributes on import failures of extensions on Windows.
- path = 'bogus file path'
- name = 'extension'
- with self.assertRaises(ImportError) as err:
- imp.load_dynamic(name, path)
- self.assertIn(path, err.exception.path)
- self.assertEqual(name, err.exception.name)
-
- @requires_load_dynamic
- def test_load_module_extension_file_is_None(self):
- # When loading an extension module and the file is None, open one
- # on the behalf of imp.load_dynamic().
- # Issue #15902
- name = '_testimportmultiple'
- found = imp.find_module(name)
- if found[0] is not None:
- found[0].close()
- if found[2][2] != imp.C_EXTENSION:
- self.skipTest("found module doesn't appear to be a C extension")
- imp.load_module(name, None, *found[1:])
-
- @requires_load_dynamic
- def test_issue24748_load_module_skips_sys_modules_check(self):
- name = 'test.imp_dummy'
- try:
- del sys.modules[name]
- except KeyError:
- pass
- try:
- module = importlib.import_module(name)
- spec = importlib.util.find_spec('_testmultiphase')
- module = imp.load_dynamic(name, spec.origin)
- self.assertEqual(module.__name__, name)
- self.assertEqual(module.__spec__.name, name)
- self.assertEqual(module.__spec__.origin, spec.origin)
- self.assertRaises(AttributeError, getattr, module, 'dummy_name')
- self.assertEqual(module.int_const, 1969)
- self.assertIs(sys.modules[name], module)
- finally:
- try:
- del sys.modules[name]
- except KeyError:
- pass
-
- @unittest.skipIf(sys.dont_write_bytecode,
- "test meaningful only when writing bytecode")
- def test_bug7732(self):
- with os_helper.temp_cwd():
- source = os_helper.TESTFN + '.py'
- os.mkdir(source)
- self.assertRaisesRegex(ImportError, '^No module',
- imp.find_module, os_helper.TESTFN, ["."])
-
- def test_multiple_calls_to_get_data(self):
- # Issue #18755: make sure multiple calls to get_data() can succeed.
- loader = imp._LoadSourceCompatibility('imp', imp.__file__,
- open(imp.__file__, encoding="utf-8"))
- loader.get_data(imp.__file__) # File should be closed
- loader.get_data(imp.__file__) # Will need to create a newly opened file
-
- def test_load_source(self):
- # Create a temporary module since load_source(name) modifies
- # sys.modules[name] attributes like __loader___
- modname = f"tmp{__name__}"
- mod = type(sys.modules[__name__])(modname)
- with support.swap_item(sys.modules, modname, mod):
- with self.assertRaisesRegex(ValueError, 'embedded null'):
- imp.load_source(modname, __file__ + "\0")
-
- @support.cpython_only
- def test_issue31315(self):
- # There shouldn't be an assertion failure in imp.create_dynamic(),
- # when spec.name is not a string.
- create_dynamic = support.get_attribute(imp, 'create_dynamic')
- class BadSpec:
- name = None
- origin = 'foo'
- with self.assertRaises(TypeError):
- create_dynamic(BadSpec())
-
- def test_issue_35321(self):
- # Both _frozen_importlib and _frozen_importlib_external
- # should have a spec origin of "frozen" and
- # no need to clean up imports in this case.
-
- import _frozen_importlib_external
- self.assertEqual(_frozen_importlib_external.__spec__.origin, "frozen")
-
- import _frozen_importlib
- self.assertEqual(_frozen_importlib.__spec__.origin, "frozen")
-
- def test_source_hash(self):
- self.assertEqual(_imp.source_hash(42, b'hi'), b'\xfb\xd9G\x05\xaf$\x9b~')
- self.assertEqual(_imp.source_hash(43, b'hi'), b'\xd0/\x87C\xccC\xff\xe2')
-
- def test_pyc_invalidation_mode_from_cmdline(self):
- cases = [
- ([], "default"),
- (["--check-hash-based-pycs", "default"], "default"),
- (["--check-hash-based-pycs", "always"], "always"),
- (["--check-hash-based-pycs", "never"], "never"),
- ]
- for interp_args, expected in cases:
- args = interp_args + [
- "-c",
- "import _imp; print(_imp.check_hash_based_pycs)",
- ]
- res = script_helper.assert_python_ok(*args)
- self.assertEqual(res.out.strip().decode('utf-8'), expected)
-
- def test_find_and_load_checked_pyc(self):
- # issue 34056
- with os_helper.temp_cwd():
- with open('mymod.py', 'wb') as fp:
- fp.write(b'x = 42\n')
- py_compile.compile(
- 'mymod.py',
- doraise=True,
- invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH,
- )
- file, path, description = imp.find_module('mymod', path=['.'])
- mod = imp.load_module('mymod', file, path, description)
- self.assertEqual(mod.x, 42)
-
- def test_issue98354(self):
- # _imp.create_builtin should raise TypeError
- # if 'name' attribute of 'spec' argument is not a 'str' instance
-
- create_builtin = support.get_attribute(_imp, "create_builtin")
-
- class FakeSpec:
- def __init__(self, name):
- self.name = self
- spec = FakeSpec("time")
- with self.assertRaises(TypeError):
- create_builtin(spec)
-
- class FakeSpec2:
- name = [1, 2, 3, 4]
- spec = FakeSpec2()
- with self.assertRaises(TypeError):
- create_builtin(spec)
-
- import builtins
- class UnicodeSubclass(str):
- pass
- class GoodSpec:
- name = UnicodeSubclass("builtins")
- spec = GoodSpec()
- bltin = create_builtin(spec)
- self.assertEqual(bltin, builtins)
-
- class UnicodeSubclassFakeSpec(str):
- def __init__(self, name):
- self.name = self
- spec = UnicodeSubclassFakeSpec("builtins")
- bltin = create_builtin(spec)
- self.assertEqual(bltin, builtins)
-
- @support.cpython_only
- def test_create_builtin_subinterp(self):
- # gh-99578: create_builtin() behavior changes after the creation of the
- # first sub-interpreter. Test both code paths, before and after the
- # creation of a sub-interpreter. Previously, create_builtin() had
- # a reference leak after the creation of the first sub-interpreter.
-
- import builtins
- create_builtin = support.get_attribute(_imp, "create_builtin")
- class Spec:
- name = "builtins"
- spec = Spec()
-
- def check_get_builtins():
- refcnt = sys.getrefcount(builtins)
- mod = _imp.create_builtin(spec)
- self.assertIs(mod, builtins)
- self.assertEqual(sys.getrefcount(builtins), refcnt + 1)
- # Check that a GC collection doesn't crash
- gc.collect()
-
- check_get_builtins()
-
- ret = support.run_in_subinterp("import builtins")
- self.assertEqual(ret, 0)
-
- check_get_builtins()
-
-
-class ReloadTests(unittest.TestCase):
-
- """Very basic tests to make sure that imp.reload() operates just like
- reload()."""
-
- def test_source(self):
- # XXX (ncoghlan): It would be nice to use test.import_helper.CleanImport
- # here, but that breaks because the os module registers some
- # handlers in copy_reg on import. Since CleanImport doesn't
- # revert that registration, the module is left in a broken
- # state after reversion. Reinitialising the module contents
- # and just reverting os.environ to its previous state is an OK
- # workaround
- with os_helper.EnvironmentVarGuard():
- import os
- imp.reload(os)
-
- def test_extension(self):
- with import_helper.CleanImport('time'):
- import time
- imp.reload(time)
-
- def test_builtin(self):
- with import_helper.CleanImport('marshal'):
- import marshal
- imp.reload(marshal)
-
- def test_with_deleted_parent(self):
- # see #18681
- from html import parser
- html = sys.modules.pop('html')
- def cleanup():
- sys.modules['html'] = html
- self.addCleanup(cleanup)
- with self.assertRaisesRegex(ImportError, 'html'):
- imp.reload(parser)
-
-
-class PEP3147Tests(unittest.TestCase):
- """Tests of PEP 3147."""
-
- tag = imp.get_tag()
-
- @unittest.skipUnless(sys.implementation.cache_tag is not None,
- 'requires sys.implementation.cache_tag not be None')
- def test_cache_from_source(self):
- # Given the path to a .py file, return the path to its PEP 3147
- # 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.{}.pyc'.format(self.tag))
- self.assertEqual(imp.cache_from_source(path, True), expect)
-
- @unittest.skipUnless(sys.implementation.cache_tag is not None,
- 'requires sys.implementation.cache_tag to not be '
- 'None')
- def test_source_from_cache(self):
- # Given the path to a PEP 3147 defined .pyc file, return the path to
- # its source. This tests the good path.
- path = os.path.join('foo', 'bar', 'baz', '__pycache__',
- 'qux.{}.pyc'.format(self.tag))
- expect = os.path.join('foo', 'bar', 'baz', 'qux.py')
- self.assertEqual(imp.source_from_cache(path), expect)
-
-
-class NullImporterTests(unittest.TestCase):
- @unittest.skipIf(os_helper.TESTFN_UNENCODABLE is None,
- "Need an undecodeable filename")
- def test_unencodeable(self):
- name = os_helper.TESTFN_UNENCODABLE
- os.mkdir(name)
- try:
- self.assertRaises(ImportError, imp.NullImporter, name)
- finally:
- os.rmdir(name)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py
index 9032fd1..e348733 100644
--- a/Lib/test/test_importlib/util.py
+++ b/Lib/test/test_importlib/util.py
@@ -131,9 +131,8 @@ def uncache(*names):
"""
for name in names:
- if name in ('sys', 'marshal', 'imp'):
- raise ValueError(
- "cannot uncache {0}".format(name))
+ if name in ('sys', 'marshal'):
+ raise ValueError("cannot uncache {}".format(name))
try:
del sys.modules[name]
except KeyError:
diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py
index 0cc99e0..4d9f5db 100644
--- a/Lib/test/test_pkgutil.py
+++ b/Lib/test/test_pkgutil.py
@@ -541,14 +541,6 @@ class ImportlibMigrationTests(unittest.TestCase):
"Python 3.12; use 'importlib' instead",
DeprecationWarning))
- def test_importer_deprecated(self):
- with self.check_deprecated():
- pkgutil.ImpImporter("")
-
- def test_loader_deprecated(self):
- with self.check_deprecated():
- pkgutil.ImpLoader("", "", "", "")
-
def test_get_loader_avoids_emulation(self):
with check_warnings() as w:
self.assertIsNotNone(pkgutil.get_loader("sys"))
diff --git a/Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst b/Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst
new file mode 100644
index 0000000..f67bffc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst
@@ -0,0 +1 @@
+Remove the long-deprecated ``imp`` module.
diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c
index e34854f..cf8990a 100644
--- a/Modules/_testmultiphase.c
+++ b/Modules/_testmultiphase.c
@@ -884,15 +884,3 @@ PyInit__test_module_state_shared(void)
}
return module;
}
-
-
-/*** Helper for imp test ***/
-
-static PyModuleDef imp_dummy_def = TEST_MODULE_DEF("imp_dummy", main_slots, testexport_methods);
-
-PyMODINIT_FUNC
-PyInit_imp_dummy(void)
-{
- return PyModuleDef_Init(&imp_dummy_def);
-}
-
diff --git a/Python/import.c b/Python/import.c
index daec64e..0bf107b 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -594,11 +594,11 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
/*
It may help to have a big picture view of what happens
when an extension is loaded. This includes when it is imported
- for the first time or via imp.load_dynamic().
+ for the first time.
- Here's a summary, using imp.load_dynamic() as the starting point:
+ Here's a summary, using importlib._boostrap._load() as a starting point.
- 1. imp.load_dynamic() -> importlib._bootstrap._load()
+ 1. importlib._bootstrap._load()
2. _load(): acquire import lock
3. _load() -> importlib._bootstrap._load_unlocked()
4. _load_unlocked() -> importlib._bootstrap.module_from_spec()
@@ -3794,7 +3794,7 @@ _imp_source_hash_impl(PyObject *module, long key, Py_buffer *source)
PyDoc_STRVAR(doc_imp,
-"(Extremely) low-level import machinery bits as used by importlib and imp.");
+"(Extremely) low-level import machinery bits as used by importlib.");
static PyMethodDef imp_methods[] = {
_IMP_EXTENSION_SUFFIXES_METHODDEF
diff --git a/Python/makeopcodetargets.py b/Python/makeopcodetargets.py
index 5aa3180..2b402ae 100755
--- a/Python/makeopcodetargets.py
+++ b/Python/makeopcodetargets.py
@@ -7,24 +7,18 @@ import os
import sys
-try:
- from importlib.machinery import SourceFileLoader
-except ImportError:
- import imp
-
- def find_module(modname):
- """Finds and returns a module in the local dist/checkout.
- """
- modpath = os.path.join(
- os.path.dirname(os.path.dirname(__file__)), "Lib")
- return imp.load_module(modname, *imp.find_module(modname, [modpath]))
-else:
- def find_module(modname):
- """Finds and returns a module in the local dist/checkout.
- """
- modpath = os.path.join(
- os.path.dirname(os.path.dirname(__file__)), "Lib", modname + ".py")
- return SourceFileLoader(modname, modpath).load_module()
+# 2023-04-27(warsaw): Pre-Python 3.12, this would catch ImportErrors and try to
+# import imp, and then use imp.load_module(). The imp module was removed in
+# Python 3.12 (and long deprecated before that), and it's unclear under what
+# conditions this import will now fail, so the fallback was simply removed.
+from importlib.machinery import SourceFileLoader
+
+def find_module(modname):
+ """Finds and returns a module in the local dist/checkout.
+ """
+ modpath = os.path.join(
+ os.path.dirname(os.path.dirname(__file__)), "Lib", modname + ".py")
+ return SourceFileLoader(modname, modpath).load_module()
def write_contents(f):
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index d525fb1..ba248d2 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -2173,10 +2173,9 @@ add_main_module(PyInterpreterState *interp)
Py_DECREF(bimod);
}
- /* Main is a little special - imp.is_builtin("__main__") will return
- * False, but BuiltinImporter is still the most appropriate initial
- * setting for its __loader__ attribute. A more suitable value will
- * be set if __main__ gets further initialized later in the startup
+ /* Main is a little special - BuiltinImporter is the most appropriate
+ * initial setting for its __loader__ attribute. A more suitable value
+ * will be set if __main__ gets further initialized later in the startup
* process.
*/
loader = _PyDict_GetItemStringWithError(d, "__loader__");
diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h
index e9f0061..27f42e5 100644
--- a/Python/stdlib_module_names.h
+++ b/Python/stdlib_module_names.h
@@ -164,7 +164,6 @@ static const char* _Py_stdlib_module_names[] = {
"idlelib",
"imaplib",
"imghdr",
-"imp",
"importlib",
"inspect",
"io",
diff --git a/Tools/build/generate_stdlib_module_names.py b/Tools/build/generate_stdlib_module_names.py
index d15e5e2..7e0e960 100644
--- a/Tools/build/generate_stdlib_module_names.py
+++ b/Tools/build/generate_stdlib_module_names.py
@@ -1,5 +1,5 @@
# This script lists the names of standard library modules
-# to update Python/stdlib_mod_names.h
+# to update Python/stdlib_module_names.h
import _imp
import os.path
import re
diff --git a/Tools/c-analyzer/TODO b/Tools/c-analyzer/TODO
index 4376036..27a5358 100644
--- a/Tools/c-analyzer/TODO
+++ b/Tools/c-analyzer/TODO
@@ -495,7 +495,6 @@ Python/import.c:PyImport_ImportModuleLevelObject():PyId___path__ _Py_IDENTIFIER(
Python/import.c:PyImport_ImportModuleLevelObject():PyId___spec__ _Py_IDENTIFIER(__spec__)
Python/import.c:PyImport_ImportModuleLevelObject():PyId__handle_fromlist _Py_IDENTIFIER(_handle_fromlist)
Python/import.c:PyImport_ImportModuleLevelObject():PyId__lock_unlock_module _Py_IDENTIFIER(_lock_unlock_module)
-Python/import.c:PyImport_ReloadModule():PyId_imp _Py_IDENTIFIER(imp)
Python/import.c:PyImport_ReloadModule():PyId_reload _Py_IDENTIFIER(reload)
Python/import.c:_PyImportZip_Init():PyId_zipimporter _Py_IDENTIFIER(zipimporter)
Python/import.c:import_find_and_load():PyId__find_and_load _Py_IDENTIFIER(_find_and_load)
diff --git a/Tools/importbench/importbench.py b/Tools/importbench/importbench.py
index 6c4a537..619263b 100644
--- a/Tools/importbench/importbench.py
+++ b/Tools/importbench/importbench.py
@@ -6,7 +6,7 @@ thus has no external changes made to import-related attributes in sys.
"""
from test.test_importlib import util
import decimal
-import imp
+from importlib.util import cache_from_source
import importlib
import importlib.machinery
import json
@@ -65,7 +65,7 @@ def source_wo_bytecode(seconds, repeat):
name = '__importlib_test_benchmark__'
# Clears out sys.modules and puts an entry at the front of sys.path.
with util.create_modules(name) as mapping:
- assert not os.path.exists(imp.cache_from_source(mapping[name]))
+ assert not os.path.exists(cache_from_source(mapping[name]))
sys.meta_path.append(importlib.machinery.PathFinder)
loader = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)
@@ -80,7 +80,7 @@ def _wo_bytecode(module):
name = module.__name__
def benchmark_wo_bytecode(seconds, repeat):
"""Source w/o bytecode: {}"""
- bytecode_path = imp.cache_from_source(module.__file__)
+ bytecode_path = cache_from_source(module.__file__)
if os.path.exists(bytecode_path):
os.unlink(bytecode_path)
sys.dont_write_bytecode = True
@@ -108,9 +108,9 @@ def source_writing_bytecode(seconds, repeat):
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
def cleanup():
sys.modules.pop(name)
- os.unlink(imp.cache_from_source(mapping[name]))
+ os.unlink(cache_from_source(mapping[name]))
for result in bench(name, cleanup, repeat=repeat, seconds=seconds):
- assert not os.path.exists(imp.cache_from_source(mapping[name]))
+ assert not os.path.exists(cache_from_source(mapping[name]))
yield result
@@ -121,7 +121,7 @@ def _writing_bytecode(module):
assert not sys.dont_write_bytecode
def cleanup():
sys.modules.pop(name)
- os.unlink(imp.cache_from_source(module.__file__))
+ os.unlink(cache_from_source(module.__file__))
yield from bench(name, cleanup, repeat=repeat, seconds=seconds)
writing_bytecode_benchmark.__doc__ = (
@@ -141,7 +141,7 @@ def source_using_bytecode(seconds, repeat):
importlib.machinery.SOURCE_SUFFIXES)
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
py_compile.compile(mapping[name])
- assert os.path.exists(imp.cache_from_source(mapping[name]))
+ assert os.path.exists(cache_from_source(mapping[name]))
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
seconds=seconds)