Skip to content

Commit 127d44f

Browse files
authored
feat(poly check, poly libs): include package distributions top namespace for known aliases (#219)
* fix(poly check, poly libs): include package distributions top namespace when collecting known aliases * bump Poetry plugin to 1.21.0 * bump CLI to 1.8.0 * test(distributions): assert returning top namespace from package distributions * fix(test): skip test for non-existing builtin for Python 3.9 and lower, assert those return an empty set
1 parent 629f124 commit 127d44f

File tree

5 files changed

+68
-10
lines changed

5 files changed

+68
-10
lines changed
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
1-
import importlib.metadata
21
from typing import Set
32

43
from polylith import alias
54
from polylith.distributions.core import (
65
distributions_packages,
76
distributions_sub_packages,
7+
get_distributions,
8+
get_packages_distributions,
89
)
910

1011

1112
def known_aliases_and_sub_dependencies(deps: dict, library_alias: list) -> Set[str]:
1213
"""Collect known aliases (packages) for third-party libraries.
1314
1415
When the library origin is not from a lock-file:
15-
collect sub-dependencies for each library, and append to the result.
16+
collect sub-dependencies and distribution top-namespace for each library, and append to the result.
1617
"""
1718

1819
third_party_libs = {k for k, _v in deps["items"].items()}
1920
lock_file = str.endswith(deps["source"], ".lock")
2021

21-
dists = list(importlib.metadata.distributions())
22+
dists = get_distributions()
2223

2324
dist_packages = distributions_packages(dists)
2425
custom_aliases = alias.parse(library_alias)
@@ -28,4 +29,6 @@ def known_aliases_and_sub_dependencies(deps: dict, library_alias: list) -> Set[s
2829
b = alias.pick(custom_aliases, third_party_libs)
2930
c = alias.pick(sub_deps, third_party_libs)
3031

31-
return third_party_libs.union(a, b, c)
32+
d = get_packages_distributions(third_party_libs) if not lock_file else set()
33+
34+
return third_party_libs.union(a, b, c, d)

components/polylith/distributions/core.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from functools import reduce
44
from typing import Dict, List
55

6-
76
SUB_DEP_SEPARATORS = r"[\s!=;><\^~]"
87

98

@@ -53,7 +52,25 @@ def distributions_sub_packages(dists) -> Dict[str, List[str]]:
5352
return reduce(map_sub_packages, dists, {})
5453

5554

56-
def get_distributions(project_dependencies: set) -> list:
57-
dists = importlib.metadata.distributions()
55+
def get_distributions() -> list:
56+
return list(importlib.metadata.distributions())
57+
58+
59+
def get_packages_distributions(project_dependencies: set) -> set:
60+
"""Return the mapped top namespace from an import
61+
62+
Example:
63+
A third-party library, such as opentelemetry-instrumentation-fastapi.
64+
The return value would be the mapped top namespace: opentelemetry
65+
66+
Note: available for Python >= 3.10
67+
"""
68+
69+
# added in Python 3.10
70+
fn = getattr(importlib.metadata, "packages_distributions", None)
71+
72+
dists = fn() if fn else {}
73+
74+
common = {k for k, v in dists.items() if project_dependencies.intersection(set(v))}
5875

59-
return [dist for dist in dists if dist.metadata["name"] in project_dependencies]
76+
return common.difference(project_dependencies)

projects/poetry_polylith_plugin/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "poetry-polylith-plugin"
3-
version = "1.20.1"
3+
version = "1.21.0"
44
description = "A Poetry plugin that adds tooling support for the Polylith Architecture"
55
authors = ["David Vujic"]
66
homepage = "https://davidvujic.github.io/python-polylith-docs/"

projects/polylith_cli/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "polylith-cli"
3-
version = "1.7.1"
3+
version = "1.8.0"
44
description = "Python tooling support for the Polylith Architecture"
55
authors = ['David Vujic']
66
homepage = "https://davidvujic.github.io/python-polylith-docs/"

test/components/polylith/distributions/test_core.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import importlib.metadata
2+
import sys
23

4+
import pytest
35
from polylith import distributions
46

57

@@ -40,3 +42,39 @@ def test_distribution_sub_packages():
4042

4143
assert res.get(expected_dist) is not None
4244
assert expected_sub_package in res[expected_dist]
45+
46+
47+
@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
48+
def test_package_distributions_returning_top_namespace(monkeypatch):
49+
fake_dists = {
50+
"something": ["something-subnamespace"],
51+
"opentelemetry": ["opentelemetry-instrumentation-fastapi"],
52+
"google": ["google-cloud-storage", "google-api-core"],
53+
"other": ["other-sub-ns"],
54+
}
55+
56+
fake_project_deps = {
57+
"opentelemetry-instrumentation-fastapi",
58+
"fastapi",
59+
"something-subnamespace",
60+
"google-cloud-storage",
61+
}
62+
63+
monkeypatch.setattr(
64+
distributions.core.importlib.metadata,
65+
"packages_distributions",
66+
lambda: fake_dists,
67+
)
68+
69+
res = distributions.core.get_packages_distributions(fake_project_deps)
70+
71+
assert res == {"google", "opentelemetry", "something"}
72+
73+
74+
@pytest.mark.skipif(sys.version_info > (3, 9), reason="asserting python3.9 and lower")
75+
def test_package_distributions_returning_empty_set():
76+
fake_project_deps = {"something-subnamespace"}
77+
78+
res = distributions.core.get_packages_distributions(fake_project_deps)
79+
80+
assert res == set()

0 commit comments

Comments
 (0)