dependence 1.1.2__tar.gz → 1.1.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dependence
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: A dependency management tool for python projects
5
5
  Project-URL: Documentation, https://dependence.enorganic.org
6
6
  Project-URL: Repository, https://github.com/enorganic/dependence
@@ -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: _EditablePackageMetadata
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
- installed[normalize_name(distribution.metadata["Name"])] = distribution
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 _get_requirement_distribution(
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
- if not reinstall:
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 = _get_requirement_distribution(
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(
@@ -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(
@@ -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 = f"Unable to determine installed version for {requirement}"
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
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dependence"
7
- version = "1.1.2"
7
+ version = "1.1.3"
8
8
  description = "A dependency management tool for python projects"
9
9
  readme = "README.md"
10
10
  license = "MIT"
File without changes
File without changes