Skip to content

Commit

Permalink
Using dict as an OrderedDict and allowed using dict as an order…
Browse files Browse the repository at this point in the history
…ed type in `setuptools.dist.check_requirements`
  • Loading branch information
Avasam committed Oct 17, 2024
1 parent 89b4401 commit 2072d98
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 29 deletions.
1 change: 1 addition & 0 deletions newsfragments/4575.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allowed using `dict` as an ordered type in ``setuptools.dist.check_requirements`` -- by :user:`Avasam`
3 changes: 1 addition & 2 deletions setuptools/command/_requirestxt.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
from packaging.requirements import Requirement

from .. import _reqs
from .._reqs import _StrOrIter

# dict can work as an ordered set
_T = TypeVar("_T")
_Ordered = Dict[_T, None]
_ordered = dict
_StrOrIter = _reqs._StrOrIter


def _prepare(
Expand Down
5 changes: 1 addition & 4 deletions setuptools/command/egg_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Create a distribution's .egg-info directory and contents"""

import collections
import functools
import os
import re
Expand Down Expand Up @@ -211,11 +210,9 @@ def save_version_info(self, filename):
build tag. Install build keys in a deterministic order
to avoid arbitrary reordering on subsequent builds.
"""
egg_info = collections.OrderedDict()
# follow the order these keys would have been added
# when PYTHONHASHSEED=0
egg_info['tag_build'] = self.tags()
egg_info['tag_date'] = 0
egg_info = dict(tag_build=self.tags(), tag_date=0)
edit_config(filename, dict(egg_info=egg_info))

def finalize_options(self):
Expand Down
29 changes: 15 additions & 14 deletions setuptools/dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
from typing import (
TYPE_CHECKING,
Any,
Dict,
List,
MutableMapping,
NoReturn,
Sequence,
Tuple,
Union,
overload,
)

from more_itertools import partition, unique_everseen
Expand All @@ -30,7 +30,6 @@
command as _, # noqa: F401 # imported for side-effects
)
from ._importlib import metadata
from ._reqs import _StrOrIter
from .config import pyprojecttoml, setupcfg
from .discovery import ConfigDiscovery
from .monkey import get_unpatched
Expand Down Expand Up @@ -63,7 +62,13 @@
"""
_Sequence: TypeAlias = Union[Tuple[str, ...], List[str]]
# This is how stringifying _Sequence would look in Python 3.10
_requence_type_repr = "tuple[str, ...] | list[str]"
_sequence_type_repr = "tuple[str, ...] | list[str]"
_OrderedStrSequence: TypeAlias = Union[str, Dict[str, Any], Sequence[str]]
"""
:meta private:
Avoid single-use iterable. Disallow sets.
A poor approximation of an OrderedSequence (dict doesn't match a Sequence).
"""


def __getattr__(name: str) -> Any: # pragma: no cover
Expand Down Expand Up @@ -97,7 +102,7 @@ def assert_string_list(dist, attr: str, value: _Sequence) -> None:
assert ''.join(value) != value
except (TypeError, ValueError, AttributeError, AssertionError) as e:
raise DistutilsSetupError(
f"{attr!r} must be of type <{_requence_type_repr}> (got {value!r})"
f"{attr!r} must be of type <{_sequence_type_repr}> (got {value!r})"
) from e


Expand Down Expand Up @@ -173,15 +178,11 @@ def invalid_unless_false(dist, attr, value):
raise DistutilsSetupError(f"{attr} is invalid.")


@overload
def check_requirements(dist, attr: str, value: set | dict) -> NoReturn: ...
@overload
def check_requirements(dist, attr: str, value: _StrOrIter) -> None: ...
def check_requirements(dist, attr: str, value: _StrOrIter) -> None:
def check_requirements(dist, attr: str, value: _OrderedStrSequence) -> None:
"""Verify that install_requires is a valid requirements list"""
try:
list(_reqs.parse(value))
if isinstance(value, (dict, set)):
if isinstance(value, set):
raise TypeError("Unordered types are not allowed")
except (TypeError, ValueError) as error:
msg = (
Expand Down Expand Up @@ -810,7 +811,7 @@ def _exclude_misc(self, name: str, value: _Sequence) -> None:
"""Handle 'exclude()' for list/tuple attrs without a special handler"""
if not isinstance(value, _sequence):
raise DistutilsSetupError(
f"{name}: setting must be of type <{_requence_type_repr}> (got {value!r})"
f"{name}: setting must be of type <{_sequence_type_repr}> (got {value!r})"
)
try:
old = getattr(self, name)
Expand All @@ -828,7 +829,7 @@ def _include_misc(self, name: str, value: _Sequence) -> None:

if not isinstance(value, _sequence):
raise DistutilsSetupError(
f"{name}: setting must be of type <{_requence_type_repr}> (got {value!r})"
f"{name}: setting must be of type <{_sequence_type_repr}> (got {value!r})"
)
try:
old = getattr(self, name)
Expand Down Expand Up @@ -870,7 +871,7 @@ def exclude(self, **attrs):
def _exclude_packages(self, packages: _Sequence) -> None:
if not isinstance(packages, _sequence):
raise DistutilsSetupError(
f"packages: setting must be of type <{_requence_type_repr}> (got {packages!r})"
f"packages: setting must be of type <{_sequence_type_repr}> (got {packages!r})"
)
list(map(self.exclude_package, packages))

Expand Down
1 change: 0 additions & 1 deletion setuptools/tests/test_core_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,6 @@ def test_parity_with_metadata_from_pypa_wheel(tmp_path):
python_requires=">=3.8",
install_requires="""
packaging==23.2
ordered-set==3.1.1
more-itertools==8.8.0; extra == "other"
jaraco.text==3.7.0
importlib-resources==5.10.2; python_version<"3.8"
Expand Down
10 changes: 2 additions & 8 deletions setuptools/tests/test_dist.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import collections
import os
import re
import urllib.parse
Expand Down Expand Up @@ -72,15 +71,10 @@ def sdist_with_index(distname, version):


def test_provides_extras_deterministic_order():
extras = collections.OrderedDict()
extras['a'] = ['foo']
extras['b'] = ['bar']
attrs = dict(extras_require=extras)
attrs = dict(extras_require=dict(a=['foo'], b=['bar']))
dist = Distribution(attrs)
assert list(dist.metadata.provides_extras) == ['a', 'b']
attrs['extras_require'] = collections.OrderedDict(
reversed(list(attrs['extras_require'].items()))
)
attrs['extras_require'] = dict(reversed(attrs['extras_require'].items()))
dist = Distribution(attrs)
assert list(dist.metadata.provides_extras) == ['b', 'a']

Expand Down

0 comments on commit 2072d98

Please sign in to comment.