Skip to content

Commit c16ef23

Browse files
jaracoclaude
andcommitted
Move the localization helpers into _compat, keeping _functools in sync.
apply and compose serve only the localize decorators, behavior the stdlib has no use for. With them out of _functools, that module is byte-identical to its importlib.metadata counterpart, so it no longer needs resolving on every downstream sync. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 7a04d49 commit c16ef23

3 files changed

Lines changed: 66 additions & 55 deletions

File tree

‎importlib_metadata/__init__.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
install,
3636
localize,
3737
)
38-
from ._functools import apply, compose, method_cache, noop, pass_none, passthrough
38+
from ._compat._functools import apply, compose
39+
from ._functools import method_cache, noop, pass_none, passthrough
3940
from ._itertools import always_iterable, bucket, unique_everseen
4041
from ._meta import (
4142
IDistribution,
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
Functional helpers needed only by the backport.
3+
4+
``apply`` and ``compose`` exist to serve the localization decorators on
5+
the public API, which the stdlib does not have. Keeping them out of
6+
``_functools`` leaves that module identical to its
7+
``importlib.metadata`` counterpart.
8+
"""
9+
10+
import functools
11+
12+
13+
# From jaraco.functools 4.0.2
14+
def compose(*funcs):
15+
"""
16+
Compose any number of unary functions into a single unary function.
17+
18+
Comparable to
19+
`function composition <https://en.wikipedia.org/wiki/Function_composition>`_
20+
in mathematics:
21+
22+
``h = g ∘ f`` implies ``h(x) = g(f(x))``.
23+
24+
In Python, ``h = compose(g, f)``.
25+
26+
>>> import textwrap
27+
>>> expected = str.strip(textwrap.dedent(compose.__doc__))
28+
>>> strip_and_dedent = compose(str.strip, textwrap.dedent)
29+
>>> strip_and_dedent(compose.__doc__) == expected
30+
True
31+
32+
Compose also allows the innermost function to take arbitrary arguments.
33+
34+
>>> round_three = lambda x: round(x, ndigits=3)
35+
>>> f = compose(round_three, int.__truediv__)
36+
>>> [f(3*x, x+1) for x in range(1,10)]
37+
[1.5, 2.0, 2.25, 2.4, 2.5, 2.571, 2.625, 2.667, 2.7]
38+
"""
39+
40+
def compose_two(f1, f2):
41+
return lambda *args, **kwargs: f1(f2(*args, **kwargs))
42+
43+
return functools.reduce(compose_two, funcs)
44+
45+
46+
def apply(transform):
47+
"""
48+
Decorate a function with a transform function that is
49+
invoked on results returned from the decorated function.
50+
51+
>>> @apply(reversed)
52+
... def get_numbers(start):
53+
... "doc for get_numbers"
54+
... return range(start, start+3)
55+
>>> list(get_numbers(4))
56+
[6, 5, 4]
57+
>>> get_numbers.__doc__
58+
'doc for get_numbers'
59+
"""
60+
61+
def wrap(func):
62+
return functools.wraps(func)(compose(transform, func))
63+
64+
return wrap

‎importlib_metadata/_functools.py‎

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -106,60 +106,6 @@ def wrapper(param, *args, **kwargs):
106106
return wrapper
107107

108108

109-
# From jaraco.functools 4.0.2
110-
def compose(*funcs):
111-
"""
112-
Compose any number of unary functions into a single unary function.
113-
114-
Comparable to
115-
`function composition <https://en.wikipedia.org/wiki/Function_composition>`_
116-
in mathematics:
117-
118-
``h = g ∘ f`` implies ``h(x) = g(f(x))``.
119-
120-
In Python, ``h = compose(g, f)``.
121-
122-
>>> import textwrap
123-
>>> expected = str.strip(textwrap.dedent(compose.__doc__))
124-
>>> strip_and_dedent = compose(str.strip, textwrap.dedent)
125-
>>> strip_and_dedent(compose.__doc__) == expected
126-
True
127-
128-
Compose also allows the innermost function to take arbitrary arguments.
129-
130-
>>> round_three = lambda x: round(x, ndigits=3)
131-
>>> f = compose(round_three, int.__truediv__)
132-
>>> [f(3*x, x+1) for x in range(1,10)]
133-
[1.5, 2.0, 2.25, 2.4, 2.5, 2.571, 2.625, 2.667, 2.7]
134-
"""
135-
136-
def compose_two(f1, f2):
137-
return lambda *args, **kwargs: f1(f2(*args, **kwargs))
138-
139-
return functools.reduce(compose_two, funcs)
140-
141-
142-
def apply(transform):
143-
"""
144-
Decorate a function with a transform function that is
145-
invoked on results returned from the decorated function.
146-
147-
>>> @apply(reversed)
148-
... def get_numbers(start):
149-
... "doc for get_numbers"
150-
... return range(start, start+3)
151-
>>> list(get_numbers(4))
152-
[6, 5, 4]
153-
>>> get_numbers.__doc__
154-
'doc for get_numbers'
155-
"""
156-
157-
def wrap(func):
158-
return functools.wraps(func)(compose(transform, func))
159-
160-
return wrap
161-
162-
163109
# From jaraco.functools 4.4
164110
def noop(*args, **kwargs):
165111
"""

0 commit comments

Comments
 (0)