dependence 0.3.1__tar.gz → 0.3.5__tar.gz
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-0.3.1 → dependence-0.3.5}/PKG-INFO +1 -1
- {dependence-0.3.1 → dependence-0.3.5}/dependence/_utilities.py +93 -22
- {dependence-0.3.1 → dependence-0.3.5}/dependence/utilities.py +68 -129
- {dependence-0.3.1 → dependence-0.3.5}/dependence.egg-info/PKG-INFO +1 -1
- {dependence-0.3.1 → dependence-0.3.5}/setup.cfg +1 -1
- {dependence-0.3.1 → dependence-0.3.5}/README.md +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence/__init__.py +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence/__main__.py +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence/freeze.py +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence/py.typed +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence/update.py +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence.egg-info/SOURCES.txt +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence.egg-info/dependency_links.txt +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence.egg-info/entry_points.txt +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence.egg-info/requires.txt +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/dependence.egg-info/top_level.txt +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/pyproject.toml +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/setup.py +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/tests/test_freeze.py +0 -0
- {dependence-0.3.1 → dependence-0.3.5}/tests/test_update.py +0 -0
|
@@ -1,32 +1,25 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import sys
|
|
3
|
-
from functools import lru_cache
|
|
2
|
+
from functools import lru_cache, wraps
|
|
4
3
|
from itertools import chain
|
|
5
|
-
from
|
|
6
|
-
from
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from subprocess import DEVNULL, PIPE, list2cmdline, run
|
|
7
6
|
from traceback import format_exception
|
|
8
|
-
from typing import
|
|
7
|
+
from typing import (
|
|
8
|
+
Any,
|
|
9
|
+
Callable,
|
|
10
|
+
Dict,
|
|
11
|
+
Hashable,
|
|
12
|
+
Iterable,
|
|
13
|
+
List,
|
|
14
|
+
Set,
|
|
15
|
+
Tuple,
|
|
16
|
+
Union,
|
|
17
|
+
)
|
|
18
|
+
from warnings import warn
|
|
9
19
|
|
|
10
20
|
import tomli
|
|
11
21
|
|
|
12
22
|
|
|
13
|
-
def check_output(command: Tuple[str, ...]) -> str:
|
|
14
|
-
"""
|
|
15
|
-
This function wraps `subprocess.check_output`, but redirects stderr
|
|
16
|
-
to a temporary file, then deletes that file (a platform-independent
|
|
17
|
-
means of redirecting output to DEVNULL).
|
|
18
|
-
|
|
19
|
-
Parameters:
|
|
20
|
-
|
|
21
|
-
- command (Tuple[str, ...]): The command to run
|
|
22
|
-
"""
|
|
23
|
-
stderr_path: str = mktemp()
|
|
24
|
-
with open(stderr_path, "w") as stderr:
|
|
25
|
-
output = _check_output(command, stderr=stderr, text=True)
|
|
26
|
-
os.remove(stderr_path)
|
|
27
|
-
return output
|
|
28
|
-
|
|
29
|
-
|
|
30
23
|
def iter_distinct(items: Iterable[Hashable]) -> Iterable:
|
|
31
24
|
"""
|
|
32
25
|
Yield distinct elements, preserving order
|
|
@@ -102,3 +95,81 @@ def iter_parse_delimited_values(
|
|
|
102
95
|
return _iter_parse_delimited_value(value, delimiter=delimiter)
|
|
103
96
|
|
|
104
97
|
return chain(*map(iter_parse_delimited_value_, values))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def check_output(
|
|
101
|
+
args: Tuple[str, ...],
|
|
102
|
+
cwd: Union[str, Path] = "",
|
|
103
|
+
echo: bool = False,
|
|
104
|
+
) -> str:
|
|
105
|
+
"""
|
|
106
|
+
This function mimics `subprocess.check_output`, but redirects stderr
|
|
107
|
+
to DEVNULL, and ignores unicode decoding errors.
|
|
108
|
+
|
|
109
|
+
Parameters:
|
|
110
|
+
|
|
111
|
+
- command (Tuple[str, ...]): The command to run
|
|
112
|
+
"""
|
|
113
|
+
if echo:
|
|
114
|
+
if cwd:
|
|
115
|
+
print("$", "cd", cwd, "&&", list2cmdline(args))
|
|
116
|
+
else:
|
|
117
|
+
print("$", list2cmdline(args))
|
|
118
|
+
output: str = run(
|
|
119
|
+
args,
|
|
120
|
+
stdout=PIPE,
|
|
121
|
+
stderr=DEVNULL,
|
|
122
|
+
check=True,
|
|
123
|
+
cwd=cwd or None,
|
|
124
|
+
).stdout.decode("utf-8", errors="ignore")
|
|
125
|
+
if echo:
|
|
126
|
+
print(output)
|
|
127
|
+
return output
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_qualified_name(function: Callable[..., Any]) -> str:
|
|
131
|
+
name: str = getattr(function, "__name__", "")
|
|
132
|
+
if name:
|
|
133
|
+
module: str = getattr(function, "__module__", "")
|
|
134
|
+
if module not in (
|
|
135
|
+
"builtins",
|
|
136
|
+
"__builtin__",
|
|
137
|
+
"__main__",
|
|
138
|
+
"__init__",
|
|
139
|
+
"",
|
|
140
|
+
):
|
|
141
|
+
name = f"{module}.{name}"
|
|
142
|
+
return name
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def deprecated(message: str = "") -> Callable[..., Callable[..., Any]]:
|
|
146
|
+
"""
|
|
147
|
+
This decorator marks a function as deprecated, and issues a
|
|
148
|
+
deprecation warning when the function is called.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
def decorating_function(
|
|
152
|
+
function: Callable[..., Any]
|
|
153
|
+
) -> Callable[..., Any]:
|
|
154
|
+
|
|
155
|
+
@wraps(function)
|
|
156
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
157
|
+
name: str = get_qualified_name(function)
|
|
158
|
+
warn(
|
|
159
|
+
(
|
|
160
|
+
(
|
|
161
|
+
f"{name} is deprecated: {message}"
|
|
162
|
+
if message
|
|
163
|
+
else f"{name} is deprecated"
|
|
164
|
+
)
|
|
165
|
+
if name
|
|
166
|
+
else message
|
|
167
|
+
),
|
|
168
|
+
DeprecationWarning,
|
|
169
|
+
stacklevel=2,
|
|
170
|
+
)
|
|
171
|
+
return function(*args, **kwargs)
|
|
172
|
+
|
|
173
|
+
return wrapper
|
|
174
|
+
|
|
175
|
+
return decorating_function
|
|
@@ -6,15 +6,14 @@ from collections import deque
|
|
|
6
6
|
from configparser import ConfigParser, SectionProxy
|
|
7
7
|
from enum import Enum, auto
|
|
8
8
|
from glob import iglob
|
|
9
|
-
from importlib.metadata import Distribution, PackageNotFoundError
|
|
9
|
+
from importlib.metadata import Distribution, PackageNotFoundError
|
|
10
10
|
from importlib.metadata import distribution as _get_distribution
|
|
11
11
|
from importlib.metadata import distributions as _get_distributions
|
|
12
12
|
from itertools import chain
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from runpy import run_path
|
|
15
|
-
from shutil import
|
|
16
|
-
from subprocess import CalledProcessError
|
|
17
|
-
from tempfile import mkdtemp
|
|
15
|
+
from shutil import rmtree
|
|
16
|
+
from subprocess import CalledProcessError, list2cmdline
|
|
18
17
|
from types import ModuleType
|
|
19
18
|
from typing import (
|
|
20
19
|
IO,
|
|
@@ -39,6 +38,7 @@ from packaging.utils import canonicalize_name
|
|
|
39
38
|
from ._utilities import (
|
|
40
39
|
append_exception_text,
|
|
41
40
|
check_output,
|
|
41
|
+
deprecated,
|
|
42
42
|
get_exception_text,
|
|
43
43
|
iter_distinct,
|
|
44
44
|
)
|
|
@@ -172,63 +172,6 @@ def cache_clear() -> None:
|
|
|
172
172
|
get_requirement_string_distribution_name.cache_clear()
|
|
173
173
|
|
|
174
174
|
|
|
175
|
-
def _iter_find_dist_info(directory: Path, name: str) -> Iterable[Path]:
|
|
176
|
-
"""
|
|
177
|
-
Find all *.dist-info directories for a project in the specified directory
|
|
178
|
-
(there shouldn't be more than one, but pip issues can cause there to
|
|
179
|
-
be on occasions).
|
|
180
|
-
"""
|
|
181
|
-
yield from filter(
|
|
182
|
-
Path.is_dir,
|
|
183
|
-
directory.glob(f"{name.replace('-', '_')}" "-*.dist-info"),
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def _move_dist_info_to_temp_directory(dist_info_directory: Path) -> Path:
|
|
188
|
-
"""
|
|
189
|
-
Move the contents of *.dist-info directories for a project into a temporary
|
|
190
|
-
directory, and return the path to that temp directory.
|
|
191
|
-
"""
|
|
192
|
-
temp_directory: Path = Path(mkdtemp())
|
|
193
|
-
file_path: Path
|
|
194
|
-
for file_path in dist_info_directory.iterdir():
|
|
195
|
-
move(str(file_path), temp_directory.joinpath(file_path.name))
|
|
196
|
-
rmtree(dist_info_directory)
|
|
197
|
-
return temp_directory
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def _merge_directories(
|
|
201
|
-
source_directory: Path, target_directory: Path, overwrite: bool = False
|
|
202
|
-
) -> None:
|
|
203
|
-
source_file_path: Path
|
|
204
|
-
target_file_path: Path
|
|
205
|
-
if not target_directory.exists():
|
|
206
|
-
target_directory.mkdir()
|
|
207
|
-
for source_file_path in source_directory.iterdir():
|
|
208
|
-
target_file_path = target_directory.joinpath(source_file_path.name)
|
|
209
|
-
if overwrite or (not target_file_path.exists()):
|
|
210
|
-
move(str(source_file_path), target_file_path)
|
|
211
|
-
rmtree(source_directory)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def _get_distribution_dist_info_path(
|
|
215
|
-
distribution: Distribution,
|
|
216
|
-
) -> Optional[Path]:
|
|
217
|
-
"""
|
|
218
|
-
Get the dist-info directory for a distribution
|
|
219
|
-
(a safer method for accessing the equivalent of `distribution._path`)
|
|
220
|
-
"""
|
|
221
|
-
return distribution._path # type: ignore
|
|
222
|
-
if distribution.files is None:
|
|
223
|
-
return None
|
|
224
|
-
package_path: PackagePath
|
|
225
|
-
for package_path in distribution.files:
|
|
226
|
-
directory = Path(package_path.locate()).parent
|
|
227
|
-
if directory.name.endswith(".dist-info"):
|
|
228
|
-
return directory
|
|
229
|
-
return None
|
|
230
|
-
|
|
231
|
-
|
|
232
175
|
def refresh_editable_distributions() -> None:
|
|
233
176
|
"""
|
|
234
177
|
Update distribution information for editable installs
|
|
@@ -236,31 +179,7 @@ def refresh_editable_distributions() -> None:
|
|
|
236
179
|
name: str
|
|
237
180
|
location: str
|
|
238
181
|
for name, location in get_editable_distributions_locations().items():
|
|
239
|
-
|
|
240
|
-
dist_info_path: Optional[Path] = _get_distribution_dist_info_path(
|
|
241
|
-
distribution
|
|
242
|
-
)
|
|
243
|
-
if dist_info_path is None:
|
|
244
|
-
continue
|
|
245
|
-
dist_info_directory: Path = dist_info_path.parent
|
|
246
|
-
location_path: Path = Path(location)
|
|
247
|
-
# Find pre-existing dist-info directories, and rename them so that
|
|
248
|
-
# the new dist-info directory doesn't overwrite the old one, then
|
|
249
|
-
# merge the two directories, replacing old files with new files
|
|
250
|
-
# when they exist in both
|
|
251
|
-
temp_directory: Path = _move_dist_info_to_temp_directory(
|
|
252
|
-
dist_info_path
|
|
253
|
-
)
|
|
254
|
-
try:
|
|
255
|
-
setup_egg_info(location_path)
|
|
256
|
-
if dist_info_directory != location_path:
|
|
257
|
-
setup_dist_info(location_path, dist_info_directory)
|
|
258
|
-
finally:
|
|
259
|
-
_merge_directories(
|
|
260
|
-
temp_directory,
|
|
261
|
-
dist_info_path,
|
|
262
|
-
overwrite=False,
|
|
263
|
-
)
|
|
182
|
+
_install_requirement_string(location, name=name, editable=True)
|
|
264
183
|
|
|
265
184
|
|
|
266
185
|
@functools.lru_cache()
|
|
@@ -652,6 +571,7 @@ def _setup_location(
|
|
|
652
571
|
os.chdir(current_directory)
|
|
653
572
|
|
|
654
573
|
|
|
574
|
+
@deprecated()
|
|
655
575
|
def setup_dist_egg_info(directory: str) -> None:
|
|
656
576
|
"""
|
|
657
577
|
Refresh dist-info and egg-info for the editable package installed in
|
|
@@ -673,6 +593,7 @@ def get_editable_distribution_location(name: str) -> str:
|
|
|
673
593
|
return get_editable_distributions_locations().get(normalize_name(name), "")
|
|
674
594
|
|
|
675
595
|
|
|
596
|
+
@deprecated()
|
|
676
597
|
def setup_dist_info(
|
|
677
598
|
directory: Union[str, Path], output_dir: Union[str, Path] = ""
|
|
678
599
|
) -> None:
|
|
@@ -685,13 +606,13 @@ def setup_dist_info(
|
|
|
685
606
|
directory = directory.absolute()
|
|
686
607
|
if not directory.is_dir():
|
|
687
608
|
directory = directory.parent
|
|
688
|
-
if isinstance(output_dir,
|
|
689
|
-
output_dir =
|
|
690
|
-
|
|
609
|
+
if isinstance(output_dir, str) and output_dir:
|
|
610
|
+
output_dir = Path(output_dir)
|
|
611
|
+
_setup_location(
|
|
691
612
|
directory,
|
|
692
613
|
(
|
|
693
614
|
("-q", "dist_info")
|
|
694
|
-
+ (("--output-dir", output_dir) if output_dir else ()),
|
|
615
|
+
+ (("--output-dir", str(output_dir)) if output_dir else ()),
|
|
695
616
|
),
|
|
696
617
|
)
|
|
697
618
|
|
|
@@ -699,7 +620,7 @@ def setup_dist_info(
|
|
|
699
620
|
def setup_egg_info(directory: Union[str, Path], egg_base: str = "") -> None:
|
|
700
621
|
"""
|
|
701
622
|
Refresh egg-info for the editable package installed in
|
|
702
|
-
`directory`
|
|
623
|
+
`directory` (only applicable for packages using a `setup.py` script)
|
|
703
624
|
"""
|
|
704
625
|
if isinstance(directory, str):
|
|
705
626
|
directory = Path(directory)
|
|
@@ -715,7 +636,7 @@ def setup_egg_info(directory: Union[str, Path], egg_base: str = "") -> None:
|
|
|
715
636
|
dist_info_path: Path = Path(dist_info)
|
|
716
637
|
if not dist_info_path.joinpath("RECORD").is_file():
|
|
717
638
|
rmtree(dist_info_path)
|
|
718
|
-
|
|
639
|
+
_setup_location(
|
|
719
640
|
directory,
|
|
720
641
|
(("-q", "egg_info") + (("--egg-base", egg_base) if egg_base else ()),),
|
|
721
642
|
)
|
|
@@ -808,46 +729,61 @@ def _install_requirement_string(
|
|
|
808
729
|
name: str = "",
|
|
809
730
|
editable: bool = False,
|
|
810
731
|
) -> None:
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
uncaught_error,
|
|
732
|
+
"""
|
|
733
|
+
Install a requirement string with no dependencies, compilation, build
|
|
734
|
+
isolation, etc.
|
|
735
|
+
"""
|
|
736
|
+
command: Tuple[str, ...] = (
|
|
737
|
+
sys.executable,
|
|
738
|
+
"-m",
|
|
739
|
+
"pip",
|
|
740
|
+
"install",
|
|
741
|
+
"--no-deps",
|
|
742
|
+
"--no-compile",
|
|
743
|
+
"--no-build-isolation",
|
|
744
|
+
)
|
|
745
|
+
if editable:
|
|
746
|
+
command += (
|
|
747
|
+
"-e",
|
|
748
|
+
requirement_string,
|
|
749
|
+
"--config-settings",
|
|
750
|
+
"editable_mode=compat",
|
|
751
|
+
)
|
|
752
|
+
else:
|
|
753
|
+
command += (requirement_string,)
|
|
754
|
+
try:
|
|
755
|
+
check_output(command)
|
|
756
|
+
except CalledProcessError as error:
|
|
757
|
+
message: str = (
|
|
838
758
|
(
|
|
839
|
-
(
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
759
|
+
f"\n{list2cmdline(command)}" f"\nCould not install {name}"
|
|
760
|
+
if name == requirement_string
|
|
761
|
+
else (
|
|
762
|
+
f"\n{list2cmdline(command)}"
|
|
763
|
+
f"\nCould not install {name} from "
|
|
764
|
+
f"{requirement_string}"
|
|
845
765
|
)
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
766
|
+
)
|
|
767
|
+
if name
|
|
768
|
+
else (
|
|
769
|
+
f"\n{list2cmdline(command)}"
|
|
770
|
+
f"\nCould not install {requirement_string}"
|
|
771
|
+
)
|
|
849
772
|
)
|
|
850
|
-
|
|
773
|
+
if not editable:
|
|
774
|
+
append_exception_text(
|
|
775
|
+
error,
|
|
776
|
+
message,
|
|
777
|
+
)
|
|
778
|
+
raise error
|
|
779
|
+
try:
|
|
780
|
+
check_output(command + ("--force-reinstall",))
|
|
781
|
+
except CalledProcessError as retry_error:
|
|
782
|
+
append_exception_text(
|
|
783
|
+
retry_error,
|
|
784
|
+
message,
|
|
785
|
+
)
|
|
786
|
+
raise retry_error
|
|
851
787
|
|
|
852
788
|
|
|
853
789
|
def _install_requirement(
|
|
@@ -1000,6 +936,7 @@ def _iter_requirement_names(
|
|
|
1000
936
|
return requirement_names
|
|
1001
937
|
|
|
1002
938
|
|
|
939
|
+
@deprecated()
|
|
1003
940
|
def _iter_requirement_strings_required_distribution_names(
|
|
1004
941
|
requirement_strings: Iterable[str],
|
|
1005
942
|
echo: bool = False,
|
|
@@ -1033,6 +970,7 @@ def _iter_requirement_strings_required_distribution_names(
|
|
|
1033
970
|
)
|
|
1034
971
|
|
|
1035
972
|
|
|
973
|
+
@deprecated()
|
|
1036
974
|
def get_requirements_required_distribution_names(
|
|
1037
975
|
requirements: Iterable[str] = (),
|
|
1038
976
|
echo: bool = False,
|
|
@@ -1075,6 +1013,7 @@ def get_requirements_required_distribution_names(
|
|
|
1075
1013
|
)
|
|
1076
1014
|
|
|
1077
1015
|
|
|
1016
|
+
@deprecated()
|
|
1078
1017
|
def iter_distribution_location_file_paths(location: str) -> Iterable[str]:
|
|
1079
1018
|
location = os.path.abspath(location)
|
|
1080
1019
|
name: str = get_setup_distribution_name(location)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|