dependence 1.1.1__py3-none-any.whl → 1.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dependence/_utilities.py +81 -29
- dependence/freeze.py +36 -16
- dependence/update.py +8 -0
- {dependence-1.1.1.dist-info → dependence-1.1.3.dist-info}/METADATA +1 -1
- dependence-1.1.3.dist-info/RECORD +11 -0
- dependence-1.1.1.dist-info/RECORD +0 -11
- {dependence-1.1.1.dist-info → dependence-1.1.3.dist-info}/WHEEL +0 -0
- {dependence-1.1.1.dist-info → dependence-1.1.3.dist-info}/entry_points.txt +0 -0
dependence/_utilities.py
CHANGED
|
@@ -95,6 +95,44 @@ def _undefined() -> Undefined:
|
|
|
95
95
|
return UNDEFINED
|
|
96
96
|
|
|
97
97
|
|
|
98
|
+
cache: Any
|
|
99
|
+
try:
|
|
100
|
+
from functools import cache # type: ignore
|
|
101
|
+
except ImportError:
|
|
102
|
+
from functools import lru_cache
|
|
103
|
+
|
|
104
|
+
cache = lru_cache(maxsize=None)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def as_tuple(
|
|
108
|
+
user_function: Callable[..., Iterable[Any]],
|
|
109
|
+
) -> Callable[..., tuple[Any, ...]]:
|
|
110
|
+
"""
|
|
111
|
+
This is a decorator which will return an iterable as a tuple.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def wrapper(*args: Any, **kwargs: Any) -> tuple[Any, ...]:
|
|
115
|
+
return tuple(user_function(*args, **kwargs) or ())
|
|
116
|
+
|
|
117
|
+
return functools.update_wrapper(wrapper, user_function)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def as_cached_tuple(
|
|
121
|
+
maxsize: int | None = None, *, typed: bool = False
|
|
122
|
+
) -> Callable[[Callable[..., Iterable[Any]]], Callable[..., tuple[Any, ...]]]:
|
|
123
|
+
"""
|
|
124
|
+
This is a decorator which will return an iterable as a tuple,
|
|
125
|
+
and cache that tuple.
|
|
126
|
+
|
|
127
|
+
Parameters:
|
|
128
|
+
|
|
129
|
+
- maxsize (int|None) = None: The maximum number of items to cache.
|
|
130
|
+
- typed (bool) = False: For class methods, should the cache be distinct for
|
|
131
|
+
sub-classes?
|
|
132
|
+
"""
|
|
133
|
+
return functools.lru_cache(maxsize=maxsize, typed=typed)(as_tuple)
|
|
134
|
+
|
|
135
|
+
|
|
98
136
|
def iter_distinct(items: Iterable[Hashable]) -> Iterable:
|
|
99
137
|
"""
|
|
100
138
|
Yield distinct elements, preserving order
|
|
@@ -418,14 +456,8 @@ def iter_configuration_files(path: str | Path) -> Iterable[Path | str]:
|
|
|
418
456
|
yield path
|
|
419
457
|
|
|
420
458
|
|
|
421
|
-
class _EditablePackageMetadata(TypedDict):
|
|
422
|
-
name: str
|
|
423
|
-
version: str
|
|
424
|
-
editable_project_location: str
|
|
425
|
-
|
|
426
|
-
|
|
427
459
|
def _iter_editable_distribution_locations() -> Iterable[tuple[str, str]]:
|
|
428
|
-
metadata:
|
|
460
|
+
metadata: _PackageMetadata
|
|
429
461
|
for metadata in json.loads(
|
|
430
462
|
check_output(
|
|
431
463
|
(
|
|
@@ -453,10 +485,38 @@ def get_editable_distributions_locations() -> dict[str, str]:
|
|
|
453
485
|
return dict(_iter_editable_distribution_locations())
|
|
454
486
|
|
|
455
487
|
|
|
488
|
+
class _PackageMetadata(TypedDict, total=False):
|
|
489
|
+
name: str
|
|
490
|
+
version: str
|
|
491
|
+
editable_project_location: str
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@cache
|
|
495
|
+
def map_pip_list() -> dict[str, _PackageMetadata]:
|
|
496
|
+
names_package_metadata: dict[str, _PackageMetadata] = {}
|
|
497
|
+
package_metadata: _PackageMetadata
|
|
498
|
+
for package_metadata in json.loads(
|
|
499
|
+
check_output(
|
|
500
|
+
(
|
|
501
|
+
sys.executable,
|
|
502
|
+
"-m",
|
|
503
|
+
"pip",
|
|
504
|
+
"list",
|
|
505
|
+
"--format=json",
|
|
506
|
+
)
|
|
507
|
+
)
|
|
508
|
+
):
|
|
509
|
+
names_package_metadata[normalize_name(package_metadata["name"])] = (
|
|
510
|
+
package_metadata
|
|
511
|
+
)
|
|
512
|
+
return names_package_metadata
|
|
513
|
+
|
|
514
|
+
|
|
456
515
|
def cache_clear() -> None:
|
|
457
516
|
"""
|
|
458
517
|
Clear distribution metadata caches
|
|
459
518
|
"""
|
|
519
|
+
map_pip_list.cache_clear()
|
|
460
520
|
get_installed_distributions.cache_clear()
|
|
461
521
|
get_editable_distributions_locations.cache_clear()
|
|
462
522
|
is_editable.cache_clear()
|
|
@@ -482,7 +542,13 @@ def get_installed_distributions() -> dict[str, Distribution]:
|
|
|
482
542
|
refresh_editable_distributions()
|
|
483
543
|
installed: dict[str, Distribution] = {}
|
|
484
544
|
for distribution in _get_distributions():
|
|
485
|
-
|
|
545
|
+
name: str = distribution.metadata["Name"]
|
|
546
|
+
if distribution.version is None:
|
|
547
|
+
# If no version can be found, use pip to find the version
|
|
548
|
+
distribution.metadata["Version"] = (
|
|
549
|
+
map_pip_list().get(name, {}).get("version")
|
|
550
|
+
)
|
|
551
|
+
installed[normalize_name(name)] = distribution
|
|
486
552
|
return installed
|
|
487
553
|
|
|
488
554
|
|
|
@@ -975,6 +1041,10 @@ def _get_requirement_name(requirement: Requirement) -> str:
|
|
|
975
1041
|
return normalize_name(requirement.name)
|
|
976
1042
|
|
|
977
1043
|
|
|
1044
|
+
@deprecated(
|
|
1045
|
+
"dependence._utilities.install_requirement is deprecated and will be "
|
|
1046
|
+
"removed in a future release."
|
|
1047
|
+
)
|
|
978
1048
|
def install_requirement(requirement: str | Requirement) -> None:
|
|
979
1049
|
"""
|
|
980
1050
|
Install a requirement
|
|
@@ -1079,31 +1149,15 @@ def _install_requirement(
|
|
|
1079
1149
|
cache_clear()
|
|
1080
1150
|
|
|
1081
1151
|
|
|
1082
|
-
def
|
|
1083
|
-
requirement: Requirement,
|
|
1152
|
+
def _get_installed_distribution(
|
|
1084
1153
|
name: str,
|
|
1085
|
-
*,
|
|
1086
|
-
reinstall: bool = True,
|
|
1087
|
-
echo: bool = False,
|
|
1088
1154
|
) -> Distribution | None:
|
|
1089
1155
|
if name in _BUILTIN_DISTRIBUTION_NAMES:
|
|
1090
1156
|
return None
|
|
1091
1157
|
try:
|
|
1092
1158
|
return get_installed_distributions()[name]
|
|
1093
1159
|
except KeyError:
|
|
1094
|
-
|
|
1095
|
-
raise
|
|
1096
|
-
if echo:
|
|
1097
|
-
warn(
|
|
1098
|
-
f'The required distribution "{name}" was not installed, '
|
|
1099
|
-
"attempting to install it now...",
|
|
1100
|
-
stacklevel=2,
|
|
1101
|
-
)
|
|
1102
|
-
# Attempt to install the requirement...
|
|
1103
|
-
install_requirement(requirement)
|
|
1104
|
-
return _get_requirement_distribution(
|
|
1105
|
-
requirement, name, reinstall=False, echo=echo
|
|
1106
|
-
)
|
|
1160
|
+
return None
|
|
1107
1161
|
|
|
1108
1162
|
|
|
1109
1163
|
def _iter_distribution_requirements(
|
|
@@ -1140,9 +1194,7 @@ def _iter_requirement_names(
|
|
|
1140
1194
|
# Ensure we don't follow the same requirement again, causing cyclic
|
|
1141
1195
|
# recursion
|
|
1142
1196
|
exclude.add(name)
|
|
1143
|
-
distribution: Distribution | None =
|
|
1144
|
-
requirement, name, echo=echo
|
|
1145
|
-
)
|
|
1197
|
+
distribution: Distribution | None = _get_installed_distribution(name)
|
|
1146
1198
|
if distribution is None:
|
|
1147
1199
|
return ()
|
|
1148
1200
|
requirements: tuple[Requirement, ...] = tuple(
|
dependence/freeze.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import os
|
|
4
5
|
from collections.abc import Iterable, MutableSet
|
|
5
6
|
from fnmatch import fnmatch
|
|
6
7
|
from functools import partial
|
|
7
|
-
from importlib.metadata import Distribution
|
|
8
|
-
from importlib.metadata import distribution as _get_distribution
|
|
9
8
|
from itertools import chain
|
|
10
9
|
from pathlib import Path
|
|
11
10
|
from typing import TYPE_CHECKING, cast
|
|
@@ -14,7 +13,6 @@ from dependence._utilities import (
|
|
|
14
13
|
get_distribution,
|
|
15
14
|
get_required_distribution_names,
|
|
16
15
|
get_requirement_string_distribution_name,
|
|
17
|
-
install_requirement,
|
|
18
16
|
iter_configuration_file_requirement_strings,
|
|
19
17
|
iter_configuration_files,
|
|
20
18
|
iter_distinct,
|
|
@@ -22,6 +20,9 @@ from dependence._utilities import (
|
|
|
22
20
|
normalize_name,
|
|
23
21
|
)
|
|
24
22
|
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from importlib.metadata import Distribution
|
|
25
|
+
|
|
25
26
|
_DO_NOT_PIN_DISTRIBUTION_NAMES: MutableSet[str] = {
|
|
26
27
|
"importlib-metadata",
|
|
27
28
|
"importlib-resources",
|
|
@@ -119,7 +120,7 @@ def get_frozen_requirements( # noqa: C901
|
|
|
119
120
|
elif not isinstance(no_version, tuple):
|
|
120
121
|
no_version = tuple(no_version)
|
|
121
122
|
# Separate requirement strings from requirement files
|
|
122
|
-
configuration_files:
|
|
123
|
+
configuration_files: dict[str, dict[str, tuple[str, ...]]] = {}
|
|
123
124
|
requirement_strings: MutableSet[str] = set()
|
|
124
125
|
requirement: str | Path
|
|
125
126
|
for requirement in requirements:
|
|
@@ -129,21 +130,38 @@ def get_frozen_requirements( # noqa: C901
|
|
|
129
130
|
iter_configuration_files(requirement)
|
|
130
131
|
)
|
|
131
132
|
if requirement_configuration_files:
|
|
132
|
-
|
|
133
|
+
is_directory: bool = os.path.isdir(requirement)
|
|
134
|
+
for (
|
|
135
|
+
requirement_configuration_file
|
|
136
|
+
) in requirement_configuration_files:
|
|
137
|
+
configuration_files[requirement_configuration_file] = (
|
|
138
|
+
{"include_pointers": ("/project",)}
|
|
139
|
+
if (
|
|
140
|
+
is_directory
|
|
141
|
+
and os.path.basename(
|
|
142
|
+
requirement_configuration_file
|
|
143
|
+
).lower()
|
|
144
|
+
== "pyproject.toml"
|
|
145
|
+
)
|
|
146
|
+
else {
|
|
147
|
+
"include_pointers": include_pointers,
|
|
148
|
+
"exclude_pointers": exclude_pointers,
|
|
149
|
+
}
|
|
150
|
+
)
|
|
133
151
|
else:
|
|
134
152
|
if requirement.startswith("setup.py"):
|
|
135
153
|
raise ValueError(requirement)
|
|
136
154
|
requirement_strings.add(requirement)
|
|
155
|
+
configuration_file: str
|
|
156
|
+
kwargs: dict[str, tuple[str, ...]]
|
|
137
157
|
frozen_requirements: Iterable[str] = iter_distinct(
|
|
138
158
|
chain(
|
|
139
159
|
requirement_strings,
|
|
140
|
-
*
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
),
|
|
146
|
-
configuration_files,
|
|
160
|
+
*(
|
|
161
|
+
iter_configuration_file_requirement_strings(
|
|
162
|
+
configuration_file, **kwargs
|
|
163
|
+
)
|
|
164
|
+
for configuration_file, kwargs in configuration_files.items()
|
|
147
165
|
),
|
|
148
166
|
)
|
|
149
167
|
)
|
|
@@ -200,7 +218,7 @@ def _iter_frozen_requirements(
|
|
|
200
218
|
no_version: Iterable[str] = (),
|
|
201
219
|
depth: int | None = None,
|
|
202
220
|
) -> Iterable[str]:
|
|
203
|
-
def get_requirement_string(distribution_name: str) -> str:
|
|
221
|
+
def get_requirement_string(distribution_name: str) -> str | None:
|
|
204
222
|
def distribution_name_matches_pattern(pattern: str) -> bool:
|
|
205
223
|
return fnmatch(distribution_name, pattern)
|
|
206
224
|
|
|
@@ -212,9 +230,11 @@ def _iter_frozen_requirements(
|
|
|
212
230
|
try:
|
|
213
231
|
distribution = get_distribution(distribution_name)
|
|
214
232
|
except KeyError:
|
|
233
|
+
# If the distribution is not installed, skip it
|
|
234
|
+
return None
|
|
215
235
|
# If the distribution is missing, install it
|
|
216
|
-
install_requirement(distribution_name)
|
|
217
|
-
distribution = _get_distribution(distribution_name)
|
|
236
|
+
# install_requirement(distribution_name)
|
|
237
|
+
# distribution = _get_distribution(distribution_name)
|
|
218
238
|
return f"{distribution.metadata['Name']}=={distribution.version}"
|
|
219
239
|
|
|
220
240
|
def get_required_distribution_names_(
|
|
@@ -249,7 +269,7 @@ def _iter_frozen_requirements(
|
|
|
249
269
|
)
|
|
250
270
|
),
|
|
251
271
|
)
|
|
252
|
-
return map(get_requirement_string, requirements)
|
|
272
|
+
return filter(None, map(get_requirement_string, requirements))
|
|
253
273
|
|
|
254
274
|
|
|
255
275
|
def freeze(
|
dependence/update.py
CHANGED
|
@@ -133,10 +133,18 @@ def _get_updated_requirement_string(
|
|
|
133
133
|
return requirement_string
|
|
134
134
|
try:
|
|
135
135
|
distribution: Distribution = get_installed_distributions()[name]
|
|
136
|
+
if distribution.version is None:
|
|
137
|
+
return requirement_string
|
|
136
138
|
_update_requirement_specifiers(requirement, distribution.version)
|
|
137
139
|
except KeyError:
|
|
138
140
|
# If the requirement isn't installed, we can't update the version
|
|
139
141
|
pass
|
|
142
|
+
except TypeError as error:
|
|
143
|
+
message: str = (
|
|
144
|
+
f"Unable to determine installed version for {requirement_string}: "
|
|
145
|
+
f"{distribution!r}"
|
|
146
|
+
)
|
|
147
|
+
raise ValueError(message) from error
|
|
140
148
|
return str(requirement)
|
|
141
149
|
|
|
142
150
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
dependence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
dependence/__main__.py,sha256=zk67MINE1FpsBcXDDvRiHQwmO7_4iay_Rkq3JTPrha4,1802
|
|
3
|
+
dependence/_utilities.py,sha256=gAgQg0UAxMDfvyRIjR4GU7h5NDV1oTrnk6ECYwMYZIc,38242
|
|
4
|
+
dependence/freeze.py,sha256=dW3m2zEf2l61GWKdQTgrvj8FCDINU6GahmKr5ViIKX4,16226
|
|
5
|
+
dependence/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
dependence/update.py,sha256=043Hsj8bQJypJ_p_dxSl8HXBwlGoUK238OFYThTWVos,20856
|
|
7
|
+
dependence/upgrade.py,sha256=lNovLvKhxiczZAJj2_hHrbkDscNOTrx1xaOhmobVNSI,7747
|
|
8
|
+
dependence-1.1.3.dist-info/METADATA,sha256=lk7O3POAhVlMtcODTpZK2smN8oBhCFnJV0zwU8AhnDI,8364
|
|
9
|
+
dependence-1.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
+
dependence-1.1.3.dist-info/entry_points.txt,sha256=NStO_B0D81ObVYr9zDs6LCy0whm0a8KCiiFHMmTwOVE,56
|
|
11
|
+
dependence-1.1.3.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
dependence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
dependence/__main__.py,sha256=zk67MINE1FpsBcXDDvRiHQwmO7_4iay_Rkq3JTPrha4,1802
|
|
3
|
-
dependence/_utilities.py,sha256=CxIl7BkoTqMtrOsJzq544_RDa8-QtZufKj31PazIBFI,36790
|
|
4
|
-
dependence/freeze.py,sha256=Z7U6XvTCuyrCKX5951cx7nel4v_Mt39OFpWY_tq36IQ,15447
|
|
5
|
-
dependence/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
dependence/update.py,sha256=k6KtRbJORnbC7-bkDbVCDjsJkwVkGshQncLh1RjmolU,20554
|
|
7
|
-
dependence/upgrade.py,sha256=lNovLvKhxiczZAJj2_hHrbkDscNOTrx1xaOhmobVNSI,7747
|
|
8
|
-
dependence-1.1.1.dist-info/METADATA,sha256=rG_Wwm15ANEz7-dx9NCA0kxkoJReF5SL-0UjAwvNZB8,8364
|
|
9
|
-
dependence-1.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
-
dependence-1.1.1.dist-info/entry_points.txt,sha256=NStO_B0D81ObVYr9zDs6LCy0whm0a8KCiiFHMmTwOVE,56
|
|
11
|
-
dependence-1.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|