Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seek for other sitecustomize.py to import #422

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/422.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Seek for other sitecustomize.py to import.
16 changes: 15 additions & 1 deletion pdm/pep582/sitecustomize.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions tests/cli/test_run.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import functools
import os
import subprocess
import textwrap
Expand Down Expand Up @@ -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()
12 changes: 11 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could make this simpler for testing, just clean the PYTHONPATH here. No need to keep the old value. Test case can provide its value when running

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could not assume the development environment of others not taking PYTHONPATH in usage. Some may use nix to do development. And nix is using PYTHONPATH to import packages that may essential to pdm testings. For example, the pip package of python3.9 for downloading wheel files for testing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know the approach used by nix.

if pythonpath:
os.environ["PYTHONPATH"] = pythonpath
yield p
# Restore the config items
Config._config_map = old_config_map
Expand Down