summaryrefslogtreecommitdiff
path: root/astroid
diff options
context:
space:
mode:
authorAvram Lubkin <aviso@rockhopper.net>2023-02-12 12:21:26 -0500
committerGitHub <noreply@github.com>2023-02-12 18:21:26 +0100
commit55afe5de59b8aa3ee5fcbd98607ad90af17ca819 (patch)
tree0819a8bace1472853d95e5d5e10e4982b88c9a2b /astroid
parent3540baeb079481c5321d4936eb0f946aa7c6f755 (diff)
downloadastroid-git-55afe5de59b8aa3ee5fcbd98607ad90af17ca819.tar.gz
Replace and deprecate modutils.is_standard_module() (#2015)
Diffstat (limited to 'astroid')
-rw-r--r--astroid/_backport_stdlib_names.py356
-rw-r--r--astroid/manager.py4
-rw-r--r--astroid/modutils.py49
3 files changed, 406 insertions, 3 deletions
diff --git a/astroid/_backport_stdlib_names.py b/astroid/_backport_stdlib_names.py
new file mode 100644
index 00000000..51d6957d
--- /dev/null
+++ b/astroid/_backport_stdlib_names.py
@@ -0,0 +1,356 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
+
+"""
+Shim to support Python versions < 3.10 that don't have sys.stdlib_module_names
+
+These values were created by cherry-picking the commits from
+https://bugs.python.org/issue42955 into each version, but may be updated
+manually if changes are needed.
+"""
+
+import sys
+
+# TODO: Remove this file when Python 3.9 is no longer supported
+
+PY_3_7 = frozenset(
+ {
+ "__future__",
+ "_abc",
+ "_ast",
+ "_asyncio",
+ "_bisect",
+ "_blake2",
+ "_bootlocale",
+ "_bz2",
+ "_codecs",
+ "_codecs_cn",
+ "_codecs_hk",
+ "_codecs_iso2022",
+ "_codecs_jp",
+ "_codecs_kr",
+ "_codecs_tw",
+ "_collections",
+ "_collections_abc",
+ "_compat_pickle",
+ "_compression",
+ "_contextvars",
+ "_crypt",
+ "_csv",
+ "_ctypes",
+ "_curses",
+ "_curses_panel",
+ "_datetime",
+ "_dbm",
+ "_decimal",
+ "_dummy_thread",
+ "_elementtree",
+ "_functools",
+ "_gdbm",
+ "_hashlib",
+ "_heapq",
+ "_imp",
+ "_io",
+ "_json",
+ "_locale",
+ "_lsprof",
+ "_lzma",
+ "_markupbase",
+ "_md5",
+ "_msi",
+ "_multibytecodec",
+ "_multiprocessing",
+ "_opcode",
+ "_operator",
+ "_osx_support",
+ "_pickle",
+ "_posixsubprocess",
+ "_py_abc",
+ "_pydecimal",
+ "_pyio",
+ "_queue",
+ "_random",
+ "_sha1",
+ "_sha256",
+ "_sha3",
+ "_sha512",
+ "_signal",
+ "_sitebuiltins",
+ "_socket",
+ "_sqlite3",
+ "_sre",
+ "_ssl",
+ "_stat",
+ "_string",
+ "_strptime",
+ "_struct",
+ "_symtable",
+ "_thread",
+ "_threading_local",
+ "_tkinter",
+ "_tracemalloc",
+ "_uuid",
+ "_warnings",
+ "_weakref",
+ "_weakrefset",
+ "_winapi",
+ "abc",
+ "aifc",
+ "antigravity",
+ "argparse",
+ "array",
+ "ast",
+ "asynchat",
+ "asyncio",
+ "asyncore",
+ "atexit",
+ "audioop",
+ "base64",
+ "bdb",
+ "binascii",
+ "binhex",
+ "bisect",
+ "builtins",
+ "bz2",
+ "cProfile",
+ "calendar",
+ "cgi",
+ "cgitb",
+ "chunk",
+ "cmath",
+ "cmd",
+ "code",
+ "codecs",
+ "codeop",
+ "collections",
+ "colorsys",
+ "compileall",
+ "concurrent",
+ "configparser",
+ "contextlib",
+ "contextvars",
+ "copy",
+ "copyreg",
+ "crypt",
+ "csv",
+ "ctypes",
+ "curses",
+ "dataclasses",
+ "datetime",
+ "dbm",
+ "decimal",
+ "difflib",
+ "dis",
+ "distutils",
+ "doctest",
+ "dummy_threading",
+ "email",
+ "encodings",
+ "ensurepip",
+ "enum",
+ "errno",
+ "faulthandler",
+ "fcntl",
+ "filecmp",
+ "fileinput",
+ "fnmatch",
+ "formatter",
+ "fractions",
+ "ftplib",
+ "functools",
+ "gc",
+ "genericpath",
+ "getopt",
+ "getpass",
+ "gettext",
+ "glob",
+ "grp",
+ "gzip",
+ "hashlib",
+ "heapq",
+ "hmac",
+ "html",
+ "http",
+ "idlelib",
+ "imaplib",
+ "imghdr",
+ "imp",
+ "importlib",
+ "inspect",
+ "io",
+ "ipaddress",
+ "itertools",
+ "json",
+ "keyword",
+ "lib2to3",
+ "linecache",
+ "locale",
+ "logging",
+ "lzma",
+ "macpath",
+ "mailbox",
+ "mailcap",
+ "marshal",
+ "math",
+ "mimetypes",
+ "mmap",
+ "modulefinder",
+ "msilib",
+ "msvcrt",
+ "multiprocessing",
+ "netrc",
+ "nis",
+ "nntplib",
+ "nt",
+ "ntpath",
+ "nturl2path",
+ "numbers",
+ "opcode",
+ "operator",
+ "optparse",
+ "os",
+ "ossaudiodev",
+ "parser",
+ "pathlib",
+ "pdb",
+ "pickle",
+ "pickletools",
+ "pipes",
+ "pkgutil",
+ "platform",
+ "plistlib",
+ "poplib",
+ "posix",
+ "posixpath",
+ "pprint",
+ "profile",
+ "pstats",
+ "pty",
+ "pwd",
+ "py_compile",
+ "pyclbr",
+ "pydoc",
+ "pydoc_data",
+ "pyexpat",
+ "queue",
+ "quopri",
+ "random",
+ "re",
+ "readline",
+ "reprlib",
+ "resource",
+ "rlcompleter",
+ "runpy",
+ "sched",
+ "secrets",
+ "select",
+ "selectors",
+ "shelve",
+ "shlex",
+ "shutil",
+ "signal",
+ "site",
+ "smtpd",
+ "smtplib",
+ "sndhdr",
+ "socket",
+ "socketserver",
+ "spwd",
+ "sqlite3",
+ "sre_compile",
+ "sre_constants",
+ "sre_parse",
+ "ssl",
+ "stat",
+ "statistics",
+ "string",
+ "stringprep",
+ "struct",
+ "subprocess",
+ "sunau",
+ "symbol",
+ "symtable",
+ "sys",
+ "sysconfig",
+ "syslog",
+ "tabnanny",
+ "tarfile",
+ "telnetlib",
+ "tempfile",
+ "termios",
+ "textwrap",
+ "this",
+ "threading",
+ "time",
+ "timeit",
+ "tkinter",
+ "token",
+ "tokenize",
+ "trace",
+ "traceback",
+ "tracemalloc",
+ "tty",
+ "turtle",
+ "turtledemo",
+ "types",
+ "typing",
+ "unicodedata",
+ "unittest",
+ "urllib",
+ "uu",
+ "uuid",
+ "venv",
+ "warnings",
+ "wave",
+ "weakref",
+ "webbrowser",
+ "winreg",
+ "winsound",
+ "wsgiref",
+ "xdrlib",
+ "xml",
+ "xmlrpc",
+ "zipapp",
+ "zipfile",
+ "zipimport",
+ "zlib",
+ }
+)
+
+PY_3_8 = frozenset(
+ PY_3_7
+ - {
+ "macpath",
+ }
+ | {
+ "_posixshmem",
+ "_statistics",
+ "_xxsubinterpreters",
+ }
+)
+
+PY_3_9 = frozenset(
+ PY_3_8
+ - {
+ "_dummy_thread",
+ "dummy_threading",
+ }
+ | {
+ "_aix_support",
+ "_bootsubprocess",
+ "_peg_parser",
+ "_zoneinfo",
+ "graphlib",
+ "zoneinfo",
+ }
+)
+
+if sys.version_info[:2] == (3, 7):
+ stdlib_module_names = PY_3_7
+elif sys.version_info[:2] == (3, 8):
+ stdlib_module_names = PY_3_8
+elif sys.version_info[:2] == (3, 9):
+ stdlib_module_names = PY_3_9
+else:
+ raise AssertionError("This module is only intended as a backport for Python <= 3.9")
diff --git a/astroid/manager.py b/astroid/manager.py
index 8a5b05c7..b0cecc30 100644
--- a/astroid/manager.py
+++ b/astroid/manager.py
@@ -30,7 +30,7 @@ from astroid.modutils import (
get_source_file,
is_module_name_part_of_extension_package_whitelist,
is_python_source,
- is_standard_module,
+ is_stdlib_module,
load_module_from_name,
modpath_from_file,
)
@@ -154,7 +154,7 @@ class AstroidManager:
def _can_load_extension(self, modname: str) -> bool:
if self.always_load_extensions:
return True
- if is_standard_module(modname):
+ if is_stdlib_module(modname):
return True
return is_module_name_part_of_extension_package_whitelist(
modname, self.extension_package_whitelist
diff --git a/astroid/modutils.py b/astroid/modutils.py
index 1b5057f5..f05b5f89 100644
--- a/astroid/modutils.py
+++ b/astroid/modutils.py
@@ -26,14 +26,20 @@ import os
import sys
import sysconfig
import types
+import warnings
from collections.abc import Callable, Iterable, Sequence
from contextlib import redirect_stderr, redirect_stdout
from functools import lru_cache
from pathlib import Path
-from astroid.const import IS_JYTHON, IS_PYPY
+from astroid.const import IS_JYTHON, IS_PYPY, PY310_PLUS
from astroid.interpreter._import import spec, util
+if PY310_PLUS:
+ from sys import stdlib_module_names
+else:
+ from astroid._backport_stdlib_names import stdlib_module_names
+
logger = logging.getLogger(__name__)
@@ -510,6 +516,41 @@ def is_python_source(filename: str | None) -> bool:
return os.path.splitext(filename)[1][1:] in PY_SOURCE_EXTS
+def is_stdlib_module(modname: str) -> bool:
+ """Return: True if the modname is in the standard library"""
+ return modname.split(".")[0] in stdlib_module_names
+
+
+def module_in_path(modname: str, path: str | Iterable[str]) -> bool:
+ """Try to determine if a module is imported from one of the specified paths
+
+ :param modname: name of the module
+
+ :param path: paths to consider
+
+ :return:
+ true if the module:
+ - is located on the path listed in one of the directory in `paths`
+ """
+
+ modname = modname.split(".")[0]
+ try:
+ filename = file_from_modpath([modname])
+ except ImportError:
+ # Import failed, we can't check path if we don't know it
+ return False
+
+ if filename is None:
+ # No filename likely means it's compiled in, or potentially a namespace
+ return False
+ filename = _normalize_path(filename)
+
+ if isinstance(path, str):
+ return filename.startswith(_cache_normalize_path(path))
+
+ return any(filename.startswith(_cache_normalize_path(entry)) for entry in path)
+
+
def is_standard_module(modname: str, std_path: Iterable[str] | None = None) -> bool:
"""Try to guess if a module is a standard python module (by default,
see `std_path` parameter's description).
@@ -523,6 +564,12 @@ def is_standard_module(modname: str, std_path: Iterable[str] | None = None) -> b
- is located on the path listed in one of the directory in `std_path`
- is a built-in module
"""
+ warnings.warn(
+ "is_standard_module() is deprecated. Use, is_stdlib_module() or module_in_path() instead",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
modname = modname.split(".")[0]
try:
filename = file_from_modpath([modname])