Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions components/polylith/distributions/collect.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import importlib.metadata
from typing import Set

from polylith import alias
from polylith.distributions.core import (
distributions_packages,
distributions_sub_packages,
get_distributions,
get_packages_distributions,
)


def known_aliases_and_sub_dependencies(deps: dict, library_alias: list) -> Set[str]:
"""Collect known aliases (packages) for third-party libraries.

When the library origin is not from a lock-file:
collect sub-dependencies for each library, and append to the result.
collect sub-dependencies and distribution top-namespace for each library, and append to the result.
"""

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

dists = list(importlib.metadata.distributions())
dists = get_distributions()

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

return third_party_libs.union(a, b, c)
d = get_packages_distributions(third_party_libs) if not lock_file else set()

return third_party_libs.union(a, b, c, d)
25 changes: 21 additions & 4 deletions components/polylith/distributions/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from functools import reduce
from typing import Dict, List


SUB_DEP_SEPARATORS = r"[\s!=;><\^~]"


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


def get_distributions(project_dependencies: set) -> list:
dists = importlib.metadata.distributions()
def get_distributions() -> list:
return list(importlib.metadata.distributions())


def get_packages_distributions(project_dependencies: set) -> set:
"""Return the mapped top namespace from an import

Example:
A third-party library, such as opentelemetry-instrumentation-fastapi.
The return value would be the mapped top namespace: opentelemetry

Note: available for Python >= 3.10
"""

# added in Python 3.10
fn = getattr(importlib.metadata, "packages_distributions", None)

dists = fn() if fn else {}

common = {k for k, v in dists.items() if project_dependencies.intersection(set(v))}

return [dist for dist in dists if dist.metadata["name"] in project_dependencies]
return common.difference(project_dependencies)
2 changes: 1 addition & 1 deletion projects/poetry_polylith_plugin/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "poetry-polylith-plugin"
version = "1.20.1"
version = "1.21.0"
description = "A Poetry plugin that adds tooling support for the Polylith Architecture"
authors = ["David Vujic"]
homepage = "https://davidvujic.github.io/python-polylith-docs/"
Expand Down
2 changes: 1 addition & 1 deletion projects/polylith_cli/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "polylith-cli"
version = "1.7.1"
version = "1.8.0"
description = "Python tooling support for the Polylith Architecture"
authors = ['David Vujic']
homepage = "https://davidvujic.github.io/python-polylith-docs/"
Expand Down
38 changes: 38 additions & 0 deletions test/components/polylith/distributions/test_core.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import importlib.metadata
import sys

import pytest
from polylith import distributions


Expand Down Expand Up @@ -40,3 +42,39 @@ def test_distribution_sub_packages():

assert res.get(expected_dist) is not None
assert expected_sub_package in res[expected_dist]


@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
def test_package_distributions_returning_top_namespace(monkeypatch):
fake_dists = {
"something": ["something-subnamespace"],
"opentelemetry": ["opentelemetry-instrumentation-fastapi"],
"google": ["google-cloud-storage", "google-api-core"],
"other": ["other-sub-ns"],
}

fake_project_deps = {
"opentelemetry-instrumentation-fastapi",
"fastapi",
"something-subnamespace",
"google-cloud-storage",
}

monkeypatch.setattr(
distributions.core.importlib.metadata,
"packages_distributions",
lambda: fake_dists,
)

res = distributions.core.get_packages_distributions(fake_project_deps)

assert res == {"google", "opentelemetry", "something"}


@pytest.mark.skipif(sys.version_info > (3, 9), reason="asserting python3.9 and lower")
def test_package_distributions_returning_empty_set():
fake_project_deps = {"something-subnamespace"}

res = distributions.core.get_packages_distributions(fake_project_deps)

assert res == set()