Skip to content

Commit

Permalink
Replace most pkg_resources calls with importlib.metadata and packaging
Browse files Browse the repository at this point in the history
pkg_resources is deprecated and, under some circumstances, causes import
errors in Python 3.12. This commit replaces the deprecated pkg_resources
functions that access distribution metadata with calls to corresponding
functions from importlib.metadata (or its backport importlib_metadata)
and packaging. This change will bring pyinfra more in line with modern
recommendations and should resolve the errors.

The change introduces a new dependency on importlib_metadata in Python
versions prior to 3.10. Even though importlib.metadata was available in
Python 3.8, its entry_points() function did not have the group keyword
argument until 3.10, hence this commit prefers the backport until that
Python version.

The only remaining use of pkg_resources is the require() function, which
will take more work to replace since there's no ready equivalent in any
of the importlib* or packaging modules.
  • Loading branch information
diazona committed May 12, 2024
1 parent 9c4b772 commit 8c9cb02
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 9 deletions.
11 changes: 6 additions & 5 deletions pyinfra/api/config.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from os import path
from typing import Optional

# TODO: move to importlib.resources
from pkg_resources import Requirement, ResolutionError, parse_version, require
from pkg_resources import ResolutionError, require
from packaging.specifiers import SpecifierSet
from packaging.version import Version

from pyinfra import __version__, state

Expand Down Expand Up @@ -53,10 +54,10 @@ class ConfigDefaults:
def check_pyinfra_version(version: str):
if not version:
return
running_version = parse_version(__version__)
required_versions = Requirement.parse("pyinfra{0}".format(version))
running_version = Version(__version__)
required_versions = SpecifierSet(version)

if running_version not in required_versions: # type: ignore[operator]
if running_version not in required_versions:
raise PyinfraError(
f"pyinfra version requirement not met (requires {version}, running {__version__})"
)
Expand Down
7 changes: 5 additions & 2 deletions pyinfra/api/connectors.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import pkg_resources
try:
from importlib_metadata import entry_points
except ImportError:
from importlib.metadata import entry_points


def _load_connector(entrypoint):
Expand All @@ -8,7 +11,7 @@ def _load_connector(entrypoint):
def get_all_connectors():
return {
entrypoint.name: _load_connector(entrypoint)
for entrypoint in pkg_resources.iter_entry_points("pyinfra.connectors")
for entrypoint in entry_points(group="pyinfra.connectors")
}


Expand Down
7 changes: 5 additions & 2 deletions pyinfra/version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
try:
from pkg_resources import get_distribution
try:
from importlib_metadata import version
except ImportError:
from importlib.metadata import version

__version__ = get_distribution("pyinfra").version
__version__ = version("pyinfra")
except Exception:
__version__ = "unknown"
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@
"pywinrm",
"typeguard",
"distro>=1.6,<2",
"packaging>=16.1",
# Backport of graphlib used for DAG operation ordering
'graphlib_backport ; python_version < "3.9"',
# Backport of typing for Unpack (added 3.11)
'typing-extensions ; python_version < "3.11"',
# Backport of importlib.metadata for entry_points(group=...) (added 3.10)
'importlib_metadata>=3.6 ; python_version < "3.10"',
)

TEST_REQUIRES = (
Expand Down

0 comments on commit 8c9cb02

Please sign in to comment.