Skip to content

Commit

Permalink
Update dynamic module imports in pkg_resources to private alias s…
Browse files Browse the repository at this point in the history
…tatic imports

Enabled ``attr-defined`` checks in mypy for ``pkg_resources``
  • Loading branch information
Avasam committed May 9, 2024
1 parent 804ccd2 commit e999582
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 29 deletions.
3 changes: 2 additions & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ exclude = (?x)(
| ^setuptools/_distutils/ # Vendored
| ^setuptools/config/_validate_pyproject/ # Auto-generated
)

# Ignoring attr-defined because setuptools wraps a lot of distutils classes, adding new attributes,
# w/o updating all the attributes and return types from the base classes for type-checkers to understand
# Especially with setuptools.dist.command vs distutils.dist.command vs setuptools._distutils.dist.command
# *.extern modules that actually live in *._vendor will also cause attr-defined issues on import
[mypy-setuptools.*]
disable_error_code = attr-defined

# - Avoid raising issues when importing from "extern" modules, as those are added to path dynamically.
Expand Down
1 change: 1 addition & 0 deletions newsfragments/4348.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix an error with `UnicodeDecodeError` handling in ``pkg_resources`` when trying to read files in UTF-8 with a fallback -- by :user:`Avasam`
1 change: 1 addition & 0 deletions newsfragments/4348.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update dynamic module imports in ``pkg_resources`` to private alias static imports. Enabled ``attr-defined`` checks in mypy for ``pkg_resources`` -- by :user:`Avasam`
44 changes: 19 additions & 25 deletions pkg_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,11 @@
drop_comment,
join_continuation,
)

from pkg_resources.extern import platformdirs
from pkg_resources.extern import packaging

__import__('pkg_resources.extern.packaging.version')
__import__('pkg_resources.extern.packaging.specifiers')
__import__('pkg_resources.extern.packaging.requirements')
__import__('pkg_resources.extern.packaging.markers')
__import__('pkg_resources.extern.packaging.utils')
from pkg_resources.extern.packaging import markers as _packaging_markers
from pkg_resources.extern.packaging import requirements as _packaging_requirements
from pkg_resources.extern.packaging import utils as _packaging_utils
from pkg_resources.extern.packaging import version as _packaging_version
from pkg_resources.extern.platformdirs import user_cache_dir

# declare some globals that will be defined later to
# satisfy the linters.
Expand Down Expand Up @@ -116,7 +112,7 @@ class PEP440Warning(RuntimeWarning):
"""


parse_version = packaging.version.Version
parse_version = _packaging_version.Version


_state_vars: Dict[str, str] = {}
Expand Down Expand Up @@ -730,7 +726,7 @@ def add(self, dist, entry=None, insert=True, replace=False):
return

self.by_key[dist.key] = dist
normalized_name = packaging.utils.canonicalize_name(dist.key)
normalized_name = _packaging_utils.canonicalize_name(dist.key)
self.normalized_to_canonical_keys[normalized_name] = dist.key
if dist.key not in keys:
keys.append(dist.key)
Expand Down Expand Up @@ -1344,9 +1340,7 @@ def get_default_cache():
or a platform-relevant user cache dir for an app
named "Python-Eggs".
"""
return os.environ.get('PYTHON_EGG_CACHE') or platformdirs.user_cache_dir(
appname='Python-Eggs'
)
return os.environ.get('PYTHON_EGG_CACHE') or user_cache_dir(appname='Python-Eggs')


def safe_name(name):
Expand All @@ -1363,8 +1357,8 @@ def safe_version(version):
"""
try:
# normalize the version
return str(packaging.version.Version(version))
except packaging.version.InvalidVersion:
return str(_packaging_version.Version(version))
except _packaging_version.InvalidVersion:
version = version.replace(' ', '.')
return re.sub('[^A-Za-z0-9.]+', '-', version)

Expand Down Expand Up @@ -1441,9 +1435,9 @@ def evaluate_marker(text, extra=None):
This implementation uses the 'pyparsing' module.
"""
try:
marker = packaging.markers.Marker(text)
marker = _packaging_markers.Marker(text)
return marker.evaluate()
except packaging.markers.InvalidMarker as e:
except _packaging_markers.InvalidMarker as e:
raise SyntaxError(e) from e


Expand Down Expand Up @@ -2695,20 +2689,20 @@ def parsed_version(self):
if not hasattr(self, "_parsed_version"):
try:
self._parsed_version = parse_version(self.version)
except packaging.version.InvalidVersion as ex:
except _packaging_version.InvalidVersion as ex:
info = f"(package: {self.project_name})"
if hasattr(ex, "add_note"):
ex.add_note(info) # PEP 678
raise
raise packaging.version.InvalidVersion(f"{str(ex)} {info}") from None
raise _packaging_version.InvalidVersion(f"{str(ex)} {info}") from None

return self._parsed_version

@property
def _forgiving_parsed_version(self):
try:
return self.parsed_version
except packaging.version.InvalidVersion as ex:
except _packaging_version.InvalidVersion as ex:
self._parsed_version = parse_version(_forgiving_version(self.version))

notes = "\n".join(getattr(ex, "__notes__", [])) # PEP 678
Expand Down Expand Up @@ -2881,7 +2875,7 @@ def from_filename(cls, filename, metadata=None, **kw):

def as_requirement(self):
"""Return a ``Requirement`` that matches this distribution exactly"""
if isinstance(self.parsed_version, packaging.version.Version):
if isinstance(self.parsed_version, _packaging_version.Version):
spec = "%s==%s" % (self.project_name, self.parsed_version)
else:
spec = "%s===%s" % (self.project_name, self.parsed_version)
Expand Down Expand Up @@ -3127,11 +3121,11 @@ def parse_requirements(strs):
return map(Requirement, join_continuation(map(drop_comment, yield_lines(strs))))


class RequirementParseError(packaging.requirements.InvalidRequirement):
class RequirementParseError(_packaging_requirements.InvalidRequirement):
"Compatibility wrapper for InvalidRequirement"


class Requirement(packaging.requirements.Requirement):
class Requirement(_packaging_requirements.Requirement):
def __init__(self, requirement_string):
"""DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
super().__init__(requirement_string)
Expand Down Expand Up @@ -3353,6 +3347,6 @@ def _read_utf8_with_fallback(file: str, fallback_encoding=LOCALE_ENCODING) -> st
"""
# TODO: Add a deadline?
# See comment in setuptools.unicode_utils._Utf8EncodingNeeded
warnings.warns(msg, PkgResourcesDeprecationWarning, stacklevel=2)
warnings.warn(msg, PkgResourcesDeprecationWarning, stacklevel=2)
with open(file, "r", encoding=fallback_encoding) as f:
return f.read()
6 changes: 3 additions & 3 deletions pkg_resources/tests/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import itertools

import pytest
from pkg_resources.extern import packaging
from pkg_resources.extern.packaging.specifiers import SpecifierSet

import pkg_resources
from pkg_resources import (
Expand Down Expand Up @@ -567,7 +567,7 @@ def testOptionsAndHashing(self):
assert hash(r1) == hash((
"twisted",
None,
packaging.specifiers.SpecifierSet(">=1.2"),
SpecifierSet(">=1.2"),
frozenset(["foo", "bar"]),
None,
))
Expand All @@ -576,7 +576,7 @@ def testOptionsAndHashing(self):
) == hash((
"twisted",
"https://localhost/twisted.zip",
packaging.specifiers.SpecifierSet(),
SpecifierSet(),
frozenset(),
None,
))
Expand Down

0 comments on commit e999582

Please sign in to comment.