Skip to content

Commit 4c34830

Browse files
matteiusCopilot
andauthored
Apply variant of fix for wrong cononical name in Pipfile. (#6413)
* Apply variant of fix for wrong cononical name in Pipfile. * Fix test for py 3.12+ * Update tests/integration/test_install_nested_setup.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: stewartmiles --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: stewartmiles
1 parent fcfc1d5 commit 4c34830

File tree

2 files changed

+78
-7
lines changed

2 files changed

+78
-7
lines changed

pipenv/utils/dependencies.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,10 @@ def find_package_name_from_directory(directory):
684684
directory_path = Path(directory_str[1:])
685685

686686
try:
687-
# Sort contents - directories first, then files
687+
# Sort contents - files first, then directories to search parent
688+
# directories before leaf directories.
688689
directory_contents = sorted(
689-
directory_path.iterdir(), key=lambda x: (x.is_file(), x.name)
690+
directory_path.iterdir(), key=lambda x: (x.is_dir(), x.name)
690691
)
691692

692693
for path in directory_contents:
@@ -844,31 +845,34 @@ def determine_package_name(package: InstallRequirement):
844845

845846

846847
def find_package_name_from_filename(filename, file):
847-
if filename.endswith("METADATA"):
848+
# Extract basename to handle both full paths (from archives) and basenames (from directories)
849+
basename = Path(filename).name
850+
851+
if basename == "METADATA":
848852
content = file.read().decode()
849853
possible_name = parse_metadata_file(content)
850854
if possible_name:
851855
return possible_name
852856

853-
if filename.endswith("PKG-INFO"):
857+
if basename == "PKG-INFO":
854858
content = file.read().decode()
855859
possible_name = parse_pkginfo_file(content)
856860
if possible_name:
857861
return possible_name
858862

859-
if filename.endswith("setup.py"):
863+
if basename == "setup.py":
860864
content = file.read().decode()
861865
possible_name = parse_setup_file(content)
862866
if possible_name:
863867
return possible_name
864868

865-
if filename.endswith("setup.cfg"):
869+
if basename == "setup.cfg":
866870
content = file.read().decode()
867871
possible_name = parse_cfg_file(content)
868872
if possible_name:
869873
return possible_name
870874

871-
if filename.endswith("pyproject.toml"):
875+
if basename == "pyproject.toml":
872876
content = file.read().decode()
873877
possible_name = parse_toml_file(content)
874878
if possible_name:
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import os
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
7+
@pytest.mark.install
8+
@pytest.mark.needs_internet
9+
@pytest.mark.skipif(
10+
os.name == "nt",
11+
reason="This test is not for Windows",
12+
)
13+
def test_install_path_with_nested_setup_module(pipenv_instance_pypi):
14+
with pipenv_instance_pypi() as p:
15+
# Install setuptools first for Python 3.12+ compatibility
16+
c = p.pipenv("install setuptools")
17+
assert c.returncode == 0
18+
19+
# Create a simple package.
20+
package_dir = Path(p.path) / "simple_package"
21+
package_dir.mkdir()
22+
23+
# Create a simple setup.py file
24+
with open(package_dir / "setup.py", "w") as f:
25+
f.write("""
26+
from setuptools import setup, find_packages
27+
28+
setup(
29+
name="simple-package",
30+
version="0.1.0",
31+
packages=find_packages(),
32+
)
33+
""")
34+
module_dir = package_dir / "simple_package"
35+
module_dir.mkdir()
36+
37+
(module_dir / "__init__.py").touch()
38+
39+
# Create a test module that contains setup.py-like content but isn't setup.py
40+
with open(module_dir / "test_setup.py", "w") as f:
41+
f.write("""
42+
def setup(name = ''):
43+
return f'Setup package {name}'
44+
45+
def configure():
46+
return setup(name='my_simple_package')
47+
""")
48+
49+
# Install the package using a path with spaces
50+
# Use both escaped spaces and quoted path to test both scenarios
51+
relative_package_dir = f'"{package_dir.relative_to(p.path)}"'
52+
c = p.pipenv(f'install -e {relative_package_dir}')
53+
assert c.returncode == 0
54+
55+
# Verify the package was installed correctly
56+
c = p.pipenv('run python -c "'
57+
'import simple_package.test_setup; '
58+
'print(simple_package.test_setup.configure())"')
59+
assert c.returncode == 0
60+
assert "Setup package my_simple_package" in c.stdout
61+
62+
# Ensure my_simple_package was not parsed from the test_setup.py module
63+
# inside the package - this is the key test for our fix.
64+
with open(Path(p.path) / "Pipfile") as f:
65+
pipfile_content = f.read()
66+
assert "my_simple_package" not in pipfile_content
67+
assert "simple-package" in pipfile_content # Should find the correct name

0 commit comments

Comments
 (0)