dependence 1.1.2__py3-none-any.whl → 1.2.0__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 +143 -61
- dependence/freeze.py +9 -7
- dependence/update.py +6 -1
- {dependence-1.1.2.dist-info → dependence-1.2.0.dist-info}/METADATA +1 -1
- dependence-1.2.0.dist-info/RECORD +11 -0
- dependence-1.1.2.dist-info/RECORD +0 -11
- {dependence-1.1.2.dist-info → dependence-1.2.0.dist-info}/WHEEL +0 -0
- {dependence-1.1.2.dist-info → dependence-1.2.0.dist-info}/entry_points.txt +0 -0
dependence/_utilities.py
CHANGED
|
@@ -4,6 +4,7 @@ import functools
|
|
|
4
4
|
import json
|
|
5
5
|
import os
|
|
6
6
|
import re
|
|
7
|
+
import shutil
|
|
7
8
|
import sys
|
|
8
9
|
from collections import deque
|
|
9
10
|
from collections.abc import Container, Hashable, Iterable, MutableSet
|
|
@@ -95,6 +96,44 @@ def _undefined() -> Undefined:
|
|
|
95
96
|
return UNDEFINED
|
|
96
97
|
|
|
97
98
|
|
|
99
|
+
cache: Any
|
|
100
|
+
try:
|
|
101
|
+
from functools import cache # type: ignore
|
|
102
|
+
except ImportError:
|
|
103
|
+
from functools import lru_cache
|
|
104
|
+
|
|
105
|
+
cache = lru_cache(maxsize=None)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def as_tuple(
|
|
109
|
+
user_function: Callable[..., Iterable[Any]],
|
|
110
|
+
) -> Callable[..., tuple[Any, ...]]:
|
|
111
|
+
"""
|
|
112
|
+
This is a decorator which will return an iterable as a tuple.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def wrapper(*args: Any, **kwargs: Any) -> tuple[Any, ...]:
|
|
116
|
+
return tuple(user_function(*args, **kwargs) or ())
|
|
117
|
+
|
|
118
|
+
return functools.update_wrapper(wrapper, user_function)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def as_cached_tuple(
|
|
122
|
+
maxsize: int | None = None, *, typed: bool = False
|
|
123
|
+
) -> Callable[[Callable[..., Iterable[Any]]], Callable[..., tuple[Any, ...]]]:
|
|
124
|
+
"""
|
|
125
|
+
This is a decorator which will return an iterable as a tuple,
|
|
126
|
+
and cache that tuple.
|
|
127
|
+
|
|
128
|
+
Parameters:
|
|
129
|
+
|
|
130
|
+
- maxsize (int|None) = None: The maximum number of items to cache.
|
|
131
|
+
- typed (bool) = False: For class methods, should the cache be distinct for
|
|
132
|
+
sub-classes?
|
|
133
|
+
"""
|
|
134
|
+
return functools.lru_cache(maxsize=maxsize, typed=typed)(as_tuple)
|
|
135
|
+
|
|
136
|
+
|
|
98
137
|
def iter_distinct(items: Iterable[Hashable]) -> Iterable:
|
|
99
138
|
"""
|
|
100
139
|
Yield distinct elements, preserving order
|
|
@@ -418,47 +457,75 @@ def iter_configuration_files(path: str | Path) -> Iterable[Path | str]:
|
|
|
418
457
|
yield path
|
|
419
458
|
|
|
420
459
|
|
|
421
|
-
|
|
460
|
+
def _iter_editable_project_locations() -> Iterable[tuple[str, str]]:
|
|
461
|
+
metadata: PackageMetadata
|
|
462
|
+
for name, metadata in map_pip_list().items():
|
|
463
|
+
editable_project_location: str | None = metadata.get(
|
|
464
|
+
"editable_project_location"
|
|
465
|
+
)
|
|
466
|
+
if editable_project_location:
|
|
467
|
+
yield (
|
|
468
|
+
name,
|
|
469
|
+
editable_project_location,
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
@functools.lru_cache
|
|
474
|
+
def map_editable_project_locations() -> dict[str, str]:
|
|
475
|
+
"""
|
|
476
|
+
Get a mapping of (normalized) editable distribution names to their
|
|
477
|
+
locations.
|
|
478
|
+
"""
|
|
479
|
+
return dict(_iter_editable_project_locations())
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
class PackageMetadata(TypedDict, total=False):
|
|
422
483
|
name: str
|
|
423
484
|
version: str
|
|
424
485
|
editable_project_location: str
|
|
425
486
|
|
|
426
487
|
|
|
427
|
-
def
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
)
|
|
488
|
+
def _iter_pip_list() -> Iterable[tuple[str, PackageMetadata]]:
|
|
489
|
+
uv: str | None = shutil.which("uv")
|
|
490
|
+
command: tuple[str, ...]
|
|
491
|
+
if uv:
|
|
492
|
+
command = (
|
|
493
|
+
uv,
|
|
494
|
+
"pip",
|
|
495
|
+
"list",
|
|
496
|
+
"--python",
|
|
497
|
+
sys.executable,
|
|
498
|
+
"--format=json",
|
|
439
499
|
)
|
|
440
|
-
|
|
500
|
+
else:
|
|
501
|
+
# If `uv` is not available, use `pip`
|
|
502
|
+
command = (
|
|
503
|
+
sys.executable,
|
|
504
|
+
"-m",
|
|
505
|
+
"pip",
|
|
506
|
+
"list",
|
|
507
|
+
"--format=json",
|
|
508
|
+
)
|
|
509
|
+
metadata: PackageMetadata
|
|
510
|
+
for metadata in json.loads(check_output(command)):
|
|
441
511
|
yield (
|
|
442
512
|
normalize_name(metadata["name"]),
|
|
443
|
-
metadata
|
|
513
|
+
metadata,
|
|
444
514
|
)
|
|
445
515
|
|
|
446
516
|
|
|
447
|
-
@
|
|
448
|
-
def
|
|
449
|
-
|
|
450
|
-
Get a mapping of (normalized) editable distribution names to their
|
|
451
|
-
locations.
|
|
452
|
-
"""
|
|
453
|
-
return dict(_iter_editable_distribution_locations())
|
|
517
|
+
@cache
|
|
518
|
+
def map_pip_list() -> dict[str, PackageMetadata]:
|
|
519
|
+
return dict(_iter_pip_list())
|
|
454
520
|
|
|
455
521
|
|
|
456
522
|
def cache_clear() -> None:
|
|
457
523
|
"""
|
|
458
524
|
Clear distribution metadata caches
|
|
459
525
|
"""
|
|
526
|
+
map_pip_list.cache_clear()
|
|
460
527
|
get_installed_distributions.cache_clear()
|
|
461
|
-
|
|
528
|
+
map_editable_project_locations.cache_clear()
|
|
462
529
|
is_editable.cache_clear()
|
|
463
530
|
is_installed.cache_clear()
|
|
464
531
|
get_requirement_string_distribution_name.cache_clear()
|
|
@@ -470,7 +537,7 @@ def refresh_editable_distributions() -> None:
|
|
|
470
537
|
"""
|
|
471
538
|
name: str
|
|
472
539
|
location: str
|
|
473
|
-
for name, location in
|
|
540
|
+
for name, location in map_editable_project_locations().items():
|
|
474
541
|
_install_requirement_string(location, name=name, editable=True)
|
|
475
542
|
|
|
476
543
|
|
|
@@ -482,7 +549,13 @@ def get_installed_distributions() -> dict[str, Distribution]:
|
|
|
482
549
|
refresh_editable_distributions()
|
|
483
550
|
installed: dict[str, Distribution] = {}
|
|
484
551
|
for distribution in _get_distributions():
|
|
485
|
-
|
|
552
|
+
name: str = distribution.metadata["Name"]
|
|
553
|
+
if distribution.version is None:
|
|
554
|
+
# If no version can be found, use pip to find the version
|
|
555
|
+
distribution.metadata["Version"] = (
|
|
556
|
+
map_pip_list().get(name, {}).get("version")
|
|
557
|
+
)
|
|
558
|
+
installed[normalize_name(name)] = distribution
|
|
486
559
|
return installed
|
|
487
560
|
|
|
488
561
|
|
|
@@ -751,7 +824,7 @@ def is_editable(name: str) -> bool:
|
|
|
751
824
|
"""
|
|
752
825
|
Return `True` if the indicated distribution is an editable installation.
|
|
753
826
|
"""
|
|
754
|
-
return bool(normalize_name(name) in
|
|
827
|
+
return bool(normalize_name(name) in map_editable_project_locations())
|
|
755
828
|
|
|
756
829
|
|
|
757
830
|
def _get_setup_cfg_metadata(path: str, key: str) -> str:
|
|
@@ -880,7 +953,7 @@ def _setup_location(
|
|
|
880
953
|
|
|
881
954
|
|
|
882
955
|
def get_editable_distribution_location(name: str) -> str:
|
|
883
|
-
return
|
|
956
|
+
return map_editable_project_locations().get(normalize_name(name), "")
|
|
884
957
|
|
|
885
958
|
|
|
886
959
|
def setup_egg_info(directory: str | Path, egg_base: str = "") -> None:
|
|
@@ -975,6 +1048,10 @@ def _get_requirement_name(requirement: Requirement) -> str:
|
|
|
975
1048
|
return normalize_name(requirement.name)
|
|
976
1049
|
|
|
977
1050
|
|
|
1051
|
+
@deprecated(
|
|
1052
|
+
"dependence._utilities.install_requirement is deprecated and will be "
|
|
1053
|
+
"removed in a future release."
|
|
1054
|
+
)
|
|
978
1055
|
def install_requirement(requirement: str | Requirement) -> None:
|
|
979
1056
|
"""
|
|
980
1057
|
Install a requirement
|
|
@@ -1000,21 +1077,44 @@ def _install_requirement_string(
|
|
|
1000
1077
|
Install a requirement string with no dependencies, compilation, build
|
|
1001
1078
|
isolation, etc.
|
|
1002
1079
|
"""
|
|
1003
|
-
command: tuple[str, ...]
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
"-
|
|
1014
|
-
|
|
1080
|
+
command: tuple[str, ...]
|
|
1081
|
+
uv: str | None = shutil.which("uv")
|
|
1082
|
+
if uv:
|
|
1083
|
+
command = (
|
|
1084
|
+
uv,
|
|
1085
|
+
"pip",
|
|
1086
|
+
"install",
|
|
1087
|
+
"--python",
|
|
1088
|
+
sys.executable,
|
|
1089
|
+
"--no-deps",
|
|
1090
|
+
"--no-compile",
|
|
1091
|
+
*(
|
|
1092
|
+
(
|
|
1093
|
+
"-e",
|
|
1094
|
+
requirement_string,
|
|
1095
|
+
)
|
|
1096
|
+
if editable
|
|
1097
|
+
else (requirement_string,)
|
|
1098
|
+
),
|
|
1015
1099
|
)
|
|
1016
1100
|
else:
|
|
1017
|
-
|
|
1101
|
+
# If `uv` is not available, use `pip`
|
|
1102
|
+
command = (
|
|
1103
|
+
sys.executable,
|
|
1104
|
+
"-m",
|
|
1105
|
+
"pip",
|
|
1106
|
+
"install",
|
|
1107
|
+
"--no-deps",
|
|
1108
|
+
"--no-compile",
|
|
1109
|
+
*(
|
|
1110
|
+
(
|
|
1111
|
+
"-e",
|
|
1112
|
+
requirement_string,
|
|
1113
|
+
)
|
|
1114
|
+
if editable
|
|
1115
|
+
else (requirement_string,)
|
|
1116
|
+
),
|
|
1117
|
+
)
|
|
1018
1118
|
try:
|
|
1019
1119
|
check_output(command)
|
|
1020
1120
|
except CalledProcessError as error:
|
|
@@ -1079,31 +1179,15 @@ def _install_requirement(
|
|
|
1079
1179
|
cache_clear()
|
|
1080
1180
|
|
|
1081
1181
|
|
|
1082
|
-
def
|
|
1083
|
-
requirement: Requirement,
|
|
1182
|
+
def _get_installed_distribution(
|
|
1084
1183
|
name: str,
|
|
1085
|
-
*,
|
|
1086
|
-
reinstall: bool = True,
|
|
1087
|
-
echo: bool = False,
|
|
1088
1184
|
) -> Distribution | None:
|
|
1089
1185
|
if name in _BUILTIN_DISTRIBUTION_NAMES:
|
|
1090
1186
|
return None
|
|
1091
1187
|
try:
|
|
1092
1188
|
return get_installed_distributions()[name]
|
|
1093
1189
|
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
|
-
)
|
|
1190
|
+
return None
|
|
1107
1191
|
|
|
1108
1192
|
|
|
1109
1193
|
def _iter_distribution_requirements(
|
|
@@ -1140,9 +1224,7 @@ def _iter_requirement_names(
|
|
|
1140
1224
|
# Ensure we don't follow the same requirement again, causing cyclic
|
|
1141
1225
|
# recursion
|
|
1142
1226
|
exclude.add(name)
|
|
1143
|
-
distribution: Distribution | None =
|
|
1144
|
-
requirement, name, echo=echo
|
|
1145
|
-
)
|
|
1227
|
+
distribution: Distribution | None = _get_installed_distribution(name)
|
|
1146
1228
|
if distribution is None:
|
|
1147
1229
|
return ()
|
|
1148
1230
|
requirements: tuple[Requirement, ...] = tuple(
|
dependence/freeze.py
CHANGED
|
@@ -5,8 +5,6 @@ import os
|
|
|
5
5
|
from collections.abc import Iterable, MutableSet
|
|
6
6
|
from fnmatch import fnmatch
|
|
7
7
|
from functools import partial
|
|
8
|
-
from importlib.metadata import Distribution
|
|
9
|
-
from importlib.metadata import distribution as _get_distribution
|
|
10
8
|
from itertools import chain
|
|
11
9
|
from pathlib import Path
|
|
12
10
|
from typing import TYPE_CHECKING, cast
|
|
@@ -15,7 +13,6 @@ from dependence._utilities import (
|
|
|
15
13
|
get_distribution,
|
|
16
14
|
get_required_distribution_names,
|
|
17
15
|
get_requirement_string_distribution_name,
|
|
18
|
-
install_requirement,
|
|
19
16
|
iter_configuration_file_requirement_strings,
|
|
20
17
|
iter_configuration_files,
|
|
21
18
|
iter_distinct,
|
|
@@ -23,6 +20,9 @@ from dependence._utilities import (
|
|
|
23
20
|
normalize_name,
|
|
24
21
|
)
|
|
25
22
|
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from importlib.metadata import Distribution
|
|
25
|
+
|
|
26
26
|
_DO_NOT_PIN_DISTRIBUTION_NAMES: MutableSet[str] = {
|
|
27
27
|
"importlib-metadata",
|
|
28
28
|
"importlib-resources",
|
|
@@ -218,7 +218,7 @@ def _iter_frozen_requirements(
|
|
|
218
218
|
no_version: Iterable[str] = (),
|
|
219
219
|
depth: int | None = None,
|
|
220
220
|
) -> Iterable[str]:
|
|
221
|
-
def get_requirement_string(distribution_name: str) -> str:
|
|
221
|
+
def get_requirement_string(distribution_name: str) -> str | None:
|
|
222
222
|
def distribution_name_matches_pattern(pattern: str) -> bool:
|
|
223
223
|
return fnmatch(distribution_name, pattern)
|
|
224
224
|
|
|
@@ -230,9 +230,11 @@ def _iter_frozen_requirements(
|
|
|
230
230
|
try:
|
|
231
231
|
distribution = get_distribution(distribution_name)
|
|
232
232
|
except KeyError:
|
|
233
|
+
# If the distribution is not installed, skip it
|
|
234
|
+
return None
|
|
233
235
|
# If the distribution is missing, install it
|
|
234
|
-
install_requirement(distribution_name)
|
|
235
|
-
distribution = _get_distribution(distribution_name)
|
|
236
|
+
# install_requirement(distribution_name)
|
|
237
|
+
# distribution = _get_distribution(distribution_name)
|
|
236
238
|
return f"{distribution.metadata['Name']}=={distribution.version}"
|
|
237
239
|
|
|
238
240
|
def get_required_distribution_names_(
|
|
@@ -267,7 +269,7 @@ def _iter_frozen_requirements(
|
|
|
267
269
|
)
|
|
268
270
|
),
|
|
269
271
|
)
|
|
270
|
-
return map(get_requirement_string, requirements)
|
|
272
|
+
return filter(None, map(get_requirement_string, requirements))
|
|
271
273
|
|
|
272
274
|
|
|
273
275
|
def freeze(
|
dependence/update.py
CHANGED
|
@@ -133,12 +133,17 @@ 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
|
|
140
142
|
except TypeError as error:
|
|
141
|
-
message =
|
|
143
|
+
message: str = (
|
|
144
|
+
f"Unable to determine installed version for {requirement_string}: "
|
|
145
|
+
f"{distribution!r}"
|
|
146
|
+
)
|
|
142
147
|
raise ValueError(message) from error
|
|
143
148
|
return str(requirement)
|
|
144
149
|
|
|
@@ -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=-9RGMsQKzaA-fEDswdXSx1LAVKdasWuKQGl7jgTeZXs,38960
|
|
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.2.0.dist-info/METADATA,sha256=gdt6DNV_0GX-ZSZppXZKePSORAiweGYy2CYJQfIifA0,8364
|
|
9
|
+
dependence-1.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
+
dependence-1.2.0.dist-info/entry_points.txt,sha256=NStO_B0D81ObVYr9zDs6LCy0whm0a8KCiiFHMmTwOVE,56
|
|
11
|
+
dependence-1.2.0.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=MMv7_feEXfRo8cxyrgK0su17k1k8uLXWwpRCvrj-vz8,16184
|
|
5
|
-
dependence/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
dependence/update.py,sha256=QLe6sx39PKM3x6TxMzQxTUPDSKn8d7UizIVpbqMZuJI,20707
|
|
7
|
-
dependence/upgrade.py,sha256=lNovLvKhxiczZAJj2_hHrbkDscNOTrx1xaOhmobVNSI,7747
|
|
8
|
-
dependence-1.1.2.dist-info/METADATA,sha256=XhMrXo14In72SHqOStXK0bn8NVEm4XqWkbGBWOyUCUo,8364
|
|
9
|
-
dependence-1.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
-
dependence-1.1.2.dist-info/entry_points.txt,sha256=NStO_B0D81ObVYr9zDs6LCy0whm0a8KCiiFHMmTwOVE,56
|
|
11
|
-
dependence-1.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|