jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/985365 )

Change subject: replace pkg_resources with importlib.metadata and packaging
......................................................................

replace pkg_resources with importlib.metadata and packaging

Bug: T340640
Change-Id: Ib4e9921b8721225bb477e9521ab337c30a0d8450
---
M pywikibot/tools/__init__.py
M setup.py
M pywikibot/scripts/wrapper.py
M pywikibot/backports.py
M .coveragerc
5 files changed, 60 insertions(+), 94 deletions(-)

Approvals:
  Xqt: Looks good to me, approved
  jenkins-bot: Verified




diff --git a/.coveragerc b/.coveragerc
index 5e64004..dd6f136 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -8,7 +8,6 @@
     except ImportError
     except KeyboardInterrupt
     except OSError
-    except pkg_resources
     except \w*ServerError
     except SyntaxError
     raise ImportError
diff --git a/pywikibot/backports.py b/pywikibot/backports.py
index 04a334e..2b2aa4e 100644
--- a/pywikibot/backports.py
+++ b/pywikibot/backports.py
@@ -184,6 +184,12 @@
     from itertools import batched  # type: ignore[no-redef]


+try:
+    import importlib.metadata as importlib_metadata
+except ImportError:
+    import importlib_metadata
+
+
 # import ModuleDeprecationWrapper here to prevent circular import
 from pywikibot.tools import ModuleDeprecationWrapper  # noqa: E402

diff --git a/pywikibot/scripts/wrapper.py b/pywikibot/scripts/wrapper.py
index 5b08cc8..3b24e25 100755
--- a/pywikibot/scripts/wrapper.py
+++ b/pywikibot/scripts/wrapper.py
@@ -44,7 +44,6 @@
 #
 from __future__ import annotations

-#
 import os
 import sys
 import types
@@ -59,7 +58,7 @@
 site_package = False


-def check_pwb_versions(package):
+def check_pwb_versions(package: str):
     """Validate package version and scripts version.

     Rules:
@@ -67,7 +66,8 @@
         - Scripts version must not be older than previous Pywikibot version
           due to deprecation policy
     """
-    from pywikibot.tools import Version
+    from packaging.version import Version
+
     scripts_version = Version(getattr(package, '__version__', pwb.__version__))
     wikibot_version = Version(pwb.__version__)

@@ -218,19 +218,18 @@
         print(f"    pip install \"{str(requirement).partition(';')[0]}\"\n")


-def check_modules(script=None):
+def check_modules(script: str | None = None) -> bool:
     """Check whether mandatory modules are present.

     This also checks Python version when importing dependencies from setup.py

     :param script: The script name to be checked for dependencies
-    :type script: str or None
     :return: True if all dependencies are installed
-    :rtype: bool
     :raise RuntimeError: wrong Python version found in setup.py
     """
-    import pkg_resources
+    from packaging.requirements import Requirement

+    from pywikibot.backports import importlib_metadata
     from setup import script_deps

     missing_requirements = []
@@ -240,35 +239,25 @@
         dependencies = script_deps.get(Path(script).name, [])
     else:
         from setup import dependencies
-        try:
-            next(pkg_resources.parse_requirements(dependencies))
-        except ValueError as e:  # pragma: no cover
-            # T286980: setuptools is too old and requirement parsing fails
-            import setuptools
-            setupversion = tuple(int(num)
-                                 for num in setuptools.__version__.split('.'))
-            if setupversion < (20, 8, 1):
-                # print the minimal requirement
-                _print_requirements(
-                    ['setuptools>=20.8.1'], None,
-                    f'outdated ({setuptools.__version__})')
-                return False
-            raise e

-    for requirement in pkg_resources.parse_requirements(dependencies):
-        if requirement.marker is None \
-           or pkg_resources.evaluate_marker(str(requirement.marker)):
+    for dependency in dependencies:
+        requirement = Requirement(dependency)
+        if requirement.marker is None or requirement.marker.evaluate():
             try:
-                pkg_resources.resource_exists(requirement, requirement.name)
-            except pkg_resources.DistributionNotFound as e:
+                instlld_vrsn = importlib_metadata.version(requirement.name)
+            except importlib_metadata.PackageNotFoundError as e:
                 missing_requirements.append(requirement)
                 print(e)
-            except pkg_resources.VersionConflict as e:
-                version_conflicts.append(requirement)
-                print(e)
+            else:
+                if instlld_vrsn not in requirement.specifier:
+                    version_conflicts.append(requirement)
+                    print(
+                        f'{requirement.name} version {instlld_vrsn} is '
+                        f'installed but {requirement.specifier} is required'
+                    )

-    del pkg_resources
-    del dependencies
+    del Requirement
+    del importlib_metadata
     del script_deps

     _print_requirements(missing_requirements, script, 'missing')
diff --git a/pywikibot/tools/__init__.py b/pywikibot/tools/__init__.py
index caa8763..088120c 100644
--- a/pywikibot/tools/__init__.py
+++ b/pywikibot/tools/__init__.py
@@ -35,15 +35,14 @@
 import sys
 from contextlib import suppress
 from functools import total_ordering, wraps
-from importlib import import_module
 from types import TracebackType
 from typing import Any
 from warnings import catch_warnings, showwarning, warn

-import pkg_resources
+import packaging.version

 import pywikibot  # T306760
-from pywikibot.backports import Callable
+from pywikibot.backports import Callable, importlib_metadata
 from pywikibot.tools._deprecate import (
     ModuleDeprecationWrapper,
     add_decorated_full_name,
@@ -60,9 +59,6 @@
 from pywikibot.tools._unidata import _first_upper_exception


-pkg_Version = pkg_resources.packaging.version.Version  # noqa: N816
-
-
 __all__ = (
     # deprecating functions
     'ModuleDeprecationWrapper',
@@ -89,7 +85,6 @@
     'first_upper',
     'strtobool',
     'normalize_username',
-    'Version',
     'MediaWikiVersion',
     'open_archive',
     'merge_unique_dicts',
@@ -117,7 +112,7 @@
     return False

 
-def has_module(module, version=None) -> bool:
+def has_module(module: str, version: str | None = None) -> bool:
     """Check if a module can be imported.

     .. versionadded:: 3.0
@@ -127,15 +122,13 @@
        removed with Python 3.12.
     """
     try:
-        m = import_module(module)
-    except ImportError:
+        metadata_version = importlib_metadata.version(module)
+    except importlib_metadata.PackageNotFoundError:
         return False
     if version:
-        if not hasattr(m, '__version__'):
-            return False  # pragma: no cover

-        required_version = pkg_resources.parse_version(version)
-        module_version = pkg_resources.parse_version(m.__version__)
+        required_version = packaging.version.Version(version)
+        module_version = packaging.version.Version(metadata_version)

         if module_version < required_version:
             warn('Module version {} is lower than requested version {}'
@@ -404,36 +397,6 @@
     return first_upper(username)


-class Version(pkg_Version):
-
-    """Version from pkg_resouce vendor package.
-
-    This Version provides propreties of vendor package 20.4 shipped with
-    setuptools 49.4.0.
-
-    .. versionadded:: 6.4
-    """
-
-    def __getattr__(self, name):
-        """Provides propreties of vendor package 20.4."""
-        if name in ('epoch', 'release', 'pre', ):
-            return getattr(self._version, name)
-        if name in ('post', 'dev'):
-            attr = getattr(self._version, name)
-            return attr[1] if attr else None
-        if name == 'is_devrelease':
-            return self.dev is not None
-
-        parts = ('major', 'minor', 'micro')
-        try:
-            index = parts.index(name)
-        except ValueError:
-            raise AttributeError('{!r} object has to attribute {!r}'
-                                 .format(type(self).__name__, name)) from None
-        release = self.release
-        return release[index] if len(release) >= index + 1 else 0
-
-
 @total_ordering
 class MediaWikiVersion:

diff --git a/setup.py b/setup.py
index c5da297..f3d0ec8 100755
--- a/setup.py
+++ b/setup.py
@@ -87,7 +87,9 @@
 # ------- setup install_requires ------- #
 # packages which are mandatory
 dependencies = [
+    'importlib_metadata ; python_version < "3.8"',
     'mwparserfromhell>=0.5.2',
+    'packaging',
     'requests>=2.21.0',
     # PEP 440
     'setuptools>=48.0.0 ; python_version >= "3.10"',
@@ -129,7 +131,6 @@
     and is not a developmental release.

     :return: pywikibot module version string
-    :rtype: str
     """
     version = metadata.__version__
     if 'sdist' not in sys.argv:
@@ -139,7 +140,8 @@
     from contextlib import suppress
     from subprocess import PIPE, run

-    from pkg_resources import parse_version, safe_version
+    from packaging.version import InvalidVersion, Version
+
     try:
         tags = run(['git', 'tag'], check=True, stdout=PIPE,
                    universal_newlines=True).stdout.splitlines()
@@ -155,24 +157,21 @@

         last_tag = tags[-1]

-    warnings = []
-    if parse_version(version) < parse_version('0'):  # pragma: no cover
-        # any version which is not a valid PEP 440 version will be considered
-        # less than any valid PEP 440 version
-        warnings.append(
-            version + ' is not a valid version string following PEP 440.')
-    elif safe_version(version) != version:  # pragma: no cover
-        warnings.append(f'{version} does not follow PEP 440. Use '
-                        f'{safe_version(version)} as version string instead.')
+    warning = ''
+    try:
+        vrsn = Version(version)
+    except InvalidVersion:  # pragma: no cover
+        warning = f'{version} is not a valid version string following PEP 440.'
+    else:
+        if last_tag and vrsn <= Version(last_tag):
+            warning = (  # pragma: no cover
+                f'New version {version!r} is not higher than last version '
+                f'{last_tag!r}.'
+            )

-    if last_tag and parse_version(version) <= parse_version(last_tag):
-        warnings.append(  # pragma: no cover
-            f'New version {version!r} is not higher than last version '
-            f'{last_tag!r}.')
-
-    if warnings:  # pragma: no cover
+    if warning:  # pragma: no cover
         print(__doc__)
-        print('\n\n'.join(warnings))
+        print('\n\n{warning}')
         sys.exit('\nBuild of distribution package canceled.')

     return version

--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/985365
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ib4e9921b8721225bb477e9521ab337c30a0d8450
Gerrit-Change-Number: 985365
Gerrit-PatchSet: 4
Gerrit-Owner: JJMC89 <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to