Skip to content

pkg_resources: Correctly handle normalized project names #4855

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

Closed
wants to merge 6 commits into from

Conversation

di
Copy link
Member

@di di commented Feb 26, 2025

Summary of changes

This fixes an issue where pkg_resources.require treats project names with periods differently than other project names.

Before:

>>> import pkg_resources
<stdin>:1: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
>>> pkg_resources.require('zip-po')
[zip-po 0.0.0 (/home/di/.pyenv/versions/3.12.4/lib/python3.12/site-packages)]
>>> pkg_resources.require('zip_po')
[zip-po 0.0.0 (/home/di/.pyenv/versions/3.12.4/lib/python3.12/site-packages)]
>>> pkg_resources.require('zip.po')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/di/git/pypa/setuptools/pkg_resources/__init__.py", line 1061, in require
    needed = self.resolve(parse_requirements(requirements))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/di/git/pypa/setuptools/pkg_resources/__init__.py", line 888, in resolve
    dist = self._resolve_dist(
           ^^^^^^^^^^^^^^^^^^^
  File "/home/di/git/pypa/setuptools/pkg_resources/__init__.py", line 929, in _resolve_dist
    raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'zip.po' distribution was not found and is required by the application

After:

>>> import pkg_resources
<stdin>:1: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
>>> pkg_resources.require('zip-po')
[zip-po 0.0.0 (/home/di/.pyenv/versions/3.12.4/lib/python3.12/site-packages)]
>>> pkg_resources.require('zip_po')
[zip-po 0.0.0 (/home/di/.pyenv/versions/3.12.4/lib/python3.12/site-packages)]
>>> pkg_resources.require('zip.po')
[zip-po 0.0.0 (/home/di/.pyenv/versions/3.12.4/lib/python3.12/site-packages)]

The simplest fix would be a one-character update to safe_name, which currently does not normalize periods when producing a "safe" project name:

def safe_name(name: str) -> str:
"""Convert an arbitrary string to a standard distribution name
Any runs of non-alphanumeric/. characters are replaced with a single '-'.
"""
return re.sub('[^A-Za-z0-9.]+', '-', name)

However, since this is a public API, changes here might be more disruptive, so I opted to change pkg_resources usage of safe_name internally instead.

Closes #4853.

Pull Request Checklist

Copy link
Contributor

@abravalheri abravalheri left a comment

Choose a reason for hiding this comment

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

Thank you very much @di for having a look on this.

I was working on a regression test.
Would you consider adding the following to the test_pkg_resources?

import inspect

# ...

class TestWorkdirRequire:
    def fake_site_packages(self, tmp_path, monkeypatch, dist_files):
        site_packages = tmp_path / "site-packages"
        site_packages.mkdir()
        for file, content in self.FILES.items():
            path = site_packages / file
            path.parent.mkdir(exist_ok=True, parents=True)
            path.write_text(inspect.cleandoc(content), encoding="utf-8")

        monkeypatch.setattr(sys, "path", [site_packages])
        return os.fspath(site_packages)

    FILES = {
        "pkg1_mod-1.2.3.dist-info/METADATA": """
            Metadata-Version: 2.4
            Name: pkg1.mod
            Version: 1.2.3
            """,
        "pkg2.mod-0.42.dist-info/METADATA": """
            Metadata-Version: 2.1
            Name: pkg2.mod
            Version: 0.42
            """,
        "pkg3_mod.egg-info/PKG-INFO": """
            Name: pkg3.mod
            Version: 1.2.3
            """,
        "pkg4.mod.egg-info/PKG-INFO": """
            Name: pkg4.mod
            Version: 0.42
            """,
    }

    @pytest.mark.parametrize(
        ("name", "version", "req"),
        [
            ("pkg1.mod", "1.2.3", "pkg1.mod>=1"),
            ("pkg2.mod", "0.42", "pkg2.mod>=0.4"),
            ("pkg3.mod", "1.2.3", "pkg3.mod<=2"),
            ("pkg4.mod", "0.42", "pkg4.mod>0.2,<1"),
        ],
    )
    def test_require_normalised_name(self, tmp_path, monkeypatch, name, version, req):
        # https://github.com/pypa/setuptools/issues/4853
        site_packages = self.fake_site_packages(tmp_path, monkeypatch, self.FILES)
        ws = pkg_resources.WorkingSet([site_packages])

        [dist] = ws.require(req)
        assert dist.version == version
        assert dist.project_name == name
        assert os.path.commonpath([dist.location, site_packages]) == site_packages

@abravalheri
Copy link
Contributor

abravalheri commented Feb 26, 2025

@krpatter-intc, would you be able to test if this PR solves your problem?

I believe that can use "setuptools @ https://github.com/di/setuptools/archive/refs/heads/fix/4853.zip" (or some variation of this) in your pyproject.toml to download the version in this PR.

If it does not work, could you then please have a look on #4856 ("setuptools @ https://github.com/abravalheri/setuptools/archive/refs/heads/issue-4853.zip")?

@krpatter-intc
Copy link

krpatter-intc commented Feb 26, 2025

@krpatter-intc, would you be able to test if this PR solves your problem?

Yep, I can confirm this fixes pkg_resources.require to take any format from the test package I built (and confirmed it was built/installed using the 75.8.1 release):

>>> pkg_resources.require("sample.module_under")
[sample-module-under 1 (c:\temp\example\.venv\lib\site-packages)]
>>> pkg_resources.require("sample-module_under") 
[sample-module-under 1 (c:\temp\example\.venv\lib\site-packages)]
>>> pkg_resources.require("sample-module-under") 
[sample-module-under 1 (c:\temp\example\.venv\lib\site-packages)]
>>>

Thanks for the quick turnaround!

EDIT: For clarity, this was done using:

https://github.com/di/setuptools/archive/refs/heads/fix/4853.zip

@abravalheri
Copy link
Contributor

Thank you very much @krpatter-intc.

My initial idea was to go with this PR, but there are some tests failing, so we might go instead with #4856 (I think it will also solve your problem).

@di di closed this Feb 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] packages of the form package.something renamed to package_something in 75.8.1
3 participants