Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/pypa/setuptools into pkg_re…
Browse files Browse the repository at this point in the history
…sources-type-global-variables
  • Loading branch information
Avasam committed May 7, 2024
2 parents 57f26ff + b3fc00f commit acaa310
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 106 deletions.
3 changes: 3 additions & 0 deletions newsfragments/4262.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Improved `AttributeError` error message if ``pkg_resources.EntryPoint.require`` is called without extras or distribution
Gracefully "do nothing" when trying to activate a ``pkg_resources.Distribution`` with a `None` location, rather than raising a `TypeError`
-- by :user:`Avasam`
3 changes: 3 additions & 0 deletions newsfragments/4322.removal.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Remove ``setuptools.convert_path`` after long deprecation period.
This function was never defined by ``setuptools`` itself, but rather a
side-effect of an import for internal usage.
3 changes: 3 additions & 0 deletions newsfragments/4322.removal.2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Remove fallback for customisations of ``distutils``' ``build.sub_command`` after long
deprecated period.
Users are advised to import ``build`` directly from ``setuptools.command.build``.
66 changes: 37 additions & 29 deletions pkg_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,16 @@
import time
import re
import types
from typing import TYPE_CHECKING, List, Protocol
from typing import (
TYPE_CHECKING,
List,
Protocol,
Any,
Callable,
Dict,
Iterable,
Optional,
)
import zipfile
import zipimport
import warnings
Expand Down Expand Up @@ -80,12 +89,6 @@
__import__('pkg_resources.extern.packaging.markers')
__import__('pkg_resources.extern.packaging.utils')

# declare some globals that will be defined later to
# satisfy the linters.
_distribution_finders = None
_namespace_handlers = None
_namespace_packages = None


warnings.warn(
"pkg_resources is deprecated as an API. "
Expand All @@ -108,11 +111,10 @@ class PEP440Warning(RuntimeWarning):
parse_version = packaging.version.Version


_state_vars = {}
_state_vars: Dict[str, Any] = {}


def _declare_state(vartype, **kw):
globals().update(kw)
def _declare_state(vartype: str, **kw: object) -> None:
_state_vars.update(dict.fromkeys(kw, vartype))


Expand Down Expand Up @@ -908,10 +910,10 @@ def find_plugins(self, plugin_env, full_env=None, installer=None, fallback=True)
# success, no need to try any more versions of this project
break

distributions = list(distributions)
distributions.sort()
sorted_distributions = list(distributions)
sorted_distributions.sort()

return distributions, error_info
return sorted_distributions, error_info

def require(self, *requirements):
"""Ensure that distributions matching `requirements` are activated
Expand Down Expand Up @@ -1623,7 +1625,7 @@ def _validate_resource_path(path):
)

def _get(self, path) -> bytes:
if hasattr(self.loader, 'get_data'):
if hasattr(self.loader, 'get_data') and self.loader:
return self.loader.get_data(path)
raise NotImplementedError(
"Can't perform this operation for loaders without 'get_data()'"
Expand Down Expand Up @@ -2013,7 +2015,10 @@ def __init__(self, importer):
self._setup_prefix()


_declare_state('dict', _distribution_finders={})
_distribution_finders: Dict[
type, Callable[[object, str, bool], Iterable["Distribution"]]
] = {}
_declare_state('dict', _distribution_finders=_distribution_finders)


def register_finder(importer_type, distribution_finder):
Expand Down Expand Up @@ -2186,8 +2191,12 @@ def resolve_egg_link(path):

register_finder(importlib.machinery.FileFinder, find_on_path)

_declare_state('dict', _namespace_handlers={})
_declare_state('dict', _namespace_packages={})
_namespace_handlers: Dict[
type, Callable[[object, str, str, types.ModuleType], Optional[str]]
] = {}
_declare_state('dict', _namespace_handlers=_namespace_handlers)
_namespace_packages: Dict[Optional[str], List[str]] = {}
_declare_state('dict', _namespace_packages=_namespace_packages)


def register_namespace_handler(importer_type, namespace_handler):
Expand Down Expand Up @@ -2478,8 +2487,9 @@ def resolve(self):
raise ImportError(str(exc)) from exc

def require(self, env=None, installer=None):
if self.extras and not self.dist:
raise UnknownExtra("Can't require() without a distribution", self)
if not self.dist:
error_cls = UnknownExtra if self.extras else AttributeError
raise error_cls("Can't require() without a distribution", self)

# Get the requirements for this entry point with all its extras and
# then resolve them. We have to pass `extras` along when resolving so
Expand Down Expand Up @@ -2545,11 +2555,11 @@ def parse_group(cls, group, lines, dist=None):
def parse_map(cls, data, dist=None):
"""Parse a map of entry point groups"""
if isinstance(data, dict):
data = data.items()
_data = data.items()
else:
data = split_sections(data)
_data = split_sections(data)
maps = {}
for group, lines in data:
for group, lines in _data:
if group is None:
if not lines:
continue
Expand Down Expand Up @@ -2811,7 +2821,7 @@ def activate(self, path=None, replace=False):
if path is None:
path = sys.path
self.insert_on(path, replace=replace)
if path is sys.path:
if path is sys.path and self.location is not None:
fixup_namespace_packages(self.location)
for pkg in self._get_metadata('namespace_packages.txt'):
if pkg in sys.modules:
Expand Down Expand Up @@ -2879,15 +2889,13 @@ def load_entry_point(self, group, name):

def get_entry_map(self, group=None):
"""Return the entry point map for `group`, or the full entry map"""
try:
ep_map = self._ep_map
except AttributeError:
ep_map = self._ep_map = EntryPoint.parse_map(
if not hasattr(self, "_ep_map"):
self._ep_map = EntryPoint.parse_map(
self._get_metadata('entry_points.txt'), self
)
if group is not None:
return ep_map.get(group, {})
return ep_map
return self._ep_map.get(group, {})
return self._ep_map

def get_entry_info(self, group, name):
"""Return the EntryPoint object for `group`+`name`, or ``None``"""
Expand Down
17 changes: 0 additions & 17 deletions setuptools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import _distutils_hack.override # noqa: F401
import distutils.core
from distutils.errors import DistutilsOptionError
from distutils.util import convert_path as _convert_path

from . import logging, monkey
from . import version as _version_module
Expand Down Expand Up @@ -247,22 +246,6 @@ def findall(dir=os.curdir):
return list(files)


@functools.wraps(_convert_path)
def convert_path(pathname):
SetuptoolsDeprecationWarning.emit(
"Access to implementation detail",
"""
The function `convert_path` is not provided by setuptools itself,
and therefore not part of the public API.
Its direct usage by 3rd-party packages is considered improper and the function
may be removed in the future.
""",
due_date=(2023, 12, 13), # initial deprecation 2022-03-25, see #3201
)
return _convert_path(pathname)


class sic(str):
"""Treat this string as-is (https://en.wikipedia.org/wiki/Sic)"""

Expand Down
18 changes: 0 additions & 18 deletions setuptools/command/build.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
from typing import Dict, List, Protocol
from distutils.command.build import build as _build

from ..warnings import SetuptoolsDeprecationWarning

_ORIGINAL_SUBCOMMANDS = {"build_py", "build_clib", "build_ext", "build_scripts"}


class build(_build):
# copy to avoid sharing the object with parent class
sub_commands = _build.sub_commands[:]

def get_sub_commands(self):
subcommands = {cmd[0] for cmd in _build.sub_commands}
if subcommands - _ORIGINAL_SUBCOMMANDS:
SetuptoolsDeprecationWarning.emit(
"Direct usage of `distutils` commands",
"""
It seems that you are using `distutils.command.build` to add
new subcommands. Using `distutils` directly is considered deprecated,
please use `setuptools.command.build`.
""",
due_date=(2023, 12, 13), # Warning introduced in 13 Jun 2022.
see_url="https://peps.python.org/pep-0632/",
)
self.sub_commands = _build.sub_commands
return super().get_sub_commands()


class SubCommand(Protocol):
"""In order to support editable installations (see :pep:`660`) all
Expand Down
36 changes: 1 addition & 35 deletions setuptools/tests/test_build.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
from contextlib import contextmanager
from setuptools import Command, SetuptoolsDeprecationWarning
from setuptools import Command
from setuptools.dist import Distribution
from setuptools.command.build import build
from distutils.command.build import build as distutils_build

import pytest


def test_distribution_gives_setuptools_build_obj(tmpdir_cwd):
Expand All @@ -24,15 +20,6 @@ def test_distribution_gives_setuptools_build_obj(tmpdir_cwd):
assert isinstance(dist.get_command_obj("build"), build)


@contextmanager
def _restore_sub_commands():
orig = distutils_build.sub_commands[:]
try:
yield
finally:
distutils_build.sub_commands = orig


class Subcommand(Command):
"""Dummy command to be used in tests"""

Expand All @@ -44,24 +31,3 @@ def finalize_options(self):

def run(self):
raise NotImplementedError("just to check if the command runs")


@_restore_sub_commands()
def test_subcommand_in_distutils(tmpdir_cwd):
"""
Ensure that sub commands registered in ``distutils`` run,
after instructing the users to migrate to ``setuptools``.
"""
dist = Distribution(
dict(
packages=[],
cmdclass={'subcommand': Subcommand},
)
)
distutils_build.sub_commands.append(('subcommand', None))

warning_msg = "please use .setuptools.command.build."
with pytest.warns(SetuptoolsDeprecationWarning, match=warning_msg):
# For backward compatibility, the subcommand should run anyway:
with pytest.raises(NotImplementedError, match="the command runs"):
dist.run_command("build")
5 changes: 0 additions & 5 deletions setuptools/tests/test_setuptools.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,3 @@ def test_its_own_wheel_does_not_contain_tests(setuptools_wheel):

for member in contents:
assert '/tests/' not in member


def test_convert_path_deprecated():
with pytest.warns(setuptools.SetuptoolsDeprecationWarning):
setuptools.convert_path('setuptools/tests')
3 changes: 1 addition & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ deps =
# Ideally all the dependencies should be set as "extras"
setenv =
PYTHONWARNDEFAULTENCODING = 1
SETUPTOOLS_ENFORCE_DEPRECATION = {env:SETUPTOOLS_ENFORCE_DEPRECATION:0}
# ^-- Temporarily disable enforcement so CI don't fail on due dates
SETUPTOOLS_ENFORCE_DEPRECATION = {env:SETUPTOOLS_ENFORCE_DEPRECATION:1}
commands =
pytest {posargs}
usedevelop = True
Expand Down

0 comments on commit acaa310

Please sign in to comment.