prompt: astroid 2.9.1 breaks pylint with missing __init__.py: F0010: error while code parsing: Unable to load file __init__.py
  ### Steps to reproduce
  > Steps provided are for Windows 11, but initial problem found in Ubuntu 20.04
  
  > Update 2022-01-04: Corrected repro steps and added more environment details
  
  1. Set up simple repo with following structure (all files can be empty):
  ```
  root_dir/
  |--src/
  |----project/ # Notice the missing __init__.py
  |------file.py # It can be empty, but I added `import os` at the top
  |----__init__.py
  ```
  2. Open a command prompt
  3. `cd root_dir`
  4. `python -m venv venv`
  5. `venv/Scripts/activate`
  6. `pip install pylint astroid==2.9.1` # I also repro'd on the latest, 2.9.2
  7. `pylint src/project` # Updated from `pylint src`
  8. Observe failure:
  ```
  src\project\__init__.py:1:0: F0010: error while code parsing: Unable to load file src\project\__init__.py:
  ```
  
  ### Current behavior
  Fails with `src\project\__init__.py:1:0: F0010: error while code parsing: Unable to load file src\project\__init__.py:`
  
  ### Expected behavior
  Does not fail with error.
  > If you replace step 6 with `pip install pylint astroid==2.9.0`, you get no failure with an empty output - since no files have content
  
  ### `python -c "from astroid import __pkginfo__; print(__pkginfo__.version)"` output
  2.9.1
  
  `python 3.9.1`
  `pylint 2.12.2 `
  
  
  
  This issue has been observed with astroid `2.9.1` and `2.9.2`
  
instance: {"FAIL_TO_PASS": "[\"tests/unittest_modutils.py::ModPathFromFileTest::test_load_packages_without_init\"]", "PASS_TO_PASS": "[\"tests/unittest_modutils.py::ModuleFileTest::test_find_egg_module\", \"tests/unittest_modutils.py::ModuleFileTest::test_find_zipped_module\", \"tests/unittest_modutils.py::LoadModuleFromNameTest::test_known_values_load_module_from_name_1\", \"tests/unittest_modutils.py::LoadModuleFromNameTest::test_known_values_load_module_from_name_2\", \"tests/unittest_modutils.py::LoadModuleFromNameTest::test_raise_load_module_from_name_1\", \"tests/unittest_modutils.py::GetModulePartTest::test_get_module_part_exception\", \"tests/unittest_modutils.py::GetModulePartTest::test_known_values_get_builtin_module_part\", \"tests/unittest_modutils.py::GetModulePartTest::test_known_values_get_compiled_module_part\", \"tests/unittest_modutils.py::GetModulePartTest::test_known_values_get_module_part_1\", \"tests/unittest_modutils.py::GetModulePartTest::test_known_values_get_module_part_2\", \"tests/unittest_modutils.py::GetModulePartTest::test_known_values_get_module_part_3\", \"tests/unittest_modutils.py::ModPathFromFileTest::test_import_symlink_both_outside_of_path\", \"tests/unittest_modutils.py::ModPathFromFileTest::test_import_symlink_with_source_outside_of_path\", \"tests/unittest_modutils.py::ModPathFromFileTest::test_known_values_modpath_from_file_1\", \"tests/unittest_modutils.py::ModPathFromFileTest::test_load_from_module_symlink_on_symlinked_paths_in_syspath\", \"tests/unittest_modutils.py::ModPathFromFileTest::test_raise_modpath_from_file_exception\", \"tests/unittest_modutils.py::LoadModuleFromPathTest::test_do_not_load_twice\", \"tests/unittest_modutils.py::FileFromModPathTest::test_builtin\", \"tests/unittest_modutils.py::FileFromModPathTest::test_site_packages\", \"tests/unittest_modutils.py::FileFromModPathTest::test_std_lib\", \"tests/unittest_modutils.py::FileFromModPathTest::test_unexisting\", \"tests/unittest_modutils.py::FileFromModPathTest::test_unicode_in_package_init\", \"tests/unittest_modutils.py::GetSourceFileTest::test\", \"tests/unittest_modutils.py::GetSourceFileTest::test_raise\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_4\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_builtin\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_builtins\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_custom_path\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_datetime\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_failing_edge_cases\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_nonstandard\", \"tests/unittest_modutils.py::StandardLibModuleTest::test_unknown\", \"tests/unittest_modutils.py::IsRelativeTest::test_deep_relative\", \"tests/unittest_modutils.py::IsRelativeTest::test_deep_relative2\", \"tests/unittest_modutils.py::IsRelativeTest::test_deep_relative3\", \"tests/unittest_modutils.py::IsRelativeTest::test_deep_relative4\", \"tests/unittest_modutils.py::IsRelativeTest::test_is_relative_bad_path\", \"tests/unittest_modutils.py::IsRelativeTest::test_known_values_is_relative_1\", \"tests/unittest_modutils.py::IsRelativeTest::test_known_values_is_relative_3\", \"tests/unittest_modutils.py::IsRelativeTest::test_known_values_is_relative_4\", \"tests/unittest_modutils.py::IsRelativeTest::test_known_values_is_relative_5\", \"tests/unittest_modutils.py::GetModuleFilesTest::test_get_all_files\", \"tests/unittest_modutils.py::GetModuleFilesTest::test_get_module_files_1\", \"tests/unittest_modutils.py::GetModuleFilesTest::test_load_module_set_attribute\", \"tests/unittest_modutils.py::ExtensionPackageWhitelistTest::test_is_module_name_part_of_extension_package_whitelist_success\", \"tests/unittest_modutils.py::ExtensionPackageWhitelistTest::test_is_module_name_part_of_extension_package_whitelist_true\"]", "base_commit": "d2a5b3c7b1e203fec3c7ca73c30eb1785d3d4d0a", "created_at": "2022-01-08T19:36:45Z", "environment_setup_commit": "da745538c7236028a22cdf0405f6829fcf6886bc", "hints_text": "I can't seem to reproduce this in my `virtualenv`. This might be specific to `venv`? Needs some further investigation.\n@interifter Which version of `pylint` are you using?\nRight, ``pip install pylint astroid==2.9.0``, will keep the local version if you already have one, so I thought it was ``2.12.2`` but that could be false. In fact it probably isn't 2.12.2. For the record, you're not supposed to set the version of ``astroid`` yourself, pylint does, and bad thing will happen if you try to set the version of an incompatible astroid. We might want to update the issue's template to have this information next.\nMy apologies... I updated the repro steps with a critical missed detail: `pylint src/project`, instead of `pylint src`\r\n\r\nBut I verified that either with, or without, `venv`, the issue is reproduced.\r\n\r\nAlso, I never have specified the `astroid` version, before. \r\n\r\nHowever, this isn't the first time the issue has been observed.\r\nBack in early 2019, a [similar issue](https://stackoverflow.com/questions/48024049/pylint-raises-error-if-directory-doesnt-contain-init-py-file) was observed with either `astroid 2.2.0` or `isort 4.3.5`, which led me to try pinning `astroid==2.9.0`, which worked.\n> @interifter Which version of `pylint` are you using?\r\n\r\n`2.12.2`\r\n\r\nFull env info:\r\n\r\n```\r\nPackage           Version\r\n----------------- -------\r\nastroid           2.9.2\r\ncolorama          0.4.4\r\nisort             5.10.1\r\nlazy-object-proxy 1.7.1\r\nmccabe            0.6.1\r\npip               20.2.3\r\nplatformdirs      2.4.1\r\npylint            2.12.2\r\nsetuptools        49.2.1\r\ntoml              0.10.2\r\ntyping-extensions 4.0.1\r\nwrapt             1.13.3\r\n```\r\n\nI confirm the bug and i'm able to reproduce it with `python 3.9.1`. \r\n```\r\n$> pip freeze\r\nastroid==2.9.2\r\nisort==5.10.1\r\nlazy-object-proxy==1.7.1\r\nmccabe==0.6.1\r\nplatformdirs==2.4.1\r\npylint==2.12.2\r\ntoml==0.10.2\r\ntyping-extensions==4.0.1\r\nwrapt==1.13.3\r\n```\nBisected and this is the faulty commit:\r\nhttps://github.com/PyCQA/astroid/commit/2ee20ccdf62450db611acc4a1a7e42f407ce8a14\nFix in #1333, no time to write tests yet so if somebody has any good ideas: please let me know!", "instance_id": "pylint-dev__astroid-1333", "patch": "diff --git a/astroid/modutils.py b/astroid/modutils.py\n--- a/astroid/modutils.py\n+++ b/astroid/modutils.py\n@@ -297,6 +297,9 @@ def _get_relative_base_path(filename, path_to_check):\n     if os.path.normcase(real_filename).startswith(path_to_check):\n         importable_path = real_filename\n \n+    # if \"var\" in path_to_check:\n+    #     breakpoint()\n+\n     if importable_path:\n         base_path = os.path.splitext(importable_path)[0]\n         relative_base_path = base_path[len(path_to_check) :]\n@@ -307,8 +310,11 @@ def _get_relative_base_path(filename, path_to_check):\n \n def modpath_from_file_with_callback(filename, path=None, is_package_cb=None):\n     filename = os.path.expanduser(_path_from_filename(filename))\n+    paths_to_check = sys.path.copy()\n+    if path:\n+        paths_to_check += path\n     for pathname in itertools.chain(\n-        path or [], map(_cache_normalize_path, sys.path), sys.path\n+        paths_to_check, map(_cache_normalize_path, paths_to_check)\n     ):\n         if not pathname:\n             continue\n", "problem_statement": "astroid 2.9.1 breaks pylint with missing __init__.py: F0010: error while code parsing: Unable to load file __init__.py\n### Steps to reproduce\r\n> Steps provided are for Windows 11, but initial problem found in Ubuntu 20.04\r\n\r\n> Update 2022-01-04: Corrected repro steps and added more environment details\r\n\r\n1. Set up simple repo with following structure (all files can be empty):\r\n```\r\nroot_dir/\r\n|--src/\r\n|----project/ # Notice the missing __init__.py\r\n|------file.py # It can be empty, but I added `import os` at the top\r\n|----__init__.py\r\n```\r\n2. Open a command prompt\r\n3. `cd root_dir`\r\n4. `python -m venv venv`\r\n5. `venv/Scripts/activate`\r\n6. `pip install pylint astroid==2.9.1` # I also repro'd on the latest, 2.9.2\r\n7. `pylint src/project` # Updated from `pylint src`\r\n8. Observe failure:\r\n```\r\nsrc\\project\\__init__.py:1:0: F0010: error while code parsing: Unable to load file src\\project\\__init__.py:\r\n```\r\n\r\n### Current behavior\r\nFails with `src\\project\\__init__.py:1:0: F0010: error while code parsing: Unable to load file src\\project\\__init__.py:`\r\n\r\n### Expected behavior\r\nDoes not fail with error.\r\n> If you replace step 6 with `pip install pylint astroid==2.9.0`, you get no failure with an empty output - since no files have content\r\n\r\n### `python -c \"from astroid import __pkginfo__; print(__pkginfo__.version)\"` output\r\n2.9.1\r\n\r\n`python 3.9.1`\r\n`pylint 2.12.2 `\r\n\r\n\r\n\r\nThis issue has been observed with astroid `2.9.1` and `2.9.2`\n", "repo": "pylint-dev/astroid", "test_patch": "diff --git a/tests/unittest_modutils.py b/tests/unittest_modutils.py\n--- a/tests/unittest_modutils.py\n+++ b/tests/unittest_modutils.py\n@@ -30,6 +30,7 @@\n import tempfile\n import unittest\n import xml\n+from pathlib import Path\n from xml import etree\n from xml.etree import ElementTree\n \n@@ -189,6 +190,30 @@ def test_load_from_module_symlink_on_symlinked_paths_in_syspath(self) -> None:\n         # this should be equivalent to: import secret\n         self.assertEqual(modutils.modpath_from_file(symlink_secret_path), [\"secret\"])\n \n+    def test_load_packages_without_init(self) -> None:\n+        \"\"\"Test that we correctly find packages with an __init__.py file.\n+\n+        Regression test for issue reported in:\n+        https://github.com/PyCQA/astroid/issues/1327\n+        \"\"\"\n+        tmp_dir = Path(tempfile.gettempdir())\n+        self.addCleanup(os.chdir, os.curdir)\n+        os.chdir(tmp_dir)\n+\n+        self.addCleanup(shutil.rmtree, tmp_dir / \"src\")\n+        os.mkdir(tmp_dir / \"src\")\n+        os.mkdir(tmp_dir / \"src\" / \"package\")\n+        with open(tmp_dir / \"src\" / \"__init__.py\", \"w\", encoding=\"utf-8\"):\n+            pass\n+        with open(tmp_dir / \"src\" / \"package\" / \"file.py\", \"w\", encoding=\"utf-8\"):\n+            pass\n+\n+        # this should be equivalent to: import secret\n+        self.assertEqual(\n+            modutils.modpath_from_file(str(Path(\"src\") / \"package\"), [\".\"]),\n+            [\"src\", \"package\"],\n+        )\n+\n \n class LoadModuleFromPathTest(resources.SysPathSetup, unittest.TestCase):\n     def test_do_not_load_twice(self) -> None:\n", "version": "2.10"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"# Copyright (c) 2014-2018, 2020 Claudiu Popa <pcmanticore@gmail.com>\n# Copyright (c) 2014 Google, Inc.\n# Copyright (c) 2014 Denis Laxalde <denis.laxalde@logilab.fr>\n# Copyright (c) 2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>\n# Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com>\n# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>\n# Copyright (c) 2015 Radosław Ganczarek <radoslaw@ganczarek.in>\n# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>\n# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>\n# Copyright (c) 2016 Ceridwen <ceridwenv@gmail.com>\n# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi>\n# Copyright (c) 2018 Mario Corchero <mcorcherojim@bloomberg.net>\n# Copyright (c) 2018 Mario Corchero <mariocj89@gmail.com>\n# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>\n# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com>\n# Copyright (c) 2019 markmcclain <markmcclain@users.noreply.github.com>\n# Copyright (c) 2019 BasPH <BasPH@users.noreply.github.com>\n# Copyright (c) 2020-2021 hippo91 <guillaume.peillex@gmail.com>\n# Copyright (c) 2020 Peter Kolbus <peter.kolbus@gmail.com>\n# Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com>\n# Copyright (c) 2021 Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>\n# Copyright (c) 2021 Keichi Takahashi <hello@keichi.dev>\n# Copyright (c) 2021 Nick Drozd <nicholasdrozd@gmail.com>\n# Copyright (c) 2021 Marc Mueller <30130371+cdce8p@users.noreply.github.com>\n# Copyright (c) 2021 DudeNr33 <3929834+DudeNr33@users.noreply.github.com>\n\n# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html\n# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE\n\n\"\"\"Python modules manipulation utility functions.\n\n:type PY_SOURCE_EXTS: tuple(str)\n:var PY_SOURCE_EXTS: list of possible python source file extension\n\n:type STD_LIB_DIRS: set of str\n:var STD_LIB_DIRS: directories where standard modules are located\n\n:type BUILTIN_MODULES: dict\n:var BUILTIN_MODULES: dictionary with builtin module names has key\n\"\"\"\n\n# We disable the import-error so pylint can work without distutils installed.\n# pylint: disable=no-name-in-module,useless-suppression\n\nimport importlib\nimport importlib.machinery\nimport importlib.util\nimport itertools\nimport os\nimport platform\nimport sys\nimport types\nfrom distutils.errors import DistutilsPlatformError  # pylint: disable=import-error\nfrom distutils.sysconfig import get_python_lib  # pylint: disable=import-error\nfrom typing import Dict, Set\n\nfrom astroid.interpreter._import import spec, util\n\n# distutils is replaced by virtualenv with a module that does\n# weird path manipulations in order to get to the\n# real distutils module.\n\n\nif sys.platform.startswith(\"win\"):\n    PY_SOURCE_EXTS = (\"py\", \"pyw\")\n    PY_COMPILED_EXTS = (\"dll\", \"pyd\")\nelse:\n    PY_SOURCE_EXTS = (\"py\",)\n    PY_COMPILED_EXTS = (\"so\",)\n\n\ntry:\n    # The explicit sys.prefix is to work around a patch in virtualenv that\n    # replaces the 'real' sys.prefix (i.e. the location of the binary)\n    # with the prefix from which the virtualenv was created. This throws\n    # off the detection logic for standard library modules, thus the\n    # workaround.\n    STD_LIB_DIRS = {\n        get_python_lib(standard_lib=True, prefix=sys.prefix),\n        # Take care of installations where exec_prefix != prefix.\n        get_python_lib(standard_lib=True, prefix=sys.exec_prefix),\n        get_python_lib(standard_lib=True),\n    }\n# get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to\n# non-valid path, see https://bugs.pypy.org/issue1164\nexcept DistutilsPlatformError:\n    STD_LIB_DIRS = set()\n\nif os.name == \"nt\":\n    STD_LIB_DIRS.add(os.path.join(sys.prefix, \"dlls\"))\n    try:\n        # real_prefix is defined when running inside virtual environments,\n        # created with the **virtualenv** library.\n        # Deprecated in virtualenv==16.7.9\n        # See: https://github.com/pypa/virtualenv/issues/1622\n        STD_LIB_DIRS.add(os.path.join(sys.real_prefix, \"dlls\"))  # type: ignore[attr-defined]\n    except AttributeError:\n        # sys.base_exec_prefix is always defined, but in a virtual environment\n        # created with the stdlib **venv** module, it points to the original\n        # installation, if the virtual env is activated.\n        try:\n            STD_LIB_DIRS.add(os.path.join(sys.base_exec_prefix, \"dlls\"))\n        except AttributeError:\n            pass\n\nif platform.python_implementation() == \"PyPy\":\n    # The get_python_lib(standard_lib=True) function does not give valid\n    # result with pypy in a virtualenv.\n    # In a virtual environment, with CPython implementation the call to this function returns a path toward\n    # the binary (its libraries) which has been used to create the virtual environment.\n    # Not with pypy implementation.\n    # The only way to retrieve such information is to use the sys.base_prefix hint.\n    # It's worth noticing that under CPython implementation the return values of\n    # get_python_lib(standard_lib=True) and get_python_lib(santdard_lib=True, prefix=sys.base_prefix)\n    # are the same.\n    # In the lines above, we could have replace the call to get_python_lib(standard=True)\n    # with the one using prefix=sys.base_prefix but we prefer modifying only what deals with pypy.\n    STD_LIB_DIRS.add(get_python_lib(standard_lib=True, prefix=sys.base_prefix))\n    _root = os.path.join(sys.prefix, \"lib_pypy\")\n    STD_LIB_DIRS.add(_root)\n    try:\n        # real_prefix is defined when running inside virtualenv.\n        STD_LIB_DIRS.add(os.path.join(sys.base_prefix, \"lib_pypy\"))\n    except AttributeError:\n        pass\n    del _root\nif os.name == \"posix\":\n    # Need the real prefix if we're in a virtualenv, otherwise\n    # the usual one will do.\n    # Deprecated in virtualenv==16.7.9\n    # See: https://github.com/pypa/virtualenv/issues/1622\n    try:\n        prefix = sys.real_prefix  # type: ignore[attr-defined]\n    except AttributeError:\n        prefix = sys.prefix\n\n    def _posix_path(path):\n        base_python = \"python%d.%d\" % sys.version_info[:2]\n        return os.path.join(prefix, path, base_python)\n\n    STD_LIB_DIRS.add(_posix_path(\"lib\"))\n    if sys.maxsize > 2 ** 32:\n        # This tries to fix a problem with /usr/lib64 builds,\n        # where systems are running both 32-bit and 64-bit code\n        # on the same machine, which reflects into the places where\n        # standard library could be found. More details can be found\n        # here http://bugs.python.org/issue1294959.\n        # An easy reproducing case would be\n        # https://github.com/PyCQA/pylint/issues/712#issuecomment-163178753\n        STD_LIB_DIRS.add(_posix_path(\"lib64\"))\n\nEXT_LIB_DIRS = {get_python_lib(), get_python_lib(True)}\nIS_JYTHON = platform.python_implementation() == \"Jython\"\nBUILTIN_MODULES = dict.fromkeys(sys.builtin_module_names, True)\n\n\nclass NoSourceFile(Exception):\n    \"\"\"exception raised when we are not able to get a python\n    source file for a precompiled file\n    \"\"\"\n\n\ndef _normalize_path(path: str) -> str:\n    \"\"\"Resolve symlinks in path and convert to absolute path.\n\n    Note that environment variables and ~ in the path need to be expanded in\n    advance.\n\n    This can be cached by using _cache_normalize_path.\n    \"\"\"\n    return os.path.normcase(os.path.realpath(path))\n\n\ndef _path_from_filename(filename, is_jython=IS_JYTHON):\n    if not is_jython:\n        return filename\n    head, has_pyclass, _ = filename.partition(\"$py.class\")\n    if has_pyclass:\n        return head + \".py\"\n    return filename\n\n\ndef _handle_blacklist(blacklist, dirnames, filenames):\n    \"\"\"remove files/directories in the black list\n\n    dirnames/filenames are usually from os.walk\n    \"\"\"\n    for norecurs in blacklist:\n        if norecurs in dirnames:\n            dirnames.remove(norecurs)\n        elif norecurs in filenames:\n            filenames.remove(norecurs)\n\n\n_NORM_PATH_CACHE: Dict[str, str] = {}\n\n\ndef _cache_normalize_path(path: str) -> str:\n    \"\"\"Normalize path with caching.\"\"\"\n    # _module_file calls abspath on every path in sys.path every time it's\n    # called; on a larger codebase this easily adds up to half a second just\n    # assembling path components. This cache alleviates that.\n    try:\n        return _NORM_PATH_CACHE[path]\n    except KeyError:\n        if not path:  # don't cache result for ''\n            return _normalize_path(path)\n        result = _NORM_PATH_CACHE[path] = _normalize_path(path)\n        return result\n\n\ndef load_module_from_name(dotted_name: str) -> types.ModuleType:\n    \"\"\"Load a Python module from its name.\n\n    :type dotted_name: str\n    :param dotted_name: python name of a module or package\n\n    :raise ImportError: if the module or package is not found\n\n    :rtype: module\n    :return: the loaded module\n    \"\"\"\n    try:\n        return sys.modules[dotted_name]\n    except KeyError:\n        pass\n\n    return importlib.import_module(dotted_name)\n\n\ndef load_module_from_modpath(parts):\n    \"\"\"Load a python module from its split name.\n\n    :type parts: list(str) or tuple(str)\n    :param parts:\n      python name of a module or package split on '.'\n\n    :raise ImportError: if the module or package is not found\n\n    :rtype: module\n    :return: the loaded module\n    \"\"\"\n    return load_module_from_name(\".\".join(parts))\n\n\ndef load_module_from_file(filepath: str):\n    \"\"\"Load a Python module from it's path.\n\n    :type filepath: str\n    :param filepath: path to the python module or package\n\n    :raise ImportError: if the module or package is not found\n\n    :rtype: module\n    :return: the loaded module\n    \"\"\"\n    modpath = modpath_from_file(filepath)\n    return load_module_from_modpath(modpath)\n\n\ndef check_modpath_has_init(path, mod_path):\n    \"\"\"check there are some __init__.py all along the way\"\"\"\n    modpath = []\n    for part in mod_path:\n        modpath.append(part)\n        path = os.path.join(path, part)\n        if not _has_init(path):\n            old_namespace = util.is_namespace(\".\".join(modpath))\n            if not old_namespace:\n                return False\n    return True\n\n\ndef _get_relative_base_path(filename, path_to_check):\n    \"\"\"Extracts the relative mod path of the file to import from\n\n    Check if a file is within the passed in path and if so, returns the\n    relative mod path from the one passed in.\n\n    If the filename is no in path_to_check, returns None\n\n    Note this function will look for both abs and realpath of the file,\n    this allows to find the relative base path even if the file is a\n    symlink of a file in the passed in path\n\n    Examples:\n        _get_relative_base_path(\"/a/b/c/d.py\", \"/a/b\") ->  [\"c\",\"d\"]\n        _get_relative_base_path(\"/a/b/c/d.py\", \"/dev\") ->  None\n    \"\"\"\n    importable_path = None\n    path_to_check = os.path.normcase(path_to_check)\n    abs_filename = os.path.abspath(filename)\n    if os.path.normcase(abs_filename).startswith(path_to_check):\n        importable_path = abs_filename\n\n    real_filename = os.path.realpath(filename)\n    if os.path.normcase(real_filename).startswith(path_to_check):\n        importable_path = real_filename\n\n    if importable_path:\n        base_path = os.path.splitext(importable_path)[0]\n        relative_base_path = base_path[len(path_to_check) :]\n        return [pkg for pkg in relative_base_path.split(os.sep) if pkg]\n\n    return None\n\n\ndef modpath_from_file_with_callback(filename, path=None, is_package_cb=None):\n    filename = os.path.expanduser(_path_from_filename(filename))\n    for pathname in itertools.chain(\n        path or [], map(_cache_normalize_path, sys.path), sys.path\n    ):\n        if not pathname:\n            continue\n        modpath = _get_relative_base_path(filename, pathname)\n        if not modpath:\n            continue\n        if is_package_cb(pathname, modpath[:-1]):\n            return modpath\n\n    raise ImportError(\n        \"Unable to find module for {} in {}\".format(filename, \", \\n\".join(sys.path))\n    )\n\n\ndef modpath_from_file(filename, path=None):\n    \"\"\"Get the corresponding split module's name from a filename\n\n    This function will return the name of a module or package split on `.`.\n\n    :type filename: str\n    :param filename: file's path for which we want the module's name\n\n    :type Optional[List[str]] path:\n      Optional list of path where the module or package should be\n      searched (use sys.path if nothing or None is given)\n\n    :raise ImportError:\n      if the corresponding module's name has not been found\n\n    :rtype: list(str)\n    :return: the corresponding split module's name\n    \"\"\"\n    return modpath_from_file_with_callback(filename, path, check_modpath_has_init)\n\n\ndef file_from_modpath(modpath, path=None, context_file=None):\n    return file_info_from_modpath(modpath, path, context_file).location\n\n\ndef file_info_from_modpath(modpath, path=None, context_file=None):\n    \"\"\"given a mod path (i.e. split module / package name), return the\n    corresponding file, giving priority to source file over precompiled\n    file if it exists\n\n    :type modpath: list or tuple\n    :param modpath:\n      split module's name (i.e name of a module or package split\n      on '.')\n      (this means explicit relative imports that start with dots have\n      empty strings in this list!)\n\n    :type path: list or None\n    :param path:\n      optional list of path where the module or package should be\n      searched (use sys.path if nothing or None is given)\n\n    :type context_file: str or None\n    :param context_file:\n      context file to consider, necessary if the identifier has been\n      introduced using a relative import unresolvable in the actual\n      context (i.e. modutils)\n\n    :raise ImportError: if there is no such module in the directory\n\n    :rtype: (str or None, import type)\n    :return:\n      the path to the module's file or None if it's an integrated\n      builtin module such as 'sys'\n    \"\"\"\n    if context_file is not None:\n        context = os.path.dirname(context_file)\n    else:\n        context = context_file\n    if modpath[0] == \"xml\":\n        # handle _xmlplus\n        try:\n            return _spec_from_modpath([\"_xmlplus\"] + modpath[1:], path, context)\n        except ImportError:\n            return _spec_from_modpath(modpath, path, context)\n    elif modpath == [\"os\", \"path\"]:\n        # FIXME: currently ignoring search_path...\n        return spec.ModuleSpec(\n            name=\"os.path\",\n            location=os.path.__file__,\n            module_type=spec.ModuleType.PY_SOURCE,\n        )\n    return _spec_from_modpath(modpath, path, context)\n\n\ndef get_module_part(dotted_name, context_file=None):\n    \"\"\"given a dotted name return the module part of the name :\n\n    >>> get_module_part('astroid.as_string.dump')\n    'astroid.as_string'\n\n    :type dotted_name: str\n    :param dotted_name: full name of the identifier we are interested in\n\n    :type context_file: str or None\n    :param context_file:\n      context file to consider, necessary if the identifier has been\n      introduced using a relative import unresolvable in the actual\n      context (i.e. modutils)\n\n\n    :raise ImportError: if there is no such module in the directory\n\n    :rtype: str or None\n    :return:\n      the module part of the name or None if we have not been able at\n      all to import the given name\n\n    XXX: deprecated, since it doesn't handle package precedence over module\n    (see #10066)\n    \"\"\"\n    # os.path trick\n    if dotted_name.startswith(\"os.path\"):\n        return \"os.path\"\n    parts = dotted_name.split(\".\")\n    if context_file is not None:\n        # first check for builtin module which won't be considered latter\n        # in that case (path != None)\n        if parts[0] in BUILTIN_MODULES:\n            if len(parts) > 2:\n                raise ImportError(dotted_name)\n            return parts[0]\n        # don't use += or insert, we want a new list to be created !\n    path = None\n    starti = 0\n    if parts[0] == \"\":\n        assert (\n            context_file is not None\n        ), \"explicit relative import, but no context_file?\"\n        path = []  # prevent resolving the import non-relatively\n        starti = 1\n    while parts[starti] == \"\":  # for all further dots: change context\n        starti += 1\n        context_file = os.path.dirname(context_file)\n    for i in range(starti, len(parts)):\n        try:\n            file_from_modpath(\n                parts[starti : i + 1], path=path, context_file=context_file\n            )\n        except ImportError:\n            if i < max(1, len(parts) - 2):\n                raise\n            return \".\".join(parts[:i])\n    return dotted_name\n\n\ndef get_module_files(src_directory, blacklist, list_all=False):\n    \"\"\"given a package directory return a list of all available python\n    module's files in the package and its subpackages\n\n    :type src_directory: str\n    :param src_directory:\n      path of the directory corresponding to the package\n\n    :type blacklist: list or tuple\n    :param blacklist: iterable\n      list of files or directories to ignore.\n\n    :type list_all: bool\n    :param list_all:\n        get files from all paths, including ones without __init__.py\n\n    :rtype: list\n    :return:\n      the list of all available python module's files in the package and\n      its subpackages\n    \"\"\"\n    files = []\n    for directory, dirnames, filenames in os.walk(src_directory):\n        if directory in blacklist:\n            continue\n        _handle_blacklist(blacklist, dirnames, filenames)\n        # check for __init__.py\n        if not list_all and \"__init__.py\" not in filenames:\n            dirnames[:] = ()\n            continue\n        for filename in filenames:\n            if _is_python_file(filename):\n                src = os.path.join(directory, filename)\n                files.append(src)\n    return files\n\n\ndef get_source_file(filename, include_no_ext=False):\n    \"\"\"given a python module's file name return the matching source file\n    name (the filename will be returned identically if it's already an\n    absolute path to a python source file...)\n\n    :type filename: str\n    :param filename: python module's file name\n\n\n    :raise NoSourceFile: if no source file exists on the file system\n\n    :rtype: str\n    :return: the absolute path of the source file if it exists\n    \"\"\"\n    filename = os.path.abspath(_path_from_filename(filename))\n    base, orig_ext = os.path.splitext(filename)\n    for ext in PY_SOURCE_EXTS:\n        source_path = f\"{base}.{ext}\"\n        if os.path.exists(source_path):\n            return source_path\n    if include_no_ext and not orig_ext and os.path.exists(base):\n        return base\n    raise NoSourceFile(filename)\n\n\ndef is_python_source(filename):\n    \"\"\"\n    rtype: bool\n    return: True if the filename is a python source file\n    \"\"\"\n    return os.path.splitext(filename)[1][1:] in PY_SOURCE_EXTS\n\n\ndef is_standard_module(modname, std_path=None):\n    \"\"\"try to guess if a module is a standard python module (by default,\n    see `std_path` parameter's description)\n\n    :type modname: str\n    :param modname: name of the module we are interested in\n\n    :type std_path: list(str) or tuple(str)\n    :param std_path: list of path considered has standard\n\n\n    :rtype: bool\n    :return:\n      true if the module:\n      - is located on the path listed in one of the directory in `std_path`\n      - is a built-in module\n    \"\"\"\n    modname = modname.split(\".\")[0]\n    try:\n        filename = file_from_modpath([modname])\n    except ImportError:\n        # import failed, i'm probably not so wrong by supposing it's\n        # not standard...\n        return False\n    # modules which are not living in a file are considered standard\n    # (sys and __builtin__ for instance)\n    if filename is None:\n        # we assume there are no namespaces in stdlib\n        return not util.is_namespace(modname)\n    filename = _normalize_path(filename)\n    for path in EXT_LIB_DIRS:\n        if filename.startswith(_cache_normalize_path(path)):\n            return False\n    if std_path is None:\n        std_path = STD_LIB_DIRS\n\n    return any(filename.startswith(_cache_normalize_path(path)) for path in std_path)\n\n\ndef is_relative(modname, from_file):\n    \"\"\"return true if the given module name is relative to the given\n    file name\n\n    :type modname: str\n    :param modname: name of the module we are interested in\n\n    :type from_file: str\n    :param from_file:\n      path of the module from which modname has been imported\n\n    :rtype: bool\n    :return:\n      true if the module has been imported relatively to `from_file`\n    \"\"\"\n    if not os.path.isdir(from_file):\n        from_file = os.path.dirname(from_file)\n    if from_file in sys.path:\n        return False\n    return bool(\n        importlib.machinery.PathFinder.find_spec(\n            modname.split(\".\", maxsplit=1)[0], [from_file]\n        )\n    )\n\n\n# internal only functions #####################################################\n\n\ndef _spec_from_modpath(modpath, path=None, context=None):\n    \"\"\"given a mod path (i.e. split module / package name), return the\n    corresponding spec\n\n    this function is used internally, see `file_from_modpath`'s\n    documentation for more information\n    \"\"\"\n    assert modpath\n    location = None\n    if context is not None:\n        try:\n            found_spec = spec.find_spec(modpath, [context])\n            location = found_spec.location\n        except ImportError:\n            found_spec = spec.find_spec(modpath, path)\n            location = found_spec.location\n    else:\n        found_spec = spec.find_spec(modpath, path)\n    if found_spec.type == spec.ModuleType.PY_COMPILED:\n        try:\n            location = get_source_file(found_spec.location)\n            return found_spec._replace(\n                location=location, type=spec.ModuleType.PY_SOURCE\n            )\n        except NoSourceFile:\n            return found_spec._replace(location=location)\n    elif found_spec.type == spec.ModuleType.C_BUILTIN:\n        # integrated builtin module\n        return found_spec._replace(location=None)\n    elif found_spec.type == spec.ModuleType.PKG_DIRECTORY:\n        location = _has_init(found_spec.location)\n        return found_spec._replace(location=location, type=spec.ModuleType.PY_SOURCE)\n    return found_spec\n\n\ndef _is_python_file(filename):\n    \"\"\"return true if the given filename should be considered as a python file\n\n    .pyc and .pyo are ignored\n    \"\"\"\n    return filename.endswith((\".py\", \".so\", \".pyd\", \".pyw\"))\n\n\ndef _has_init(directory):\n    \"\"\"if the given directory has a valid __init__ file, return its path,\n    else return None\n    \"\"\"\n    mod_or_pack = os.path.join(directory, \"__init__\")\n    for ext in PY_SOURCE_EXTS + (\"pyc\", \"pyo\"):\n        if os.path.exists(mod_or_pack + \".\" + ext):\n            return mod_or_pack + \".\" + ext\n    return None\n\n\ndef is_namespace(specobj):\n    return specobj.type == spec.ModuleType.PY_NAMESPACE\n\n\ndef is_directory(specobj):\n    return specobj.type == spec.ModuleType.PKG_DIRECTORY\n\n\ndef is_module_name_part_of_extension_package_whitelist(\n    module_name: str, package_whitelist: Set[str]\n) -> bool:\n    \"\"\"\n    Returns True if one part of the module name is in the package whitelist\n\n    >>> is_module_name_part_of_extension_package_whitelist('numpy.core.umath', {'numpy'})\n    True\n    \"\"\"\n    parts = module_name.split(\".\")\n    return any(\n        \".\".join(parts[:x]) in package_whitelist for x in range(1, len(parts) + 1)\n    )\n","new_file_content":"# Copyright (c) 2014-2018, 2020 Claudiu Popa <pcmanticore@gmail.com>\n# Copyright (c) 2014 Google, Inc.\n# Copyright (c) 2014 Denis Laxalde <denis.laxalde@logilab.fr>\n# Copyright (c) 2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>\n# Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com>\n# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>\n# Copyright (c) 2015 Radosław Ganczarek <radoslaw@ganczarek.in>\n# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>\n# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>\n# Copyright (c) 2016 Ceridwen <ceridwenv@gmail.com>\n# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi>\n# Copyright (c) 2018 Mario Corchero <mcorcherojim@bloomberg.net>\n# Copyright (c) 2018 Mario Corchero <mariocj89@gmail.com>\n# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>\n# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com>\n# Copyright (c) 2019 markmcclain <markmcclain@users.noreply.github.com>\n# Copyright (c) 2019 BasPH <BasPH@users.noreply.github.com>\n# Copyright (c) 2020-2021 hippo91 <guillaume.peillex@gmail.com>\n# Copyright (c) 2020 Peter Kolbus <peter.kolbus@gmail.com>\n# Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com>\n# Copyright (c) 2021 Marc Mueller <30130371+cdce8p@users.noreply.github.com>\n# Copyright (c) 2021 DudeNr33 <3929834+DudeNr33@users.noreply.github.com>\n\n# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html\n# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE\n\n\"\"\"Python modules manipulation utility functions.\n\n:type PY_SOURCE_EXTS: tuple(str)\n:var PY_SOURCE_EXTS: list of possible python source file extension\n\n:type STD_LIB_DIRS: set of str\n:var STD_LIB_DIRS: directories where standard modules are located\n\n:type BUILTIN_MODULES: dict\n:var BUILTIN_MODULES: dictionary with builtin module names has key\n\"\"\"\n\n# We disable the import-error so pylint can work without distutils installed.\n# pylint: disable=no-name-in-module,useless-suppression\n\nimport importlib\nimport importlib.machinery\nimport importlib.util\nimport itertools\nimport os\nimport platform\nimport sys\nimport types\nfrom distutils.errors import DistutilsPlatformError  # pylint: disable=import-error\nfrom distutils.sysconfig import get_python_lib  # pylint: disable=import-error\nfrom typing import Set\n\nfrom astroid.interpreter._import import spec, util\n\n# distutils is replaced by virtualenv with a module that does\n# weird path manipulations in order to get to the\n# real distutils module.\n\n\nif sys.platform.startswith(\"win\"):\n    PY_SOURCE_EXTS = (\"py\", \"pyw\")\n    PY_COMPILED_EXTS = (\"dll\", \"pyd\")\nelse:\n    PY_SOURCE_EXTS = (\"py\",)\n    PY_COMPILED_EXTS = (\"so\",)\n\n\ntry:\n    # The explicit sys.prefix is to work around a patch in virtualenv that\n    # replaces the 'real' sys.prefix (i.e. the location of the binary)\n    # with the prefix from which the virtualenv was created. This throws\n    # off the detection logic for standard library modules, thus the\n    # workaround.\n    STD_LIB_DIRS = {\n        get_python_lib(standard_lib=True, prefix=sys.prefix),\n        # Take care of installations where exec_prefix != prefix.\n        get_python_lib(standard_lib=True, prefix=sys.exec_prefix),\n        get_python_lib(standard_lib=True),\n    }\n# get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to\n# non-valid path, see https://bugs.pypy.org/issue1164\nexcept DistutilsPlatformError:\n    STD_LIB_DIRS = set()\n\nif os.name == \"nt\":\n    STD_LIB_DIRS.add(os.path.join(sys.prefix, \"dlls\"))\n    try:\n        # real_prefix is defined when running inside virtual environments,\n        # created with the **virtualenv** library.\n        STD_LIB_DIRS.add(os.path.join(sys.real_prefix, \"dlls\"))\n    except AttributeError:\n        # sys.base_exec_prefix is always defined, but in a virtual environment\n        # created with the stdlib **venv** module, it points to the original\n        # installation, if the virtual env is activated.\n        try:\n            STD_LIB_DIRS.add(os.path.join(sys.base_exec_prefix, \"dlls\"))\n        except AttributeError:\n            pass\n\nif platform.python_implementation() == \"PyPy\":\n    # The get_python_lib(standard_lib=True) function does not give valid\n    # result with pypy in a virtualenv.\n    # In a virtual environment, with CPython implementation the call to this function returns a path toward\n    # the binary (its libraries) which has been used to create the virtual environment.\n    # Not with pypy implementation.\n    # The only way to retrieve such information is to use the sys.base_prefix hint.\n    # It's worth noticing that under CPython implementation the return values of\n    # get_python_lib(standard_lib=True) and get_python_lib(santdard_lib=True, prefix=sys.base_prefix)\n    # are the same.\n    # In the lines above, we could have replace the call to get_python_lib(standard=True)\n    # with the one using prefix=sys.base_prefix but we prefer modifying only what deals with pypy.\n    STD_LIB_DIRS.add(get_python_lib(standard_lib=True, prefix=sys.base_prefix))\n    _root = os.path.join(sys.prefix, \"lib_pypy\")\n    STD_LIB_DIRS.add(_root)\n    try:\n        # real_prefix is defined when running inside virtualenv.\n        STD_LIB_DIRS.add(os.path.join(sys.base_prefix, \"lib_pypy\"))\n    except AttributeError:\n        pass\n    del _root\nif os.name == \"posix\":\n    # Need the real prefix is we're under a virtualenv, otherwise\n    # the usual one will do.\n    try:\n        prefix = sys.real_prefix\n    except AttributeError:\n        prefix = sys.prefix\n\n    def _posix_path(path):\n        base_python = \"python%d.%d\" % sys.version_info[:2]\n        return os.path.join(prefix, path, base_python)\n\n    STD_LIB_DIRS.add(_posix_path(\"lib\"))\n    if sys.maxsize > 2 ** 32:\n        # This tries to fix a problem with /usr/lib64 builds,\n        # where systems are running both 32-bit and 64-bit code\n        # on the same machine, which reflects into the places where\n        # standard library could be found. More details can be found\n        # here http://bugs.python.org/issue1294959.\n        # An easy reproducing case would be\n        # https://github.com/PyCQA/pylint/issues/712#issuecomment-163178753\n        STD_LIB_DIRS.add(_posix_path(\"lib64\"))\n\nEXT_LIB_DIRS = {get_python_lib(), get_python_lib(True)}\nIS_JYTHON = platform.python_implementation() == \"Jython\"\nBUILTIN_MODULES = dict.fromkeys(sys.builtin_module_names, True)\n\n\nclass NoSourceFile(Exception):\n    \"\"\"exception raised when we are not able to get a python\n    source file for a precompiled file\n    \"\"\"\n\n\ndef _normalize_path(path):\n    return os.path.normcase(os.path.abspath(path))\n\n\ndef _canonicalize_path(path):\n    return os.path.realpath(os.path.expanduser(path))\n\n\ndef _path_from_filename(filename, is_jython=IS_JYTHON):\n    if not is_jython:\n        return filename\n    head, has_pyclass, _ = filename.partition(\"$py.class\")\n    if has_pyclass:\n        return head + \".py\"\n    return filename\n\n\ndef _handle_blacklist(blacklist, dirnames, filenames):\n    \"\"\"remove files/directories in the black list\n\n    dirnames/filenames are usually from os.walk\n    \"\"\"\n    for norecurs in blacklist:\n        if norecurs in dirnames:\n            dirnames.remove(norecurs)\n        elif norecurs in filenames:\n            filenames.remove(norecurs)\n\n\n_NORM_PATH_CACHE = {}\n\n\ndef _cache_normalize_path(path):\n    \"\"\"abspath with caching\"\"\"\n    # _module_file calls abspath on every path in sys.path every time it's\n    # called; on a larger codebase this easily adds up to half a second just\n    # assembling path components. This cache alleviates that.\n    try:\n        return _NORM_PATH_CACHE[path]\n    except KeyError:\n        if not path:  # don't cache result for ''\n            return _normalize_path(path)\n        result = _NORM_PATH_CACHE[path] = _normalize_path(path)\n        return result\n\n\ndef load_module_from_name(dotted_name: str) -> types.ModuleType:\n    \"\"\"Load a Python module from its name.\n\n    :type dotted_name: str\n    :param dotted_name: python name of a module or package\n\n    :raise ImportError: if the module or package is not found\n\n    :rtype: module\n    :return: the loaded module\n    \"\"\"\n    try:\n        return sys.modules[dotted_name]\n    except KeyError:\n        pass\n\n    return importlib.import_module(dotted_name)\n\n\ndef load_module_from_modpath(parts):\n    \"\"\"Load a python module from its split name.\n\n    :type parts: list(str) or tuple(str)\n    :param parts:\n      python name of a module or package split on '.'\n\n    :raise ImportError: if the module or package is not found\n\n    :rtype: module\n    :return: the loaded module\n    \"\"\"\n    return load_module_from_name(\".\".join(parts))\n\n\ndef load_module_from_file(filepath: str):\n    \"\"\"Load a Python module from it's path.\n\n    :type filepath: str\n    :param filepath: path to the python module or package\n\n    :raise ImportError: if the module or package is not found\n\n    :rtype: module\n    :return: the loaded module\n    \"\"\"\n    modpath = modpath_from_file(filepath)\n    return load_module_from_modpath(modpath)\n\n\ndef check_modpath_has_init(path, mod_path):\n    \"\"\"check there are some __init__.py all along the way\"\"\"\n    modpath = []\n    for part in mod_path:\n        modpath.append(part)\n        path = os.path.join(path, part)\n        if not _has_init(path):\n            old_namespace = util.is_namespace(\".\".join(modpath))\n            if not old_namespace:\n                return False\n    return True\n\n\ndef _get_relative_base_path(filename, path_to_check):\n    \"\"\"Extracts the relative mod path of the file to import from\n\n    Check if a file is within the passed in path and if so, returns the\n    relative mod path from the one passed in.\n\n    If the filename is no in path_to_check, returns None\n\n    Note this function will look for both abs and realpath of the file,\n    this allows to find the relative base path even if the file is a\n    symlink of a file in the passed in path\n\n    Examples:\n        _get_relative_base_path(\"/a/b/c/d.py\", \"/a/b\") ->  [\"c\",\"d\"]\n        _get_relative_base_path(\"/a/b/c/d.py\", \"/dev\") ->  None\n    \"\"\"\n    importable_path = None\n    path_to_check = os.path.normcase(path_to_check)\n    abs_filename = os.path.abspath(filename)\n    if os.path.normcase(abs_filename).startswith(path_to_check):\n        importable_path = abs_filename\n\n    real_filename = os.path.realpath(filename)\n    if os.path.normcase(real_filename).startswith(path_to_check):\n        importable_path = real_filename\n\n    if importable_path:\n        base_path = os.path.splitext(importable_path)[0]\n        relative_base_path = base_path[len(path_to_check) :]\n        return [pkg for pkg in relative_base_path.split(os.sep) if pkg]\n\n    return None\n\n\ndef modpath_from_file_with_callback(filename, path=None, is_package_cb=None):\n    filename = os.path.expanduser(_path_from_filename(filename))\n    for pathname in itertools.chain(\n        path or [], map(_canonicalize_path, sys.path), sys.path\n    ):\n        pathname = _cache_normalize_path(pathname)\n        if not pathname:\n            continue\n        modpath = _get_relative_base_path(filename, pathname)\n        if not modpath:\n            continue\n        if is_package_cb(pathname, modpath[:-1]):\n            return modpath\n\n    raise ImportError(\n        \"Unable to find module for {} in {}\".format(filename, \", \\n\".join(sys.path))\n    )\n\n\ndef modpath_from_file(filename, path=None):\n    \"\"\"Get the corresponding split module's name from a filename\n\n    This function will return the name of a module or package split on `.`.\n\n    :type filename: str\n    :param filename: file's path for which we want the module's name\n\n    :type Optional[List[str]] path:\n      Optional list of path where the module or package should be\n      searched (use sys.path if nothing or None is given)\n\n    :raise ImportError:\n      if the corresponding module's name has not been found\n\n    :rtype: list(str)\n    :return: the corresponding split module's name\n    \"\"\"\n    return modpath_from_file_with_callback(filename, path, check_modpath_has_init)\n\n\ndef file_from_modpath(modpath, path=None, context_file=None):\n    return file_info_from_modpath(modpath, path, context_file).location\n\n\ndef file_info_from_modpath(modpath, path=None, context_file=None):\n    \"\"\"given a mod path (i.e. split module / package name), return the\n    corresponding file, giving priority to source file over precompiled\n    file if it exists\n\n    :type modpath: list or tuple\n    :param modpath:\n      split module's name (i.e name of a module or package split\n      on '.')\n      (this means explicit relative imports that start with dots have\n      empty strings in this list!)\n\n    :type path: list or None\n    :param path:\n      optional list of path where the module or package should be\n      searched (use sys.path if nothing or None is given)\n\n    :type context_file: str or None\n    :param context_file:\n      context file to consider, necessary if the identifier has been\n      introduced using a relative import unresolvable in the actual\n      context (i.e. modutils)\n\n    :raise ImportError: if there is no such module in the directory\n\n    :rtype: (str or None, import type)\n    :return:\n      the path to the module's file or None if it's an integrated\n      builtin module such as 'sys'\n    \"\"\"\n    if context_file is not None:\n        context = os.path.dirname(context_file)\n    else:\n        context = context_file\n    if modpath[0] == \"xml\":\n        # handle _xmlplus\n        try:\n            return _spec_from_modpath([\"_xmlplus\"] + modpath[1:], path, context)\n        except ImportError:\n            return _spec_from_modpath(modpath, path, context)\n    elif modpath == [\"os\", \"path\"]:\n        # FIXME: currently ignoring search_path...\n        return spec.ModuleSpec(\n            name=\"os.path\",\n            location=os.path.__file__,\n            module_type=spec.ModuleType.PY_SOURCE,\n        )\n    return _spec_from_modpath(modpath, path, context)\n\n\ndef get_module_part(dotted_name, context_file=None):\n    \"\"\"given a dotted name return the module part of the name :\n\n    >>> get_module_part('astroid.as_string.dump')\n    'astroid.as_string'\n\n    :type dotted_name: str\n    :param dotted_name: full name of the identifier we are interested in\n\n    :type context_file: str or None\n    :param context_file:\n      context file to consider, necessary if the identifier has been\n      introduced using a relative import unresolvable in the actual\n      context (i.e. modutils)\n\n\n    :raise ImportError: if there is no such module in the directory\n\n    :rtype: str or None\n    :return:\n      the module part of the name or None if we have not been able at\n      all to import the given name\n\n    XXX: deprecated, since it doesn't handle package precedence over module\n    (see #10066)\n    \"\"\"\n    # os.path trick\n    if dotted_name.startswith(\"os.path\"):\n        return \"os.path\"\n    parts = dotted_name.split(\".\")\n    if context_file is not None:\n        # first check for builtin module which won't be considered latter\n        # in that case (path != None)\n        if parts[0] in BUILTIN_MODULES:\n            if len(parts) > 2:\n                raise ImportError(dotted_name)\n            return parts[0]\n        # don't use += or insert, we want a new list to be created !\n    path = None\n    starti = 0\n    if parts[0] == \"\":\n        assert (\n            context_file is not None\n        ), \"explicit relative import, but no context_file?\"\n        path = []  # prevent resolving the import non-relatively\n        starti = 1\n    while parts[starti] == \"\":  # for all further dots: change context\n        starti += 1\n        context_file = os.path.dirname(context_file)\n    for i in range(starti, len(parts)):\n        try:\n            file_from_modpath(\n                parts[starti : i + 1], path=path, context_file=context_file\n            )\n        except ImportError:\n            if i < max(1, len(parts) - 2):\n                raise\n            return \".\".join(parts[:i])\n    return dotted_name\n\n\ndef get_module_files(src_directory, blacklist, list_all=False):\n    \"\"\"given a package directory return a list of all available python\n    module's files in the package and its subpackages\n\n    :type src_directory: str\n    :param src_directory:\n      path of the directory corresponding to the package\n\n    :type blacklist: list or tuple\n    :param blacklist: iterable\n      list of files or directories to ignore.\n\n    :type list_all: bool\n    :param list_all:\n        get files from all paths, including ones without __init__.py\n\n    :rtype: list\n    :return:\n      the list of all available python module's files in the package and\n      its subpackages\n    \"\"\"\n    files = []\n    for directory, dirnames, filenames in os.walk(src_directory):\n        if directory in blacklist:\n            continue\n        _handle_blacklist(blacklist, dirnames, filenames)\n        # check for __init__.py\n        if not list_all and \"__init__.py\" not in filenames:\n            dirnames[:] = ()\n            continue\n        for filename in filenames:\n            if _is_python_file(filename):\n                src = os.path.join(directory, filename)\n                files.append(src)\n    return files\n\n\ndef get_source_file(filename, include_no_ext=False):\n    \"\"\"given a python module's file name return the matching source file\n    name (the filename will be returned identically if it's already an\n    absolute path to a python source file...)\n\n    :type filename: str\n    :param filename: python module's file name\n\n\n    :raise NoSourceFile: if no source file exists on the file system\n\n    :rtype: str\n    :return: the absolute path of the source file if it exists\n    \"\"\"\n    filename = os.path.abspath(_path_from_filename(filename))\n    base, orig_ext = os.path.splitext(filename)\n    for ext in PY_SOURCE_EXTS:\n        source_path = f\"{base}.{ext}\"\n        if os.path.exists(source_path):\n            return source_path\n    if include_no_ext and not orig_ext and os.path.exists(base):\n        return base\n    raise NoSourceFile(filename)\n\n\ndef is_python_source(filename):\n    \"\"\"\n    rtype: bool\n    return: True if the filename is a python source file\n    \"\"\"\n    return os.path.splitext(filename)[1][1:] in PY_SOURCE_EXTS\n\n\ndef is_standard_module(modname, std_path=None):\n    \"\"\"try to guess if a module is a standard python module (by default,\n    see `std_path` parameter's description)\n\n    :type modname: str\n    :param modname: name of the module we are interested in\n\n    :type std_path: list(str) or tuple(str)\n    :param std_path: list of path considered has standard\n\n\n    :rtype: bool\n    :return:\n      true if the module:\n      - is located on the path listed in one of the directory in `std_path`\n      - is a built-in module\n    \"\"\"\n    modname = modname.split(\".\")[0]\n    try:\n        filename = file_from_modpath([modname])\n    except ImportError:\n        # import failed, i'm probably not so wrong by supposing it's\n        # not standard...\n        return False\n    # modules which are not living in a file are considered standard\n    # (sys and __builtin__ for instance)\n    if filename is None:\n        # we assume there are no namespaces in stdlib\n        return not util.is_namespace(modname)\n    filename = _normalize_path(filename)\n    for path in EXT_LIB_DIRS:\n        if filename.startswith(_cache_normalize_path(path)):\n            return False\n    if std_path is None:\n        std_path = STD_LIB_DIRS\n    for path in std_path:\n        if filename.startswith(_cache_normalize_path(path)):\n            return True\n    return False\n\n\ndef is_relative(modname, from_file):\n    \"\"\"return true if the given module name is relative to the given\n    file name\n\n    :type modname: str\n    :param modname: name of the module we are interested in\n\n    :type from_file: str\n    :param from_file:\n      path of the module from which modname has been imported\n\n    :rtype: bool\n    :return:\n      true if the module has been imported relatively to `from_file`\n    \"\"\"\n    if not os.path.isdir(from_file):\n        from_file = os.path.dirname(from_file)\n    if from_file in sys.path:\n        return False\n    return bool(\n        importlib.machinery.PathFinder.find_spec(\n            modname.split(\".\", maxsplit=1)[0], [from_file]\n        )\n    )\n\n\n# internal only functions #####################################################\n\n\ndef _spec_from_modpath(modpath, path=None, context=None):\n    \"\"\"given a mod path (i.e. split module / package name), return the\n    corresponding spec\n\n    this function is used internally, see `file_from_modpath`'s\n    documentation for more information\n    \"\"\"\n    assert modpath\n    location = None\n    if context is not None:\n        try:\n            found_spec = spec.find_spec(modpath, [context])\n            location = found_spec.location\n        except ImportError:\n            found_spec = spec.find_spec(modpath, path)\n            location = found_spec.location\n    else:\n        found_spec = spec.find_spec(modpath, path)\n    if found_spec.type == spec.ModuleType.PY_COMPILED:\n        try:\n            location = get_source_file(found_spec.location)\n            return found_spec._replace(\n                location=location, type=spec.ModuleType.PY_SOURCE\n            )\n        except NoSourceFile:\n            return found_spec._replace(location=location)\n    elif found_spec.type == spec.ModuleType.C_BUILTIN:\n        # integrated builtin module\n        return found_spec._replace(location=None)\n    elif found_spec.type == spec.ModuleType.PKG_DIRECTORY:\n        location = _has_init(found_spec.location)\n        return found_spec._replace(location=location, type=spec.ModuleType.PY_SOURCE)\n    return found_spec\n\n\ndef _is_python_file(filename):\n    \"\"\"return true if the given filename should be considered as a python file\n\n    .pyc and .pyo are ignored\n    \"\"\"\n    return filename.endswith((\".py\", \".so\", \".pyd\", \".pyw\"))\n\n\ndef _has_init(directory):\n    \"\"\"if the given directory has a valid __init__ file, return its path,\n    else return None\n    \"\"\"\n    mod_or_pack = os.path.join(directory, \"__init__\")\n    for ext in PY_SOURCE_EXTS + (\"pyc\", \"pyo\"):\n        if os.path.exists(mod_or_pack + \".\" + ext):\n            return mod_or_pack + \".\" + ext\n    return None\n\n\ndef is_namespace(specobj):\n    return specobj.type == spec.ModuleType.PY_NAMESPACE\n\n\ndef is_directory(specobj):\n    return specobj.type == spec.ModuleType.PKG_DIRECTORY\n\n\ndef is_module_name_part_of_extension_package_whitelist(\n    module_name: str, package_whitelist: Set[str]\n) -> bool:\n    \"\"\"\n    Returns True if one part of the module name is in the package whitelist\n\n    >>> is_module_name_part_of_extension_package_whitelist('numpy.core.umath', {'numpy'})\n    True\n    \"\"\"\n    parts = module_name.split(\".\")\n    return any(\n        \".\".join(parts[:x]) in package_whitelist for x in range(1, len(parts) + 1)\n    )\n","header":{"file":{"path":"astroid/modutils.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/astroid/modutils.py"},"plus_file":{"path":"b/astroid/modutils.py"},"hunks":[{"descriptor":{"old_range":{"start":297,"length":6},"new_range":{"start":297,"length":9},"section":"def _get_relative_base_path(filename, path_to_check):"},"line_group":{"all_lines":[{"content":"    if os.path.normcase(real_filename).startswith(path_to_check):","type":"context"},{"content":"        importable_path = real_filename","type":"context"},{"content":"","type":"context"},{"content":"    # if \"var\" in path_to_check:","type":"added"},{"content":"    #     breakpoint()","type":"added"},{"content":"","type":"added"},{"content":"    if importable_path:","type":"context"},{"content":"        base_path = os.path.splitext(importable_path)[0]","type":"context"},{"content":"        relative_base_path = base_path[len(path_to_check) :]","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":307,"length":8},"new_range":{"start":310,"length":11},"section":"def _get_relative_base_path(filename, path_to_check):"},"line_group":{"all_lines":[{"content":"","type":"context"},{"content":"def modpath_from_file_with_callback(filename, path=None, is_package_cb=None):","type":"context"},{"content":"    filename = os.path.expanduser(_path_from_filename(filename))","type":"context"},{"content":"    paths_to_check = sys.path.copy()","type":"added"},{"content":"    if path:","type":"added"},{"content":"        paths_to_check += path","type":"added"},{"content":"    for pathname in itertools.chain(","type":"context"},{"content":"        path or [], map(_cache_normalize_path, sys.path), sys.path","type":"deleted"},{"content":"        paths_to_check, map(_cache_normalize_path, paths_to_check)","type":"added"},{"content":"    ):","type":"context"},{"content":"        if not pathname:","type":"context"},{"content":"            continue","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"d2a5b3c7b1e203fec3c7ca73c30eb1785d3d4d0a","new_commit_hash":"9b6ebb18f75f49da85fd3543b71ed532911b1ede","commit_message":"Update ChangeLog","commit_date":"2021-11-21T17:53:21+01:00","metadata":{}}