Skip to content

Commit 42f722f

Browse files
committed
Improve implementation of the function; add docstrings
1 parent 239de05 commit 42f722f

File tree

1 file changed

+36
-6
lines changed

1 file changed

+36
-6
lines changed

tests/utils.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import subprocess
88
import sys
99
import venv
10+
from collections.abc import Mapping
1011
from functools import cache
1112
from pathlib import Path
1213
from typing import NamedTuple
@@ -54,28 +55,57 @@ class PackageDependencies(NamedTuple):
5455
external_pkgs: tuple[str, ...]
5556

5657

58+
@cache
59+
def get_pypi_name_to_typeshed_name_mapping() -> Mapping[str, str]:
60+
stub_name_map = {}
61+
for typeshed_name in os.listdir("stubs"):
62+
with Path("stubs", typeshed_name, "METADATA.toml").open("rb") as f:
63+
pypi_name = tomli.load(f).get("stub_distribution", f"types-{typeshed_name}")
64+
assert isinstance(pypi_name, str)
65+
stub_name_map[pypi_name] = typeshed_name
66+
return stub_name_map
67+
68+
5769
@cache
5870
def read_dependencies(distribution: str) -> PackageDependencies:
71+
"""Read the dependencies listed in a METADATA.toml file for a stubs package.
72+
73+
Once the dependencies have been read,
74+
determine which dependencies are typeshed-internal dependencies,
75+
and which dependencies are external (non-types) dependencies.
76+
For typeshed dependencies, translate the "dependency name" into the "package name";
77+
for external dependencies, leave them as they are in the METADATA.toml file.
78+
79+
Note that this function may consider things to be typeshed stubs
80+
even if they haven't yet been uploaded to PyPI.
81+
If a typeshed stub is removed, this function will consider it to be an external dependency.
82+
"""
83+
pypi_name_to_typeshed_name_mapping = get_pypi_name_to_typeshed_name_mapping()
5984
with Path("stubs", distribution, "METADATA.toml").open("rb") as f:
6085
data = tomli.load(f)
6186
dependencies = data.get("requires", [])
6287
assert isinstance(dependencies, list)
6388
typeshed, external = [], []
6489
for dependency in dependencies:
6590
assert isinstance(dependency, str)
66-
if dependency.startswith("types-"):
67-
maybe_typeshed_dependency = Requirement(dependency).name.removeprefix("types-")
68-
if maybe_typeshed_dependency in os.listdir("stubs"):
69-
typeshed.append(maybe_typeshed_dependency)
70-
else:
71-
external.append(dependency)
91+
maybe_typeshed_dependency = Requirement(dependency).name
92+
if maybe_typeshed_dependency in pypi_name_to_typeshed_name_mapping:
93+
typeshed.append(pypi_name_to_typeshed_name_mapping[maybe_typeshed_dependency])
7294
else:
7395
external.append(dependency)
7496
return PackageDependencies(tuple(typeshed), tuple(external))
7597

7698

7799
@cache
78100
def get_recursive_requirements(package_name: str) -> PackageDependencies:
101+
"""Recursively gather dependencies for a single stubs package.
102+
103+
For example, if the stubs for `caldav`
104+
declare a dependency on typeshed's stubs for `requests`,
105+
and the stubs for requests declare a dependency on typeshed's stubs for `urllib3`,
106+
`get_recursive_requirements("caldav")` will determine that the stubs for `caldav`
107+
have both `requests` and `urllib3` as typeshed-internal dependencies.
108+
"""
79109
typeshed: set[str] = set()
80110
external: set[str] = set()
81111
non_recursive_requirements = read_dependencies(package_name)

0 commit comments

Comments
 (0)