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
7 changes: 5 additions & 2 deletions bases/polylith/cli/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,17 @@ def sync_command(


@app.command("deps")
def deps_command(directory: Annotated[str, options.directory] = ""):
def deps_command(
directory: Annotated[str, options.directory] = "",
brick: Annotated[str, options.brick] = "",
):
"""Visualize the dependencies between bricks."""
root = repo.get_workspace_root(Path.cwd())
ns = configuration.get_namespace_from_config(root)

dir_path = Path(directory).as_posix() if directory else None

commands.deps.run(root, ns, dir_path)
commands.deps.run(root, ns, dir_path, brick or None)


if __name__ == "__main__":
Expand Down
2 changes: 2 additions & 0 deletions bases/polylith/cli/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@

verbose = Option(help="More verbose output.")
quiet = Option(help="Do not output any messages.")

brick = Option(help="Shows dependencies for selected brick.")
16 changes: 10 additions & 6 deletions components/polylith/commands/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
from polylith import bricks, deps, info


def print_report(root: Path, ns: str, bases: Set[str], components: Set[str]):
def get_imports(root: Path, ns: str, bases: Set[str], components: Set[str]) -> dict:
brick_imports = deps.get_brick_imports(root, ns, bases, components)

flattened = {**brick_imports["bases"], **brick_imports["components"]}

deps.print_deps(bases, components, flattened)
return {**brick_imports["bases"], **brick_imports["components"]}


def pick_name(data: List[dict]) -> Set[str]:
Expand All @@ -30,11 +28,17 @@ def get_components(root: Path, ns: str, project_data: dict) -> Set[str]:
return pick_name(bricks.get_components_data(root, ns))


def run(root: Path, ns: str, directory: Union[str, None]):
def run(root: Path, ns: str, directory: Union[str, None], brick: Union[str, None]):
projects_data = info.get_projects_data(root, ns) if directory else []
project = next((p for p in projects_data if directory in p["path"].as_posix()), {})

bases = get_bases(root, ns, project)
components = get_components(root, ns, project)

print_report(root, ns, bases, components)
imports = get_imports(root, ns, bases, components)

if brick and imports.get(brick):
deps.print_brick_deps(brick, bases, components, imports)
return

deps.print_deps(bases, components, imports)
4 changes: 2 additions & 2 deletions components/polylith/deps/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from polylith.deps.core import get_brick_imports
from polylith.deps.report import print_deps
from polylith.deps.report import print_brick_deps, print_deps

__all__ = ["get_brick_imports", "print_deps"]
__all__ = ["get_brick_imports", "print_brick_deps", "print_deps"]
68 changes: 64 additions & 4 deletions components/polylith/deps/report.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from functools import reduce
from itertools import zip_longest
from typing import List, Set, Tuple

from polylith.reporting import theme
Expand All @@ -7,10 +8,6 @@
from rich.table import Table


def calculate_tag(brick: str, project_data: dict) -> str:
return "base" if brick in project_data.get("bases", []) else "comp"


def to_col(brick: str, tag: str) -> str:
name = "\n".join(brick)

Expand Down Expand Up @@ -80,5 +77,68 @@ def print_deps(bases: Set[str], components: Set[str], import_data: dict):
table.add_row(*row)

console = Console(theme=theme.poly_theme)
console.print(table, overflow="ellipsis")


def without(key: str, bricks: Set[str]) -> Set[str]:
return {b for b in bricks if b != key}


def sorted_usings(usings: Set[str], bases: Set[str], components: Set[str]) -> List[str]:
usings_bases = sorted({b for b in usings if b in bases})
usings_components = sorted({c for c in usings if c in components})

return usings_components + usings_bases


def sorted_used_by(
brick: str, bases: Set[str], components: Set[str], import_data: dict
) -> List[str]:
brick_used_by = without(brick, {k for k, v in import_data.items() if brick in v})

return sorted_usings(brick_used_by, bases, components)


def sorted_uses(
brick: str, bases: Set[str], components: Set[str], import_data: dict
) -> List[str]:
brick_uses = without(brick, {b for b in import_data[brick]})

return sorted_usings(brick_uses, bases, components)


def calculate_tag(brick: str, bases: Set[str]) -> str:
return "base" if brick in bases else "comp"


def print_brick_deps(
brick: str, bases: Set[str], components: Set[str], import_data: dict
):
brick_used_by = sorted_used_by(brick, bases, components, import_data)
brick_uses = sorted_uses(brick, bases, components, import_data)

tag = calculate_tag(brick, bases)

console = Console(theme=theme.poly_theme)

table = Table(box=box.SIMPLE_HEAD)
table.add_column("[data]used by[/]")
table.add_column(":backhand_index_pointing_left:")
table.add_column(f"[{tag}]{brick}[/]")
table.add_column(":backhand_index_pointing_right:")
table.add_column("[data]uses[/]")

for item in zip_longest(brick_used_by, brick_uses):
used_by, uses = item

used_by_tag = calculate_tag(used_by, bases) if used_by else ""
uses_tag = calculate_tag(uses, bases) if uses else ""

left = f"[{used_by_tag}]{used_by}[/]" if used_by else ""
right = f"[{uses_tag}]{uses}[/]" if uses else ""

row = [left, "", "", "", right]

table.add_row(*row)

console.print(table, overflow="ellipsis")
13 changes: 12 additions & 1 deletion components/polylith/poetry/commands/deps.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
from cleo.helpers import option

from poetry.console.commands.command import Command
from polylith import commands, configuration, repo
Expand All @@ -8,13 +9,23 @@ class DepsCommand(Command):
name = "poly deps"
description = "Visualize the dependencies between <comment>bricks</>."

options = [
option(
long_name="brick",
description="Shows dependencies for selected brick",
flag=False,
),
]

def handle(self) -> int:
directory = self.option("directory")
brick = self.option("brick")

root = repo.get_workspace_root(Path.cwd())
ns = configuration.get_namespace_from_config(root)

dir_path = Path(directory).as_posix() if directory else None

commands.deps.run(root, ns, dir_path)
commands.deps.run(root, ns, dir_path, brick)

return 0
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.16.0"
version = "1.17.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.3.0"
version = "1.4.0"
description = "Python tooling support for the Polylith Architecture"
authors = ['David Vujic']
homepage = "https://davidvujic.github.io/python-polylith-docs/"
Expand Down