From 5ddd1228a1c96b803409159d2acd2eccb064ed48 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 25 Jul 2024 16:56:48 -0400 Subject: [PATCH 01/44] Expand the documentation of Distribution.locate_file to explain why 'locate_file' does what it does and what the consequences are of not implementing it. Ref pypa/pip#11684 --- importlib_metadata/__init__.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 2c71d33c..2eefb1d6 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -373,6 +373,17 @@ def locate_file(self, path: str | os.PathLike[str]) -> SimplePath: """ Given a path to a file in this distribution, return a SimplePath to it. + + This method is used by callers of ``Distribution.files()`` to + locate files within the distribution. If it's possible for a + Distribution to represent files in the distribution as + ``SimplePath`` objects, it should implement this method + to resolve such objects. + + Some Distribution providers may elect not to resolve SimplePath + objects within the distribution by raising a + NotImplementedError, but consumers of such a Distribution would + be unable to invoke ``Distribution.files()``. """ @classmethod From 875003a735fdd6334782250d15baa8142896a9a5 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 1 Aug 2024 15:48:57 -0400 Subject: [PATCH 02/44] Disallow passing of 'dist' to EntryPoints.select. Closes python/cpython#107220. --- importlib_metadata/__init__.py | 17 +++++++++++++++++ newsfragments/+29a322e3.feature.rst | 1 + 2 files changed, 18 insertions(+) create mode 100644 newsfragments/+29a322e3.feature.rst diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 2eefb1d6..9a96d061 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -227,9 +227,26 @@ def matches(self, **params): >>> ep.matches(attr='bong') True """ + self._disallow_dist(params) attrs = (getattr(self, param) for param in params) return all(map(operator.eq, params.values(), attrs)) + @staticmethod + def _disallow_dist(params): + """ + Querying by dist is not allowed (dist objects are not comparable). + >>> EntryPoint(name='fan', value='fav', group='fag').matches(dist='foo') + Traceback (most recent call last): + ... + ValueError: "dist" is not suitable for matching... + """ + if "dist" in params: + raise ValueError( + '"dist" is not suitable for matching. ' + "Instead, use Distribution.entry_points.select() on a " + "located distribution." + ) + def _key(self): return self.name, self.value, self.group diff --git a/newsfragments/+29a322e3.feature.rst b/newsfragments/+29a322e3.feature.rst new file mode 100644 index 00000000..0e80b746 --- /dev/null +++ b/newsfragments/+29a322e3.feature.rst @@ -0,0 +1 @@ +Disallow passing of 'dist' to EntryPoints.select. \ No newline at end of file From 8e66fbc444727f75a54c055bfcc5504c49f6418c Mon Sep 17 00:00:00 2001 From: Daniel Hollas Date: Mon, 5 Aug 2024 19:40:35 +0100 Subject: [PATCH 03/44] Defer import inspect --- importlib_metadata/__init__.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 2eefb1d6..a8dead9b 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -8,7 +8,6 @@ import zipp import email import types -import inspect import pathlib import operator import textwrap @@ -1071,6 +1070,9 @@ def _topmost(name: PackagePath) -> Optional[str]: return top if rest else None +inspect = None + + def _get_toplevel_name(name: PackagePath) -> str: """ Infer a possibly importable module name from a name presumed on @@ -1089,11 +1091,14 @@ def _get_toplevel_name(name: PackagePath) -> str: >>> _get_toplevel_name(PackagePath('foo.dist-info')) 'foo.dist-info' """ - return _topmost(name) or ( - # python/typeshed#10328 - inspect.getmodulename(name) # type: ignore - or str(name) - ) + n = _topmost(name) + if n: + return n + + global inspect + if inspect is None: + import inspect + return inspect.getmodulename(name) or str(name) def _top_level_inferred(dist): From 06acfd262258d809242c74179477af324389e1c7 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Thu, 8 Aug 2024 23:14:35 +0200 Subject: [PATCH 04/44] Update to the latest ruff version (jaraco/skeleton#137) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5a4a7e91..ff54405e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.8 + rev: v0.5.6 hooks: - id: ruff - id: ruff-format From dd30b7600f33ce06a479a73002b950f4a3947759 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 8 Aug 2024 17:19:17 -0400 Subject: [PATCH 05/44] Add Protocols, remove @overload, from `.coveragerc` `exclude_also` (jaraco/skeleton#135) Co-authored-by: Jason R. Coombs --- .coveragerc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.coveragerc b/.coveragerc index 35b98b1d..2e3f4dd7 100644 --- a/.coveragerc +++ b/.coveragerc @@ -8,6 +8,8 @@ disable_warnings = [report] show_missing = True exclude_also = - # jaraco/skeleton#97 - @overload + # Exclude common false positives per + # https://coverage.readthedocs.io/en/latest/excluding.html#advanced-exclusion + # Ref jaraco/skeleton#97 and jaraco/skeleton#135 + class .*\bProtocol\): if TYPE_CHECKING: From 3841656c61bad87f922fcba50445b503209b69c2 Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 12 Aug 2024 12:13:19 -0400 Subject: [PATCH 06/44] Loosen restrictions on mypy (jaraco/skeleton#136) Based on changes downstream in setuptools. --- mypy.ini | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mypy.ini b/mypy.ini index b6f97276..83b0d15c 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,5 +1,14 @@ [mypy] -ignore_missing_imports = True -# required to support namespace packages -# https://github.com/python/mypy/issues/14057 +# Is the project well-typed? +strict = False + +# Early opt-in even when strict = False +warn_unused_ignores = True +warn_redundant_casts = True +enable_error_code = ignore-without-code + +# Support namespace packages per https://github.com/python/mypy/issues/14057 explicit_package_bases = True + +# Disable overload-overlap due to many false-positives +disable_error_code = overload-overlap From 1a27fd5b8815e65571e6c028d6bef2c1daf61688 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 12 Aug 2024 12:16:15 -0400 Subject: [PATCH 07/44] Split the test dependencies into four classes (test, cover, type, check). (jaraco/skeleton#139) --- pyproject.toml | 25 ++++++++++++++++++++----- tox.ini | 4 ++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1307e1fa..31057d85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,14 +28,10 @@ Source = "https://github.com/PROJECT_PATH" test = [ # upstream "pytest >= 6, != 8.1.*", - "pytest-checkdocs >= 2.4", - "pytest-cov", - "pytest-mypy", - "pytest-enabler >= 2.2", - "pytest-ruff >= 0.2.1; sys_platform != 'cygwin'", # local ] + doc = [ # upstream "sphinx >= 3.5", @@ -47,4 +43,23 @@ doc = [ # local ] +check = [ + "pytest-checkdocs >= 2.4", + "pytest-ruff >= 0.2.1; sys_platform != 'cygwin'", +] + +cover = [ + "pytest-cov", +] + +enabler = [ + "pytest-enabler >= 2.2", +] + +type = [ + "pytest-mypy", +] + + + [tool.setuptools_scm] diff --git a/tox.ini b/tox.ini index cc4db36e..01f0975f 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,10 @@ commands = usedevelop = True extras = test + check + cover + enabler + type [testenv:diffcov] description = run tests and check that diff from main is covered From 6d9b766099dbac1c97a220badde7e14304e03291 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 19 Aug 2024 13:47:26 -0400 Subject: [PATCH 08/44] Remove MetadataPathFinder regardless of its position. Closes #500 --- conftest.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/conftest.py b/conftest.py index 779ac24b..762e66f3 100644 --- a/conftest.py +++ b/conftest.py @@ -13,13 +13,18 @@ def pytest_configure(): def remove_importlib_metadata(): """ - Because pytest imports importlib_metadata, the coverage - reports are broken (#322). So work around the issue by - undoing the changes made by pytest's import of - importlib_metadata (if any). + Ensure importlib_metadata is not imported yet. + + Because pytest or other modules might import + importlib_metadata, the coverage reports are broken (#322). + Work around the issue by undoing the changes made by a + previous import of importlib_metadata (if any). """ - if sys.meta_path[-1].__class__.__name__ == 'MetadataPathFinder': - del sys.meta_path[-1] + sys.meta_path[:] = [ + item + for item in sys.meta_path + if item.__class__.__name__ != 'MetadataPathFinder' + ] for mod in list(sys.modules): if mod.startswith('importlib_metadata'): del sys.modules[mod] From 3c8e1ec4e34c11dcff086be7fbd0d1981bf32480 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 19 Aug 2024 15:35:22 -0400 Subject: [PATCH 09/44] Finalize --- NEWS.rst | 9 +++++++++ newsfragments/+29a322e3.feature.rst | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 newsfragments/+29a322e3.feature.rst diff --git a/NEWS.rst b/NEWS.rst index 2e22a335..018825be 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,12 @@ +v8.3.0 +====== + +Features +-------- + +- Disallow passing of 'dist' to EntryPoints.select. + + v8.2.0 ====== diff --git a/newsfragments/+29a322e3.feature.rst b/newsfragments/+29a322e3.feature.rst deleted file mode 100644 index 0e80b746..00000000 --- a/newsfragments/+29a322e3.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Disallow passing of 'dist' to EntryPoints.select. \ No newline at end of file From debb5165a88b1a4433150b265e155c21b497d154 Mon Sep 17 00:00:00 2001 From: Daniel Hollas Date: Tue, 20 Aug 2024 12:23:17 +0100 Subject: [PATCH 10/44] Don't use global var - wallrusify - add a note about deffered import --- importlib_metadata/__init__.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index a8dead9b..f76ef2cc 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1070,9 +1070,6 @@ def _topmost(name: PackagePath) -> Optional[str]: return top if rest else None -inspect = None - - def _get_toplevel_name(name: PackagePath) -> str: """ Infer a possibly importable module name from a name presumed on @@ -1091,13 +1088,12 @@ def _get_toplevel_name(name: PackagePath) -> str: >>> _get_toplevel_name(PackagePath('foo.dist-info')) 'foo.dist-info' """ - n = _topmost(name) - if n: + if n := _topmost(name): return n - global inspect - if inspect is None: - import inspect + # We're deffering import of inspect to speed up overall import time + import inspect + return inspect.getmodulename(name) or str(name) From e99c10510d48e840b0550bd05d1167633dcfaea7 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:00:48 -0400 Subject: [PATCH 11/44] Restore single-expression logic. --- importlib_metadata/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index f76ef2cc..b1a15350 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1088,13 +1088,14 @@ def _get_toplevel_name(name: PackagePath) -> str: >>> _get_toplevel_name(PackagePath('foo.dist-info')) 'foo.dist-info' """ - if n := _topmost(name): - return n - # We're deffering import of inspect to speed up overall import time import inspect - return inspect.getmodulename(name) or str(name) + return _topmost(name) or ( + # python/typeshed#10328 + inspect.getmodulename(name) # type: ignore + or str(name) + ) def _top_level_inferred(dist): From a7aaf72702b3a49ea3e33c9cf7f223839067c883 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:01:47 -0400 Subject: [PATCH 12/44] Use third-person imperative voice and link to issue in comment. --- importlib_metadata/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index b1a15350..c2b76dd2 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1088,7 +1088,7 @@ def _get_toplevel_name(name: PackagePath) -> str: >>> _get_toplevel_name(PackagePath('foo.dist-info')) 'foo.dist-info' """ - # We're deffering import of inspect to speed up overall import time + # Defer import of inspect for performance (python/cpython#118761) import inspect return _topmost(name) or ( From ebcdcfdd18d427498f11b74e245b3f8a7ef5df9c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:04:10 -0400 Subject: [PATCH 13/44] Remove workaround for python/typeshed#10328. --- importlib_metadata/__init__.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 72670f44..24587e68 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1108,11 +1108,7 @@ def _get_toplevel_name(name: PackagePath) -> str: # Defer import of inspect for performance (python/cpython#118761) import inspect - return _topmost(name) or ( - # python/typeshed#10328 - inspect.getmodulename(name) # type: ignore - or str(name) - ) + return _topmost(name) or (inspect.getmodulename(name) or str(name)) def _top_level_inferred(dist): From 71b467843258873048eb944545ba1235866523e6 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:05:25 -0400 Subject: [PATCH 14/44] Add news fragment. --- newsfragments/499.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/499.feature.rst diff --git a/newsfragments/499.feature.rst b/newsfragments/499.feature.rst new file mode 100644 index 00000000..1aa347ed --- /dev/null +++ b/newsfragments/499.feature.rst @@ -0,0 +1 @@ +Deferred import of inspect for import performance. \ No newline at end of file From 1616cb3a82c33c3603ff984b6ff417e68068aa6e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:06:05 -0400 Subject: [PATCH 15/44] Finalize --- NEWS.rst | 9 +++++++++ newsfragments/499.feature.rst | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 newsfragments/499.feature.rst diff --git a/NEWS.rst b/NEWS.rst index 018825be..f4a37fdf 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,12 @@ +v8.4.0 +====== + +Features +-------- + +- Deferred import of inspect for import performance. (#499) + + v8.3.0 ====== diff --git a/newsfragments/499.feature.rst b/newsfragments/499.feature.rst deleted file mode 100644 index 1aa347ed..00000000 --- a/newsfragments/499.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Deferred import of inspect for import performance. \ No newline at end of file From 46c6127405cba0cf19b96ce6e533c28890eb1ea3 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:39:18 -0400 Subject: [PATCH 16/44] =?UTF-8?q?=F0=9F=91=B9=20Feed=20the=20hobgoblins=20?= =?UTF-8?q?(delint).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conftest.py | 1 - exercises.py | 4 +++- importlib_metadata/__init__.py | 34 ++++++++++++++++---------------- importlib_metadata/_adapters.py | 2 +- importlib_metadata/_compat.py | 3 +-- importlib_metadata/_functools.py | 2 +- importlib_metadata/_meta.py | 14 ++++++++++--- tests/_path.py | 3 +-- tests/compat/py39.py | 1 - tests/compat/test_py39_compat.py | 5 +++-- tests/fixtures.py | 14 ++++++------- tests/test_api.py | 5 +++-- tests/test_integration.py | 4 +++- tests/test_main.py | 13 ++++++------ tests/test_zip.py | 3 ++- 15 files changed, 59 insertions(+), 49 deletions(-) diff --git a/conftest.py b/conftest.py index 762e66f3..6d3402d6 100644 --- a/conftest.py +++ b/conftest.py @@ -1,6 +1,5 @@ import sys - collect_ignore = [ # this module fails mypy tests because 'setup.py' matches './setup.py' 'tests/data/sources/example/setup.py', diff --git a/exercises.py b/exercises.py index c88fa983..adccf03c 100644 --- a/exercises.py +++ b/exercises.py @@ -29,6 +29,7 @@ def cached_distribution_perf(): def uncached_distribution_perf(): "uncached distribution" import importlib + import importlib_metadata # end warmup @@ -37,9 +38,10 @@ def uncached_distribution_perf(): def entrypoint_regexp_perf(): - import importlib_metadata import re + import importlib_metadata + input = '0' + ' ' * 2**10 + '0' # end warmup re.match(importlib_metadata.EntryPoint.pattern, input) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 24587e68..84d16508 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1,23 +1,28 @@ from __future__ import annotations -import os -import re import abc -import sys -import json -import zipp +import collections import email -import types -import pathlib -import operator -import textwrap import functools import itertools +import json +import operator +import os +import pathlib import posixpath -import collections +import re +import sys +import textwrap +import types +from contextlib import suppress +from importlib import import_module +from importlib.abc import MetaPathFinder +from itertools import starmap +from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast + +import zipp from . import _meta -from .compat import py39, py311 from ._collections import FreezableDefaultDict, Pair from ._compat import ( NullFinder, @@ -26,12 +31,7 @@ from ._functools import method_cache, pass_none from ._itertools import always_iterable, bucket, unique_everseen from ._meta import PackageMetadata, SimplePath - -from contextlib import suppress -from importlib import import_module -from importlib.abc import MetaPathFinder -from itertools import starmap -from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast +from .compat import py39, py311 __all__ = [ 'Distribution', diff --git a/importlib_metadata/_adapters.py b/importlib_metadata/_adapters.py index 6223263e..3b516a2d 100644 --- a/importlib_metadata/_adapters.py +++ b/importlib_metadata/_adapters.py @@ -1,6 +1,6 @@ +import email.message import re import textwrap -import email.message from ._text import FoldedCase diff --git a/importlib_metadata/_compat.py b/importlib_metadata/_compat.py index df312b1c..01356d69 100644 --- a/importlib_metadata/_compat.py +++ b/importlib_metadata/_compat.py @@ -1,6 +1,5 @@ -import sys import platform - +import sys __all__ = ['install', 'NullFinder'] diff --git a/importlib_metadata/_functools.py b/importlib_metadata/_functools.py index 71f66bd0..5dda6a21 100644 --- a/importlib_metadata/_functools.py +++ b/importlib_metadata/_functools.py @@ -1,5 +1,5 @@ -import types import functools +import types # from jaraco.functools 3.3 diff --git a/importlib_metadata/_meta.py b/importlib_metadata/_meta.py index 1927d0f6..0942bbd9 100644 --- a/importlib_metadata/_meta.py +++ b/importlib_metadata/_meta.py @@ -1,9 +1,17 @@ from __future__ import annotations import os -from typing import Protocol -from typing import Any, Dict, Iterator, List, Optional, TypeVar, Union, overload - +from typing import ( + Any, + Dict, + Iterator, + List, + Optional, + Protocol, + TypeVar, + Union, + overload, +) _T = TypeVar("_T") diff --git a/tests/_path.py b/tests/_path.py index b3cfb9cd..7e4f7ee0 100644 --- a/tests/_path.py +++ b/tests/_path.py @@ -2,8 +2,7 @@ import functools import pathlib -from typing import Dict, Protocol, Union -from typing import runtime_checkable +from typing import Dict, Protocol, Union, runtime_checkable class Symlink(str): diff --git a/tests/compat/py39.py b/tests/compat/py39.py index 9476eb35..4e45d7cc 100644 --- a/tests/compat/py39.py +++ b/tests/compat/py39.py @@ -1,6 +1,5 @@ from jaraco.test.cpython import from_test_support, try_import - os_helper = try_import('os_helper') or from_test_support( 'FS_NONASCII', 'skip_unless_symlink', 'temp_dir' ) diff --git a/tests/compat/test_py39_compat.py b/tests/compat/test_py39_compat.py index 549e518a..db9fb1b7 100644 --- a/tests/compat/test_py39_compat.py +++ b/tests/compat/test_py39_compat.py @@ -1,8 +1,7 @@ -import sys import pathlib +import sys import unittest -from .. import fixtures from importlib_metadata import ( distribution, distributions, @@ -11,6 +10,8 @@ version, ) +from .. import fixtures + class OldStdlibFinderTests(fixtures.DistInfoPkgOffPath, unittest.TestCase): def setUp(self): diff --git a/tests/fixtures.py b/tests/fixtures.py index 187f1705..410e6f17 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -1,18 +1,16 @@ -import sys +import contextlib import copy +import functools import json -import shutil import pathlib +import shutil +import sys import textwrap -import functools -import contextlib - -from .compat.py312 import import_helper -from .compat.py39 import os_helper from . import _path from ._path import FilesSpec - +from .compat.py39 import os_helper +from .compat.py312 import import_helper try: from importlib import resources # type: ignore diff --git a/tests/test_api.py b/tests/test_api.py index 7ce0cd64..c36f93e0 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,9 +1,8 @@ +import importlib import re import textwrap import unittest -import importlib -from . import fixtures from importlib_metadata import ( Distribution, PackageNotFoundError, @@ -15,6 +14,8 @@ version, ) +from . import fixtures + class APITests( fixtures.EggInfoPkg, diff --git a/tests/test_integration.py b/tests/test_integration.py index f7af67f3..9bb3e793 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -8,15 +8,17 @@ """ import unittest + import packaging.requirements import packaging.version -from . import fixtures from importlib_metadata import ( _compat, version, ) +from . import fixtures + class IntegrationTests(fixtures.DistInfoPkg, unittest.TestCase): def test_package_spec_installed(self): diff --git a/tests/test_main.py b/tests/test_main.py index dc248492..7c9851fc 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,14 +1,11 @@ -import re +import importlib import pickle +import re import unittest -import importlib -import importlib_metadata -from .compat.py39 import os_helper import pyfakefs.fake_filesystem_unittest as ffs -from . import fixtures -from ._path import Symlink +import importlib_metadata from importlib_metadata import ( Distribution, EntryPoint, @@ -21,6 +18,10 @@ version, ) +from . import fixtures +from ._path import Symlink +from .compat.py39 import os_helper + class BasicTests(fixtures.DistInfoPkg, unittest.TestCase): version_pattern = r'\d+\.\d+(\.\d)?' diff --git a/tests/test_zip.py b/tests/test_zip.py index 01aba6df..d4f8e2f0 100644 --- a/tests/test_zip.py +++ b/tests/test_zip.py @@ -1,7 +1,6 @@ import sys import unittest -from . import fixtures from importlib_metadata import ( PackageNotFoundError, distribution, @@ -11,6 +10,8 @@ version, ) +from . import fixtures + class TestZip(fixtures.ZipFixtures, unittest.TestCase): def setUp(self): From d968f6270d55f27a10491344a22e9e0fd77b5583 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:40:57 -0400 Subject: [PATCH 17/44] Remove superfluous parentheses. --- importlib_metadata/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 84d16508..f6477999 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1108,7 +1108,7 @@ def _get_toplevel_name(name: PackagePath) -> str: # Defer import of inspect for performance (python/cpython#118761) import inspect - return _topmost(name) or (inspect.getmodulename(name) or str(name)) + return _topmost(name) or inspect.getmodulename(name) or str(name) def _top_level_inferred(dist): From 56b61b3dd90df2dba2da445a8386029b54fdebf3 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 20 Aug 2024 13:42:29 -0400 Subject: [PATCH 18/44] Rely on zipp overlay for zipfile.Path. --- importlib_metadata/__init__.py | 4 ++-- newsfragments/+d7832466.feature.rst | 1 + pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 newsfragments/+d7832466.feature.rst diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index f6477999..b75befa3 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -20,7 +20,7 @@ from itertools import starmap from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast -import zipp +from zipp.compat.overlay import zipfile from . import _meta from ._collections import FreezableDefaultDict, Pair @@ -768,7 +768,7 @@ def children(self): return [] def zip_children(self): - zip_path = zipp.Path(self.root) + zip_path = zipfile.Path(self.root) names = zip_path.root.namelist() self.joinpath = zip_path.joinpath diff --git a/newsfragments/+d7832466.feature.rst b/newsfragments/+d7832466.feature.rst new file mode 100644 index 00000000..3f3f3162 --- /dev/null +++ b/newsfragments/+d7832466.feature.rst @@ -0,0 +1 @@ +Rely on zipp overlay for zipfile.Path. \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 24ce25e3..8c45cc9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ ] requires-python = ">=3.8" dependencies = [ - "zipp>=0.5", + "zipp>=3.20", 'typing-extensions>=3.6.4; python_version < "3.8"', ] dynamic = ["version"] From f1350e413775a9e79e20779cc9705e28a1c55900 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 21 Aug 2024 07:05:32 -0400 Subject: [PATCH 19/44] Add upstream and local sections for 'type' extra, since many projects will have 'types-*' dependencies. --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 31057d85..3866a323 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,10 @@ enabler = [ ] type = [ + # upstream "pytest-mypy", + + # local ] From 6c0b7b37d94650ab5c59464615f56e3720cd3d56 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 21 Aug 2024 18:30:07 -0400 Subject: [PATCH 20/44] =?UTF-8?q?=F0=9F=A7=8E=E2=80=8D=E2=99=80=EF=B8=8F?= =?UTF-8?q?=20Genuflect=20to=20the=20types.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ref jaraco/pytest-perf#16 --- mypy.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypy.ini b/mypy.ini index 83b0d15c..8e00827c 100644 --- a/mypy.ini +++ b/mypy.ini @@ -12,3 +12,7 @@ explicit_package_bases = True # Disable overload-overlap due to many false-positives disable_error_code = overload-overlap + +# jaraco/pytest-perf#16 +[mypy-pytest_perf.*] +ignore_missing_imports = True From 4551c19215511b192fb3e5253ed9b05d7aa6c821 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 21 Aug 2024 19:20:02 -0400 Subject: [PATCH 21/44] =?UTF-8?q?=F0=9F=A7=8E=E2=80=8D=E2=99=80=EF=B8=8F?= =?UTF-8?q?=20Genuflect=20to=20the=20types.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ref jaraco/zipp#123 --- mypy.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypy.ini b/mypy.ini index 8e00827c..9f476547 100644 --- a/mypy.ini +++ b/mypy.ini @@ -16,3 +16,7 @@ disable_error_code = overload-overlap # jaraco/pytest-perf#16 [mypy-pytest_perf.*] ignore_missing_imports = True + +# jaraco/zipp#123 +[mypy-zipp.*] +ignore_missing_imports = True From d4aa5054a9818aeaa73174fd69ca21c0bb6a3fad Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 21 Aug 2024 19:26:42 -0400 Subject: [PATCH 22/44] =?UTF-8?q?=F0=9F=A7=8E=E2=80=8D=E2=99=80=EF=B8=8F?= =?UTF-8?q?=20Genuflect=20to=20the=20types.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- importlib_metadata/__init__.py | 4 ++-- tests/fixtures.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index b75befa3..3f1d942e 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -331,7 +331,7 @@ class PackagePath(pathlib.PurePosixPath): size: int dist: Distribution - def read_text(self, encoding: str = 'utf-8') -> str: # type: ignore[override] + def read_text(self, encoding: str = 'utf-8') -> str: return self.locate().read_text(encoding=encoding) def read_binary(self) -> bytes: @@ -750,7 +750,7 @@ class FastPath: True """ - @functools.lru_cache() # type: ignore + @functools.lru_cache() # type: ignore[misc] def __new__(cls, root): return super().__new__(cls) diff --git a/tests/fixtures.py b/tests/fixtures.py index 410e6f17..6708a063 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -13,12 +13,12 @@ from .compat.py312 import import_helper try: - from importlib import resources # type: ignore + from importlib import resources getattr(resources, 'files') getattr(resources, 'as_file') except (ImportError, AttributeError): - import importlib_resources as resources # type: ignore + import importlib_resources as resources # type: ignore[import-not-found, no-redef] @contextlib.contextmanager From 8484eccd39bda1ead5d8fec8cd967004f640a81f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 21 Aug 2024 19:27:40 -0400 Subject: [PATCH 23/44] =?UTF-8?q?=F0=9F=A7=8E=E2=80=8D=E2=99=80=EF=B8=8F?= =?UTF-8?q?=20Genuflect=20to=20the=20types.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-sync jaraco.path 3.7.1. --- tests/_path.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/_path.py b/tests/_path.py index 7e4f7ee0..81ab76ac 100644 --- a/tests/_path.py +++ b/tests/_path.py @@ -1,4 +1,4 @@ -# from jaraco.path 3.7 +# from jaraco.path 3.7.1 import functools import pathlib @@ -11,7 +11,7 @@ class Symlink(str): """ -FilesSpec = Dict[str, Union[str, bytes, Symlink, 'FilesSpec']] # type: ignore +FilesSpec = Dict[str, Union[str, bytes, Symlink, 'FilesSpec']] @runtime_checkable @@ -28,12 +28,12 @@ def symlink_to(self, target): ... # pragma: no cover def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: - return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore + return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] def build( spec: FilesSpec, - prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore + prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] ): """ Build a set of files/directories, as described by the spec. @@ -67,7 +67,7 @@ def build( @functools.singledispatch def create(content: Union[str, bytes, FilesSpec], path): path.mkdir(exist_ok=True) - build(content, prefix=path) # type: ignore + build(content, prefix=path) # type: ignore[arg-type] @create.register From 0666d9da54886a68488d93a9907943e95fa2d1d4 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 21 Aug 2024 19:30:53 -0400 Subject: [PATCH 24/44] =?UTF-8?q?=F0=9F=A7=8E=E2=80=8D=E2=99=80=EF=B8=8F?= =?UTF-8?q?=20Genuflect=20to=20the=20types.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ref jaraco/jaraco.test#7 --- mypy.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypy.ini b/mypy.ini index 9f476547..786d03f4 100644 --- a/mypy.ini +++ b/mypy.ini @@ -20,3 +20,7 @@ ignore_missing_imports = True # jaraco/zipp#123 [mypy-zipp.*] ignore_missing_imports = True + +# jaraco/jaraco.test#7 +[mypy-jaraco.test.*] +ignore_missing_imports = True From 6f8cc1ef4bf403e8c01e90230b6b2c6fc532179c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 21 Aug 2024 19:37:14 -0400 Subject: [PATCH 25/44] =?UTF-8?q?=F0=9F=A7=8E=E2=80=8D=E2=99=80=EF=B8=8F?= =?UTF-8?q?=20Genuflect=20to=20the=20types.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fixtures.py b/tests/fixtures.py index 6708a063..7c9740d9 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -18,7 +18,7 @@ getattr(resources, 'files') getattr(resources, 'as_file') except (ImportError, AttributeError): - import importlib_resources as resources # type: ignore[import-not-found, no-redef] + import importlib_resources as resources # type: ignore[import-not-found, no-redef, unused-ignore] @contextlib.contextmanager From a55f01c752984538435f4baea1efc3ac58b5f006 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 22 Aug 2024 09:42:05 -0400 Subject: [PATCH 26/44] Add reference to development methodology. Ref python/cpython#123144 --- importlib_metadata/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 3f1d942e..6dfaad0c 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -1,3 +1,12 @@ +""" +APIs exposing metadata from third-party Python packages. + +This codebase is shared between importlib.metadata in the stdlib +and importlib_metadata in PyPI. See +https://github.com/python/importlib_metadata/wiki/Development-Methodology +for more detail. +""" + from __future__ import annotations import abc From 57b8aa81d77416805dcaaa22d5d45fef3e8b331c Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Sun, 25 Aug 2024 09:29:10 +0100 Subject: [PATCH 27/44] Add `--fix` flag to ruff pre-commit hook for automatic suggestion of fixes (jaraco/skeleton#140) * Add `--fix` flag to ruff pre-commit hook for automatic suggestion of fixes. This is documented in https://github.com/astral-sh/ruff-pre-commit?tab=readme-ov-file#using-ruff-with-pre-commit and should be safe to apply, because it requires the developer to "manually approve" the suggested changes via `git add`. * Add --unsafe-fixes to ruff pre-commit hoot --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff54405e..8ec58e22 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,4 +3,5 @@ repos: rev: v0.5.6 hooks: - id: ruff + args: [--fix, --unsafe-fixes] - id: ruff-format From d3e83beaec3bdf4a628f2f0ae0a52d21c84e346f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 25 Aug 2024 06:33:23 -0400 Subject: [PATCH 28/44] Disable mypy for now. Ref jaraco/skeleton#143 --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3866a323..1d81b1cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,5 +64,8 @@ type = [ ] - [tool.setuptools_scm] + + +[tool.pytest-enabler.mypy] +# Disabled due to jaraco/skeleton#143 From 3fcabf10b810c8585b858fb81fc3cd8c5efe898d Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 25 Aug 2024 13:26:38 -0400 Subject: [PATCH 29/44] Move overload-overlap disablement to its own line for easier diffs and simpler relevant comments. Ref #142 --- mypy.ini | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mypy.ini b/mypy.ini index 83b0d15c..2806c330 100644 --- a/mypy.ini +++ b/mypy.ini @@ -10,5 +10,6 @@ enable_error_code = ignore-without-code # Support namespace packages per https://github.com/python/mypy/issues/14057 explicit_package_bases = True -# Disable overload-overlap due to many false-positives -disable_error_code = overload-overlap +disable_error_code = + # Disable due to many false positives + overload-overlap From 04c69839d11588f9f6b1e7bfb868d53f48ee52bd Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 26 Aug 2024 16:53:06 -0400 Subject: [PATCH 30/44] Pass mypy and link issues --- importlib_metadata/__init__.py | 4 ++-- pyproject.toml | 4 ---- tests/_path.py | 7 ++++--- tests/fixtures.py | 9 +++------ 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 6dfaad0c..9d8fb980 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -66,7 +66,7 @@ def __str__(self) -> str: return f"No package metadata was found for {self.name}" @property - def name(self) -> str: # type: ignore[override] + def name(self) -> str: # type: ignore[override] # make readonly (name,) = self.args return name @@ -284,7 +284,7 @@ class EntryPoints(tuple): __slots__ = () - def __getitem__(self, name: str) -> EntryPoint: # type: ignore[override] + def __getitem__(self, name: str) -> EntryPoint: # type: ignore[override] # Work with str instead of int """ Get the EntryPoint in self matching name. """ diff --git a/pyproject.toml b/pyproject.toml index c00be7ed..2e5e40c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,3 @@ type = [ [tool.setuptools_scm] - - -[tool.pytest-enabler.mypy] -# Disabled due to jaraco/skeleton#143 diff --git a/tests/_path.py b/tests/_path.py index 81ab76ac..30a6c15d 100644 --- a/tests/_path.py +++ b/tests/_path.py @@ -28,12 +28,12 @@ def symlink_to(self, target): ... # pragma: no cover def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: - return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] + return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] # jaraco/jaraco.path#4 def build( spec: FilesSpec, - prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] + prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] # jaraco/jaraco.path#4 ): """ Build a set of files/directories, as described by the spec. @@ -67,7 +67,8 @@ def build( @functools.singledispatch def create(content: Union[str, bytes, FilesSpec], path): path.mkdir(exist_ok=True) - build(content, prefix=path) # type: ignore[arg-type] + # Mypy only looks at the signature of the main singledispatch method. So it must contain the complete Union + build(content, prefix=path) # type: ignore[arg-type] # python/mypy#11727 @create.register diff --git a/tests/fixtures.py b/tests/fixtures.py index 7c9740d9..8e692f86 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -12,13 +12,10 @@ from .compat.py39 import os_helper from .compat.py312 import import_helper -try: +if sys.version_info >= (3, 9): from importlib import resources - - getattr(resources, 'files') - getattr(resources, 'as_file') -except (ImportError, AttributeError): - import importlib_resources as resources # type: ignore[import-not-found, no-redef, unused-ignore] +else: + import importlib_resources as resources @contextlib.contextmanager From 76eebe0eb4632d7658f4fdaac119211313684f8b Mon Sep 17 00:00:00 2001 From: Daniel Hollas Date: Tue, 27 Aug 2024 15:31:57 +0100 Subject: [PATCH 31/44] Defer import of zipp --- importlib_metadata/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index 6dfaad0c..e9af4972 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -29,8 +29,6 @@ from itertools import starmap from typing import Any, Iterable, List, Mapping, Match, Optional, Set, cast -from zipp.compat.overlay import zipfile - from . import _meta from ._collections import FreezableDefaultDict, Pair from ._compat import ( @@ -777,6 +775,8 @@ def children(self): return [] def zip_children(self): + from zipp.compat.overlay import zipfile + zip_path = zipfile.Path(self.root) names = zip_path.root.namelist() self.joinpath = zip_path.joinpath From e0b4f09ed38845178d1bc5a2d8cb3d13ba69740f Mon Sep 17 00:00:00 2001 From: Daniel Hollas Date: Tue, 27 Aug 2024 15:49:58 +0100 Subject: [PATCH 32/44] Defer json import --- importlib_metadata/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index e9af4972..d1b0d92d 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -14,7 +14,6 @@ import email import functools import itertools -import json import operator import os import pathlib @@ -673,6 +672,8 @@ def origin(self): return self._load_json('direct_url.json') def _load_json(self, filename): + import json + return pass_none(json.loads)( self.read_text(filename), object_hook=lambda data: types.SimpleNamespace(**data), From 8436e8142685cc5378ecaea3311a6172ec8e34c0 Mon Sep 17 00:00:00 2001 From: Daniel Hollas Date: Tue, 27 Aug 2024 16:04:41 +0100 Subject: [PATCH 33/44] Defer platform import --- importlib_metadata/_compat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/importlib_metadata/_compat.py b/importlib_metadata/_compat.py index 01356d69..e78ff59d 100644 --- a/importlib_metadata/_compat.py +++ b/importlib_metadata/_compat.py @@ -1,4 +1,3 @@ -import platform import sys __all__ = ['install', 'NullFinder'] @@ -52,5 +51,7 @@ def pypy_partial(val): Workaround for #327. """ + import platform + is_pypy = platform.python_implementation() == 'PyPy' return val + is_pypy From 0c326f3f77b2420163f73d97f8fbd090fa49147d Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 29 Aug 2024 13:13:06 -0400 Subject: [PATCH 34/44] Add a degenerate nitpick_ignore for downstream consumers. Add a 'local' comment to delineate where the skeleton ends and the downstream begins. --- docs/conf.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 32150488..3d956a8c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,3 +1,6 @@ +from __future__ import annotations + + extensions = [ 'sphinx.ext.autodoc', 'jaraco.packaging.sphinx', @@ -30,6 +33,7 @@ # Be strict about any broken references nitpicky = True +nitpick_ignore: list[tuple[str, str]] = [] # Include Python intersphinx mapping to prevent failures # jaraco/skeleton#51 @@ -40,3 +44,5 @@ # Preserve authored syntax for defaults autodoc_preserve_defaults = True + +# local From cae15af2d0c34fca473bf5425c23da378d1b0419 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 29 Aug 2024 15:25:16 -0400 Subject: [PATCH 35/44] Update tests/_path.py with jaraco.path 3.7.2 --- tests/_path.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/tests/_path.py b/tests/_path.py index 81ab76ac..c66cf5f8 100644 --- a/tests/_path.py +++ b/tests/_path.py @@ -1,8 +1,13 @@ -# from jaraco.path 3.7.1 +# from jaraco.path 3.7.2 + +from __future__ import annotations import functools import pathlib -from typing import Dict, Protocol, Union, runtime_checkable +from typing import TYPE_CHECKING, Mapping, Protocol, Union, runtime_checkable + +if TYPE_CHECKING: + from typing_extensions import Self class Symlink(str): @@ -11,29 +16,25 @@ class Symlink(str): """ -FilesSpec = Dict[str, Union[str, bytes, Symlink, 'FilesSpec']] +FilesSpec = Mapping[str, Union[str, bytes, Symlink, 'FilesSpec']] @runtime_checkable class TreeMaker(Protocol): - def __truediv__(self, *args, **kwargs): ... # pragma: no cover - - def mkdir(self, **kwargs): ... # pragma: no cover - - def write_text(self, content, **kwargs): ... # pragma: no cover - - def write_bytes(self, content): ... # pragma: no cover - - def symlink_to(self, target): ... # pragma: no cover + def __truediv__(self, other, /) -> Self: ... + def mkdir(self, *, exist_ok) -> object: ... + def write_text(self, content, /, *, encoding) -> object: ... + def write_bytes(self, content, /) -> object: ... + def symlink_to(self, target, /) -> object: ... -def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: - return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] +def _ensure_tree_maker(obj: str | TreeMaker) -> TreeMaker: + return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) def build( spec: FilesSpec, - prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] + prefix: str | TreeMaker = pathlib.Path(), ): """ Build a set of files/directories, as described by the spec. @@ -65,23 +66,24 @@ def build( @functools.singledispatch -def create(content: Union[str, bytes, FilesSpec], path): +def create(content: str | bytes | FilesSpec, path: TreeMaker) -> None: path.mkdir(exist_ok=True) - build(content, prefix=path) # type: ignore[arg-type] + # Mypy only looks at the signature of the main singledispatch method. So it must contain the complete Union + build(content, prefix=path) # type: ignore[arg-type] # python/mypy#11727 @create.register -def _(content: bytes, path): +def _(content: bytes, path: TreeMaker) -> None: path.write_bytes(content) @create.register -def _(content: str, path): +def _(content: str, path: TreeMaker) -> None: path.write_text(content, encoding='utf-8') @create.register -def _(content: Symlink, path): +def _(content: Symlink, path: TreeMaker) -> None: path.symlink_to(content) From 2beb8b0c9d0f7046370e7c58c4e6baaf35154a16 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 29 Aug 2024 16:26:28 -0400 Subject: [PATCH 36/44] Add support for linking usernames. Closes jaraco/skeleton#144 --- docs/conf.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 3d956a8c..d5745d62 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,4 +45,13 @@ # Preserve authored syntax for defaults autodoc_preserve_defaults = True +# Add support for linking usernames, PyPI projects, Wikipedia pages +github_url = 'https://github.com/' +extlinks = { + 'user': (f'{github_url}%s', '@%s'), + 'pypi': ('https://pypi.org/project/%s', '%s'), + 'wiki': ('https://wikipedia.org/wiki/%s', '%s'), +} +extensions += ['sphinx.ext.extlinks'] + # local From 790fa6e6feb9a93d39135494819b12e9df8a7bba Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 29 Aug 2024 16:53:52 -0400 Subject: [PATCH 37/44] Include the trailing slash in disable_error_code(overload-overlap), also required for clean diffs. Ref jaraco/skeleton#142 --- mypy.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy.ini b/mypy.ini index 2806c330..efcb8cbc 100644 --- a/mypy.ini +++ b/mypy.ini @@ -12,4 +12,4 @@ explicit_package_bases = True disable_error_code = # Disable due to many false positives - overload-overlap + overload-overlap, From d11b67fed9f21503ca369e33c917a8038994ce0b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2024 09:58:23 -0400 Subject: [PATCH 38/44] Add comment to protect the deferred import. --- importlib_metadata/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index e9af4972..9b912f8e 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -775,6 +775,7 @@ def children(self): return [] def zip_children(self): + # deferred for performance (python/importlib_metadata#502) from zipp.compat.overlay import zipfile zip_path = zipfile.Path(self.root) From e3ce33b45e572824b482049570cac13da543999b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2024 09:59:03 -0400 Subject: [PATCH 39/44] Add news fragment. --- newsfragments/502.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/502.feature.rst diff --git a/newsfragments/502.feature.rst b/newsfragments/502.feature.rst new file mode 100644 index 00000000..20659bb8 --- /dev/null +++ b/newsfragments/502.feature.rst @@ -0,0 +1 @@ +Deferred import of zipfile.Path \ No newline at end of file From 18eb2da0ee267394c1735bec5b1d9f2b0fa77dd9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2024 10:13:51 -0400 Subject: [PATCH 40/44] Revert "Defer platform import" This reverts commit 8436e8142685cc5378ecaea3311a6172ec8e34c0. --- importlib_metadata/_compat.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/importlib_metadata/_compat.py b/importlib_metadata/_compat.py index e78ff59d..01356d69 100644 --- a/importlib_metadata/_compat.py +++ b/importlib_metadata/_compat.py @@ -1,3 +1,4 @@ +import platform import sys __all__ = ['install', 'NullFinder'] @@ -51,7 +52,5 @@ def pypy_partial(val): Workaround for #327. """ - import platform - is_pypy = platform.python_implementation() == 'PyPy' return val + is_pypy From 3f78dc17786e0e0290db450e843ac494af0158e9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2024 10:15:30 -0400 Subject: [PATCH 41/44] Add comment to protect the deferred import. --- importlib_metadata/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index d1b0d92d..58bbd95e 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -672,6 +672,7 @@ def origin(self): return self._load_json('direct_url.json') def _load_json(self, filename): + # Deferred for performance (python/importlib_metadata#503) import json return pass_none(json.loads)( From 2a3f50d8bbd41fc831676e7dc89d84c605c85760 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2024 10:15:46 -0400 Subject: [PATCH 42/44] Add news fragment. --- newsfragments/503.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/503.feature.rst diff --git a/newsfragments/503.feature.rst b/newsfragments/503.feature.rst new file mode 100644 index 00000000..7e6bdc7a --- /dev/null +++ b/newsfragments/503.feature.rst @@ -0,0 +1 @@ +Deferred import of json \ No newline at end of file From afa39e8e08b48fbedd3b8ac94cf58de39ff09c35 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2024 10:30:18 -0400 Subject: [PATCH 43/44] Back out changes to tests._path --- tests/_path.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/_path.py b/tests/_path.py index 30a6c15d..81ab76ac 100644 --- a/tests/_path.py +++ b/tests/_path.py @@ -28,12 +28,12 @@ def symlink_to(self, target): ... # pragma: no cover def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: - return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] # jaraco/jaraco.path#4 + return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] def build( spec: FilesSpec, - prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] # jaraco/jaraco.path#4 + prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] ): """ Build a set of files/directories, as described by the spec. @@ -67,8 +67,7 @@ def build( @functools.singledispatch def create(content: Union[str, bytes, FilesSpec], path): path.mkdir(exist_ok=True) - # Mypy only looks at the signature of the main singledispatch method. So it must contain the complete Union - build(content, prefix=path) # type: ignore[arg-type] # python/mypy#11727 + build(content, prefix=path) # type: ignore[arg-type] @create.register From b34810b1e0665580a91ea19b6317a1890ecd42c1 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 11 Sep 2024 10:50:50 -0400 Subject: [PATCH 44/44] Finalize --- NEWS.rst | 11 +++++++++++ newsfragments/+d7832466.feature.rst | 1 - newsfragments/502.feature.rst | 1 - newsfragments/503.feature.rst | 1 - 4 files changed, 11 insertions(+), 3 deletions(-) delete mode 100644 newsfragments/+d7832466.feature.rst delete mode 100644 newsfragments/502.feature.rst delete mode 100644 newsfragments/503.feature.rst diff --git a/NEWS.rst b/NEWS.rst index f4a37fdf..4e75f3b0 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,14 @@ +v8.5.0 +====== + +Features +-------- + +- Deferred import of zipfile.Path (#502) +- Deferred import of json (#503) +- Rely on zipp overlay for zipfile.Path. + + v8.4.0 ====== diff --git a/newsfragments/+d7832466.feature.rst b/newsfragments/+d7832466.feature.rst deleted file mode 100644 index 3f3f3162..00000000 --- a/newsfragments/+d7832466.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Rely on zipp overlay for zipfile.Path. \ No newline at end of file diff --git a/newsfragments/502.feature.rst b/newsfragments/502.feature.rst deleted file mode 100644 index 20659bb8..00000000 --- a/newsfragments/502.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Deferred import of zipfile.Path \ No newline at end of file diff --git a/newsfragments/503.feature.rst b/newsfragments/503.feature.rst deleted file mode 100644 index 7e6bdc7a..00000000 --- a/newsfragments/503.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Deferred import of json \ No newline at end of file