diff --git a/news/422.bugfix.md b/news/422.bugfix.md new file mode 100644 index 0000000000..231c88a3d1 --- /dev/null +++ b/news/422.bugfix.md @@ -0,0 +1 @@ +Seek for other sitecustomize.py to import. diff --git a/pdm/pep582/sitecustomize.py b/pdm/pep582/sitecustomize.py index 24f4272915..921d84124a 100644 --- a/pdm/pep582/sitecustomize.py +++ b/pdm/pep582/sitecustomize.py @@ -41,11 +41,25 @@ def find_pypackage(path, version): return result -def main(): +def ensure_another_sitecustomize_imported(): + import imp + + try: + f, pathname, desc = imp.find_module("sitecustomize", sys.path) + try: + imp.load_module("another_sitecustomize", f, pathname, desc) + finally: + f.close() + except ImportError: + pass + +def main(): self_path = os.path.normcase(os.path.dirname(os.path.abspath(__file__))) sys.path[:] = [path for path in sys.path if os.path.normcase(path) != self_path] + ensure_another_sitecustomize_imported() + libpath = get_pypackages_path() if not libpath: return diff --git a/tests/cli/test_run.py b/tests/cli/test_run.py index 6ee382902b..95b8951b7f 100644 --- a/tests/cli/test_run.py +++ b/tests/cli/test_run.py @@ -1,3 +1,4 @@ +import functools import os import subprocess import textwrap @@ -214,3 +215,40 @@ def test_run_with_another_project_root(project, invoke, capfd): assert ret.exit_code == 0 out, _ = capfd.readouterr() assert out.strip() == "2.24.0" + + +def test_import_another_sitecustomize(project, invoke, capfd): + project.meta["requires-python"] = ">=2.7" + project.write_pyproject() + # a script for checking another sitecustomize is imported + project.root.joinpath("foo.py").write_text( + textwrap.dedent( + """ + import sys + module = sys.modules.get('another_sitecustomize') + if module: + print(module.__file__) + """ + ) + ) + # ensure there have at least one sitecustomize can be imported + # there may have more than one sitecustomize.py in sys.path + project.root.joinpath("sitecustomize.py").write_text("# do nothing") + env = os.environ.copy() + paths = [str(project.root)] + original_paths = env.get("PYTHONPATH", "") + if original_paths: + paths.insert(0, original_paths) + env["PYTHONPATH"] = os.pathsep.join(paths) + # invoke pdm commands + invoke = functools.partial(invoke, env=env, obj=project) + project._environment = None + capfd.readouterr() + with cd(project.root): + invoke(["run", "python", "foo.py"]) + # only the first and second sitecustomize module will be imported + # as sitecustomize and another_sitecustomize + # the first one is pdm.pep582.sitecustomize for sure + # the second one maybe not the dummy module injected here + out, _ = capfd.readouterr() + assert out.strip() diff --git a/tests/conftest.py b/tests/conftest.py index 71e5cfcddb..f0698fd10f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -224,6 +224,13 @@ def pip_global_tempdir_manager(): yield +def remove_pep582_path_from_pythonpath(pythonpath): + """Remove all pep582 paths of PDM from PYTHONPATH""" + paths = pythonpath.split(os.pathsep) + paths = [path for path in paths if "pdm/pep582" not in path] + return os.pathsep.join(paths) + + @pytest.fixture() def project_no_init(tmp_path, mocker): p = main.create_project(tmp_path) @@ -235,8 +242,11 @@ def project_no_init(tmp_path, mocker): do_use(p, getattr(sys, "_base_executable", sys.executable)) with temp_environ(): os.environ.pop("VIRTUAL_ENV", None) - os.environ.pop("PYTHONPATH", None) os.environ.pop("PEP582_PACKAGES", None) + pythonpath = os.environ.pop("PYTHONPATH", "") + pythonpath = remove_pep582_path_from_pythonpath(pythonpath) + if pythonpath: + os.environ["PYTHONPATH"] = pythonpath yield p # Restore the config items Config._config_map = old_config_map