From 4efa79b199e697c6c42ab22fd2b48157e2a7bd20 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Fri, 19 Jan 2024 17:03:08 +0100 Subject: [PATCH 01/31] wip(cli): add hatch build hook for parsing project bricks --- .../hatch_bricks_build_hook/__init__.py | 3 + .../polylith/hatch_bricks_build_hook/core.py | 8 +++ .../hatch_bricks_build_hook/plugin.py | 58 ++++++++++++++++++ components/polylith/parsing/__init__.py | 4 ++ components/polylith/parsing/core.py | 23 +++++++ components/polylith/parsing/rewrite.py | 60 +++++++++++++++++++ components/polylith/project/__init__.py | 2 + poetry.lock | 32 +++++++++- pyproject.toml | 3 + test/components/polylith/parsing/__init__.py | 0 test/components/polylith/parsing/test_core.py | 14 +++++ 11 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 bases/polylith/hatch_bricks_build_hook/__init__.py create mode 100644 bases/polylith/hatch_bricks_build_hook/core.py create mode 100644 bases/polylith/hatch_bricks_build_hook/plugin.py create mode 100644 components/polylith/parsing/__init__.py create mode 100644 components/polylith/parsing/core.py create mode 100644 components/polylith/parsing/rewrite.py create mode 100644 test/components/polylith/parsing/__init__.py create mode 100644 test/components/polylith/parsing/test_core.py diff --git a/bases/polylith/hatch_bricks_build_hook/__init__.py b/bases/polylith/hatch_bricks_build_hook/__init__.py new file mode 100644 index 00000000..46894f95 --- /dev/null +++ b/bases/polylith/hatch_bricks_build_hook/__init__.py @@ -0,0 +1,3 @@ +from polylith.hatch_bricks_build_hook import core + +__all__ = ["core"] diff --git a/bases/polylith/hatch_bricks_build_hook/core.py b/bases/polylith/hatch_bricks_build_hook/core.py new file mode 100644 index 00000000..0fc0454a --- /dev/null +++ b/bases/polylith/hatch_bricks_build_hook/core.py @@ -0,0 +1,8 @@ +from hatchling.plugin import hookimpl + +from polylith.hatch_bricks_build_hook.plugin import PolylithBricksHook + + +@hookimpl +def hatch_register_build_hook(): + return PolylithBricksHook diff --git a/bases/polylith/hatch_bricks_build_hook/plugin.py b/bases/polylith/hatch_bricks_build_hook/plugin.py new file mode 100644 index 00000000..4f69f392 --- /dev/null +++ b/bases/polylith/hatch_bricks_build_hook/plugin.py @@ -0,0 +1,58 @@ +import shutil +from pathlib import Path +from typing import Any, Dict + +from hatchling.builders.hooks.plugin.interface import BuildHookInterface +from polylith import parsing, project, repo + + +def get_temp_dir(config: dict) -> Path: + tmp_dir = config.get("tmp_dir", ".tmp") + + return Path(tmp_dir) + + +class PolylithBricksHook(BuildHookInterface): + PLUGIN_NAME = "polylith-bricks" + + def initialize(self, version: str, build_data: Dict[str, Any]) -> None: + top_ns = self.config.get("top_namespace") + pyproject = Path(f"{self.root}/{repo.default_toml}") + + data = project.get_toml(pyproject) + bricks = project.get_project_packages_from_polylith_section(data) + + if not bricks: + return + + if not top_ns: + build_data["force_include"] = bricks + return + + namespaces = parsing.parse_brick_namespace_from_path(bricks) + ns = next(namespace for namespace in namespaces) + + tmp_dir = get_temp_dir(self.config) + + for source, brick in bricks.items(): + destination = Path(tmp_dir / brick).as_posix() + res = parsing.copy_brick(source, destination) + + modules = res.glob("**/*.py") + + for module in modules: + was_rewritten = parsing.rewrite_module(module, ns, top_ns) + + if was_rewritten: + print(f"Updated {module.parent.name}/{module.name}.") + + key = tmp_dir.as_posix() + build_data["force_include"][key] = top_ns + + def finalize( + self, version: str, build_data: Dict[str, Any], artifact_path: str + ) -> None: + tmp_dir = get_temp_dir(self.config) + + if tmp_dir.exists() and tmp_dir.is_dir(): + shutil.rmtree(tmp_dir.as_posix()) diff --git a/components/polylith/parsing/__init__.py b/components/polylith/parsing/__init__.py new file mode 100644 index 00000000..67f8b428 --- /dev/null +++ b/components/polylith/parsing/__init__.py @@ -0,0 +1,4 @@ +from polylith.parsing.core import copy_brick, parse_brick_namespace_from_path +from polylith.parsing.rewrite import rewrite_module + +__all__ = ["copy_brick", "parse_brick_namespace_from_path", "rewrite_module"] diff --git a/components/polylith/parsing/core.py b/components/polylith/parsing/core.py new file mode 100644 index 00000000..b16fef3b --- /dev/null +++ b/components/polylith/parsing/core.py @@ -0,0 +1,23 @@ +import shutil +from pathlib import Path + + +def copy_brick(source: str, destination: str) -> Path: + ignore = shutil.ignore_patterns( + "*.pyc", + "__pycache__", + ".venv", + ".mypy_cache", + "node_modules", + ".git", + ) + + res = shutil.copytree(source, destination, ignore=ignore, dirs_exist_ok=True) + + return Path(res) + + +def parse_brick_namespace_from_path(bricks: dict) -> set: + parts = {str.split(v, "/")[0] for v in bricks.values()} + + return parts diff --git a/components/polylith/parsing/rewrite.py b/components/polylith/parsing/rewrite.py new file mode 100644 index 00000000..b61d031c --- /dev/null +++ b/components/polylith/parsing/rewrite.py @@ -0,0 +1,60 @@ +import ast +from pathlib import Path + + +def create_namespace_path(top_ns: str, current: str) -> str: + top_ns_module_path = top_ns.replace("/", ".") + return f"{top_ns_module_path}.{current}" + + +def mutate_import(node: ast.Import, ns: str, top_ns: str) -> bool: + did_mutate = False + + for alias in node.names: + if alias.name == ns: + alias.name = create_namespace_path(top_ns, alias.name) + did_mutate = True + + return did_mutate + + +def mutate_import_from(node: ast.ImportFrom, ns: str, top_ns: str) -> bool: + did_mutate = False + + if not node.module or node.level != 0: + return did_mutate + + if node.module == ns or node.module.startswith(f"{ns}."): + node.module = create_namespace_path(top_ns, node.module) + did_mutate = True + + return did_mutate + + +def mutate_imports(node: ast.AST, ns: str, top_ns: str) -> bool: + if isinstance(node, ast.Import): + return mutate_import(node, ns, top_ns) + + if isinstance(node, ast.ImportFrom): + return mutate_import_from(node, ns, top_ns) + + return False + + +def rewrite_module(source: Path, ns: str, top_ns: str) -> bool: + file_path = source.as_posix() + + with open(file_path, "r", encoding="utf-8") as f: + tree = ast.parse(f.read(), source.name) + + res = {mutate_imports(node, ns, top_ns) for node in ast.walk(tree)} + + if True in res: + rewritten_source_code = ast.unparse(tree) # type: ignore[attr-defined] + + with open(file_path, "w", encoding="utf-8", newline="") as f: + f.write(rewritten_source_code) + + return True + + return False diff --git a/components/polylith/project/__init__.py b/components/polylith/project/__init__.py index 7040d729..a6ddbe59 100644 --- a/components/polylith/project/__init__.py +++ b/components/polylith/project/__init__.py @@ -4,6 +4,7 @@ get_packages_for_projects, get_project_dependencies, get_project_name, + get_project_packages_from_polylith_section, get_toml, ) from polylith.project.parser import parse_package_paths @@ -13,6 +14,7 @@ "get_packages_for_projects", "get_project_dependencies", "get_project_name", + "get_project_packages_from_polylith_section", "get_toml", "parse_package_paths", "templates", diff --git a/poetry.lock b/poetry.lock index 7743811d..b20ff494 100644 --- a/poetry.lock +++ b/poetry.lock @@ -459,6 +459,17 @@ https = ["urllib3 (>=1.24.1)"] paramiko = ["paramiko"] pgp = ["gpg"] +[[package]] +name = "editables" +version = "0.5" +description = "Editable installations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "editables-0.5-py3-none-any.whl", hash = "sha256:61e5ffa82629e0d8bfe09bc44a07db3c1ab8ed1ce78a6980732870f19b5e7d4c"}, + {file = "editables-0.5.tar.gz", hash = "sha256:309627d9b5c4adc0e668d8c6fa7bac1ba7c8c5d415c2d27f60f081f8e80d1de2"}, +] + [[package]] name = "exceptiongroup" version = "1.2.0" @@ -519,6 +530,25 @@ mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.11.0,<2.12.0" pyflakes = ">=3.2.0,<3.3.0" +[[package]] +name = "hatchling" +version = "1.21.0" +description = "Modern, extensible Python build backend" +optional = false +python-versions = ">=3.8" +files = [ + {file = "hatchling-1.21.0-py3-none-any.whl", hash = "sha256:b33ef0ecdee6dbfd28c21ca30df459ba1d566050d033f8b5a1d0e26e5606d26b"}, + {file = "hatchling-1.21.0.tar.gz", hash = "sha256:5c086772357a50723b825fd5da5278ac7e3697cdf7797d07541a6c90b6ff754c"}, +] + +[package.dependencies] +editables = ">=0.3" +packaging = ">=21.3" +pathspec = ">=0.10.1" +pluggy = ">=1.0.0" +tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} +trove-classifiers = "*" + [[package]] name = "idna" version = "3.6" @@ -1477,4 +1507,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "de65e90775c58e5e930efa83146526a3879827f46296afad0d4031081992315a" +content-hash = "28699790093c8c0b68111d1a436c94c72469405980dd2dfc3d57eb4288f61c56" diff --git a/pyproject.toml b/pyproject.toml index e5f1547c..e3cd80b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ readme = "README.md" packages = [ {include = "polylith/poetry_plugin",from = "bases"}, {include = "polylith/cli",from = "bases"}, + {include = "polylith/hatch_bricks_build_hook", from = "bases"}, {include = "polylith/alias",from = "components"}, {include = "polylith/bricks",from = "components"}, {include = "polylith/check",from = "components"}, @@ -22,6 +23,7 @@ packages = [ {include = "polylith/info",from = "components"}, {include = "polylith/interface",from = "components"}, {include = "polylith/libs",from = "components"}, + {include = "polylith/parsing",from = "components"}, {include = "polylith/poetry",from = "components"}, {include = "polylith/project",from = "components"}, {include = "polylith/readme",from = "components"}, @@ -40,6 +42,7 @@ tomlkit = "^0.11.5" rich = "^13.6.0" typer = {extras = ["all"], version = "^0.9.0"} cleo = "^2.1.0" +hatchling = "^1.21.0" [tool.poetry.group.dev.dependencies] black = "^23.12.1" diff --git a/test/components/polylith/parsing/__init__.py b/test/components/polylith/parsing/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/components/polylith/parsing/test_core.py b/test/components/polylith/parsing/test_core.py new file mode 100644 index 00000000..679d734d --- /dev/null +++ b/test/components/polylith/parsing/test_core.py @@ -0,0 +1,14 @@ +from polylith.parsing import core + + +expected_ns = "unittest" +bricks = { + f"../../bases/{expected_ns}/one": f"{expected_ns}/one", + f"../../components/{expected_ns}/two": f"{expected_ns}/two", +} + + +def test_parse_brick_namespace_from_path(): + res = core.parse_brick_namespace_from_path(bricks) + + assert res == {expected_ns} From c08db849d0bb6f3dfe0e64dbd5f7703a72f983cf Mon Sep 17 00:00:00 2001 From: David Vujic Date: Fri, 19 Jan 2024 17:34:30 +0100 Subject: [PATCH 02/31] wip(cli): add hatch build hook for parsing project bricks --- .../hatch_bricks_build_hook/__init__.py | 3 - .../hatch_bricks_build_hook/plugin.py | 64 +++++++++++-------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/bases/polylith/hatch_bricks_build_hook/__init__.py b/bases/polylith/hatch_bricks_build_hook/__init__.py index 46894f95..e69de29b 100644 --- a/bases/polylith/hatch_bricks_build_hook/__init__.py +++ b/bases/polylith/hatch_bricks_build_hook/__init__.py @@ -1,3 +0,0 @@ -from polylith.hatch_bricks_build_hook import core - -__all__ = ["core"] diff --git a/bases/polylith/hatch_bricks_build_hook/plugin.py b/bases/polylith/hatch_bricks_build_hook/plugin.py index 4f69f392..bd7b8645 100644 --- a/bases/polylith/hatch_bricks_build_hook/plugin.py +++ b/bases/polylith/hatch_bricks_build_hook/plugin.py @@ -6,17 +6,42 @@ from polylith import parsing, project, repo -def get_temp_dir(config: dict) -> Path: - tmp_dir = config.get("tmp_dir", ".tmp") +def get_work_dir(config: dict) -> Path: + work_dir = config.get("work_dir", ".tmp") - return Path(tmp_dir) + return Path(work_dir) + + +def parse_namespace(bricks: dict) -> str: + namespaces = parsing.parse_brick_namespace_from_path(bricks) + + return next(namespace for namespace in namespaces) + + +def copy_brick(source: str, brick: str, tmp_dir: Path) -> Path: + destination = Path(tmp_dir / brick).as_posix() + + return parsing.copy_brick(source, destination) + + +def rewrite_modules(path: Path, ns: str, top_ns: str) -> None: + modules = path.glob("**/*.py") + + for module in modules: + was_rewritten = parsing.rewrite_module(module, ns, top_ns) + + if was_rewritten: + print( + f"Updated {module.parent.name}/{module.name} with new top namespace for local imports." + ) class PolylithBricksHook(BuildHookInterface): PLUGIN_NAME = "polylith-bricks" - def initialize(self, version: str, build_data: Dict[str, Any]) -> None: + def initialize(self, _version: str, build_data: Dict[str, Any]) -> None: top_ns = self.config.get("top_namespace") + work_dir = get_work_dir(self.config) pyproject = Path(f"{self.root}/{repo.default_toml}") data = project.get_toml(pyproject) @@ -29,30 +54,19 @@ def initialize(self, version: str, build_data: Dict[str, Any]) -> None: build_data["force_include"] = bricks return - namespaces = parsing.parse_brick_namespace_from_path(bricks) - ns = next(namespace for namespace in namespaces) - - tmp_dir = get_temp_dir(self.config) + ns = parse_namespace(bricks) for source, brick in bricks.items(): - destination = Path(tmp_dir / brick).as_posix() - res = parsing.copy_brick(source, destination) - - modules = res.glob("**/*.py") + path = copy_brick(source, brick, work_dir) + rewrite_modules(path, ns, top_ns) - for module in modules: - was_rewritten = parsing.rewrite_module(module, ns, top_ns) - - if was_rewritten: - print(f"Updated {module.parent.name}/{module.name}.") - - key = tmp_dir.as_posix() + key = work_dir.as_posix() build_data["force_include"][key] = top_ns - def finalize( - self, version: str, build_data: Dict[str, Any], artifact_path: str - ) -> None: - tmp_dir = get_temp_dir(self.config) + def finalize(self, *args, **kwargs) -> None: + work_dir = get_work_dir(self.config) + + if not work_dir.exists() or not work_dir.is_dir(): + return - if tmp_dir.exists() and tmp_dir.is_dir(): - shutil.rmtree(tmp_dir.as_posix()) + shutil.rmtree(work_dir.as_posix()) From d16fc80a66300c1fc62101707a08c517cbb1841c Mon Sep 17 00:00:00 2001 From: David Vujic Date: Fri, 19 Jan 2024 17:46:33 +0100 Subject: [PATCH 03/31] wip(cli): add hatch build hook for parsing project bricks --- .../{hatch_bricks_build_hook => hatch_hooks/bricks}/__init__.py | 0 .../core.py => hatch_hooks/bricks/hooks.py} | 2 +- .../{hatch_bricks_build_hook => hatch_hooks/bricks}/plugin.py | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename bases/polylith/{hatch_bricks_build_hook => hatch_hooks/bricks}/__init__.py (100%) rename bases/polylith/{hatch_bricks_build_hook/core.py => hatch_hooks/bricks/hooks.py} (61%) rename bases/polylith/{hatch_bricks_build_hook => hatch_hooks/bricks}/plugin.py (100%) diff --git a/bases/polylith/hatch_bricks_build_hook/__init__.py b/bases/polylith/hatch_hooks/bricks/__init__.py similarity index 100% rename from bases/polylith/hatch_bricks_build_hook/__init__.py rename to bases/polylith/hatch_hooks/bricks/__init__.py diff --git a/bases/polylith/hatch_bricks_build_hook/core.py b/bases/polylith/hatch_hooks/bricks/hooks.py similarity index 61% rename from bases/polylith/hatch_bricks_build_hook/core.py rename to bases/polylith/hatch_hooks/bricks/hooks.py index 0fc0454a..bb954f16 100644 --- a/bases/polylith/hatch_bricks_build_hook/core.py +++ b/bases/polylith/hatch_hooks/bricks/hooks.py @@ -1,6 +1,6 @@ from hatchling.plugin import hookimpl -from polylith.hatch_bricks_build_hook.plugin import PolylithBricksHook +from polylith.hatch_hooks.bricks.plugin import PolylithBricksHook @hookimpl diff --git a/bases/polylith/hatch_bricks_build_hook/plugin.py b/bases/polylith/hatch_hooks/bricks/plugin.py similarity index 100% rename from bases/polylith/hatch_bricks_build_hook/plugin.py rename to bases/polylith/hatch_hooks/bricks/plugin.py From 5d12f7ea1b911b73d0069d29116fc620993002f5 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Fri, 19 Jan 2024 18:04:46 +0100 Subject: [PATCH 04/31] fix(cli): correct create project input args --- bases/polylith/cli/create.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bases/polylith/cli/create.py b/bases/polylith/cli/create.py index cd8fcc14..d7806bab 100644 --- a/bases/polylith/cli/create.py +++ b/bases/polylith/cli/create.py @@ -29,8 +29,10 @@ def component_command( create(name, description, component.create_component) -def _create_project(root: Path, _ns: str, name: str, description: Union[str, None]): +def _create_project(root: Path, options: dict): root_pyproject: dict = project.get_toml(root / repo.default_toml) + name = options["package"] + description = options["description"] if repo.is_poetry(root_pyproject): template = project.templates.poetry_pyproject From 1be572e28d445b4b3c0ea5c34cf237df48a5e85c Mon Sep 17 00:00:00 2001 From: David Vujic Date: Fri, 19 Jan 2024 18:05:06 +0100 Subject: [PATCH 05/31] fix: hatch hook base --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e3cd80b8..9a74313d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ readme = "README.md" packages = [ {include = "polylith/poetry_plugin",from = "bases"}, {include = "polylith/cli",from = "bases"}, - {include = "polylith/hatch_bricks_build_hook", from = "bases"}, + {include = "polylith/hatch_hooks", from = "bases"}, {include = "polylith/alias",from = "components"}, {include = "polylith/bricks",from = "components"}, {include = "polylith/check",from = "components"}, From c060aca267530050b37da916e159cdb7d75f7809 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Fri, 19 Jan 2024 18:05:27 +0100 Subject: [PATCH 06/31] wip(hatch build hook): add project --- .../hatch-bricks-build-hook/pyproject.toml | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 projects/hatch-bricks-build-hook/pyproject.toml diff --git a/projects/hatch-bricks-build-hook/pyproject.toml b/projects/hatch-bricks-build-hook/pyproject.toml new file mode 100644 index 00000000..747591ee --- /dev/null +++ b/projects/hatch-bricks-build-hook/pyproject.toml @@ -0,0 +1,29 @@ +[tool.poetry] +name = "hatch-bricks-build-hook" +version = "0.1.0" +description = "Hatch build hook plugin for Polylith bricks" +authors = ['David Vujic'] +license = "MIT" + +packages = [ + {include = "polylith/hatch_hooks", from = "../../bases"}, + {include = "polylith/files",from = "../../components"}, + {include = "polylith/readme",from = "../../components"}, + {include = "polylith/dirs",from = "../../components"}, + {include = "polylith/repo",from = "../../components"}, + {include = "polylith/parsing",from = "../../components"}, + {include = "polylith/workspace",from = "../../components"}, + {include = "polylith/project",from = "../../components"}, + {include = "polylith/development",from = "../../components"}, +] + +[tool.poetry.dependencies] +python = "^3.8.1" +hatchling = "^1.21.0" + +[project.entry-points.hatch] +polylith-bricks = "hatch_hooks.bricks.hooks" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" From 6f95dccfc1855a28240e04a42753eb9ab9c96d71 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Fri, 19 Jan 2024 18:05:57 +0100 Subject: [PATCH 07/31] fix(cli): correct create project input args --- bases/polylith/cli/create.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bases/polylith/cli/create.py b/bases/polylith/cli/create.py index d7806bab..7008bdfd 100644 --- a/bases/polylith/cli/create.py +++ b/bases/polylith/cli/create.py @@ -1,5 +1,4 @@ from pathlib import Path -from typing import Union from polylith import project, repo from polylith.bricks import base, component From aa450f94b1f9c1dcd4e21fb081afa11002c5d3b1 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 11:40:18 +0100 Subject: [PATCH 08/31] refactor: extract into new toml brick, rearrange hatch build hook project --- .../hatch_hooks/{bricks => }/__init__.py | 0 .../hatch_hooks/{bricks => }/hooks.py | 2 +- components/polylith/hatch/hooks/__init__.py | 3 + .../polylith/hatch/hooks/bricks.py | 6 +- components/polylith/project/__init__.py | 10 +- components/polylith/project/get.py | 76 ++------------- components/polylith/toml/__init__.py | 13 +++ components/polylith/toml/core.py | 67 +++++++++++++ projects/hatch-bricks-build-hook/poetry.lock | 95 +++++++++++++++++++ .../hatch-bricks-build-hook/pyproject.toml | 10 +- .../poetry_polylith_plugin/pyproject.toml | 1 + projects/polylith-cli/pyproject.toml | 1 + pyproject.toml | 2 + test/components/polylith/hatch/__init__.py | 0 test/components/polylith/hatch/test_core.py | 5 + test/components/polylith/toml/__init__.py | 0 .../test_project_get.py => toml/test_core.py} | 10 +- 17 files changed, 207 insertions(+), 94 deletions(-) rename bases/polylith/hatch_hooks/{bricks => }/__init__.py (100%) rename bases/polylith/hatch_hooks/{bricks => }/hooks.py (63%) create mode 100644 components/polylith/hatch/hooks/__init__.py rename bases/polylith/hatch_hooks/bricks/plugin.py => components/polylith/hatch/hooks/bricks.py (92%) create mode 100644 components/polylith/toml/__init__.py create mode 100644 components/polylith/toml/core.py create mode 100644 projects/hatch-bricks-build-hook/poetry.lock create mode 100644 test/components/polylith/hatch/__init__.py create mode 100644 test/components/polylith/hatch/test_core.py create mode 100644 test/components/polylith/toml/__init__.py rename test/components/polylith/{project/test_project_get.py => toml/test_core.py} (82%) diff --git a/bases/polylith/hatch_hooks/bricks/__init__.py b/bases/polylith/hatch_hooks/__init__.py similarity index 100% rename from bases/polylith/hatch_hooks/bricks/__init__.py rename to bases/polylith/hatch_hooks/__init__.py diff --git a/bases/polylith/hatch_hooks/bricks/hooks.py b/bases/polylith/hatch_hooks/hooks.py similarity index 63% rename from bases/polylith/hatch_hooks/bricks/hooks.py rename to bases/polylith/hatch_hooks/hooks.py index bb954f16..4cc9749a 100644 --- a/bases/polylith/hatch_hooks/bricks/hooks.py +++ b/bases/polylith/hatch_hooks/hooks.py @@ -1,6 +1,6 @@ from hatchling.plugin import hookimpl -from polylith.hatch_hooks.bricks.plugin import PolylithBricksHook +from polylith.hatch.hooks.bricks import PolylithBricksHook @hookimpl diff --git a/components/polylith/hatch/hooks/__init__.py b/components/polylith/hatch/hooks/__init__.py new file mode 100644 index 00000000..b8a46187 --- /dev/null +++ b/components/polylith/hatch/hooks/__init__.py @@ -0,0 +1,3 @@ +from polylith.hatch.hooks import bricks + +__all__ = ["bricks"] diff --git a/bases/polylith/hatch_hooks/bricks/plugin.py b/components/polylith/hatch/hooks/bricks.py similarity index 92% rename from bases/polylith/hatch_hooks/bricks/plugin.py rename to components/polylith/hatch/hooks/bricks.py index bd7b8645..5069704e 100644 --- a/bases/polylith/hatch_hooks/bricks/plugin.py +++ b/components/polylith/hatch/hooks/bricks.py @@ -3,7 +3,7 @@ from typing import Any, Dict from hatchling.builders.hooks.plugin.interface import BuildHookInterface -from polylith import parsing, project, repo +from polylith import toml, parsing, repo def get_work_dir(config: dict) -> Path: @@ -44,8 +44,8 @@ def initialize(self, _version: str, build_data: Dict[str, Any]) -> None: work_dir = get_work_dir(self.config) pyproject = Path(f"{self.root}/{repo.default_toml}") - data = project.get_toml(pyproject) - bricks = project.get_project_packages_from_polylith_section(data) + data = toml.read_toml_document(pyproject) + bricks = toml.get_project_packages_from_polylith_section(data) if not bricks: return diff --git a/components/polylith/project/__init__.py b/components/polylith/project/__init__.py index a6ddbe59..45309b8e 100644 --- a/components/polylith/project/__init__.py +++ b/components/polylith/project/__init__.py @@ -1,20 +1,12 @@ from polylith.project import templates from polylith.project.create import create_project -from polylith.project.get import ( - get_packages_for_projects, - get_project_dependencies, - get_project_name, - get_project_packages_from_polylith_section, - get_toml, -) +from polylith.project.get import get_packages_for_projects, get_project_name, get_toml from polylith.project.parser import parse_package_paths __all__ = [ "create_project", "get_packages_for_projects", - "get_project_dependencies", "get_project_name", - "get_project_packages_from_polylith_section", "get_toml", "parse_package_paths", "templates", diff --git a/components/polylith/project/get.py b/components/polylith/project/get.py index 0079cd61..c770089b 100644 --- a/components/polylith/project/get.py +++ b/components/polylith/project/get.py @@ -1,57 +1,9 @@ -import re from functools import lru_cache from pathlib import Path -from typing import Any, List +from typing import List import tomlkit -from polylith import repo, workspace - - -def transform_to_package(namespace: str, include: str) -> dict: - path, _separator, brick = str.partition(include, f"/{namespace}/") - - return {"include": f"{namespace}/{brick}", "from": path} - - -def find_by_key(data: dict, key: str) -> Any: - if key in data.keys(): - return data[key] - - filtered = {k: v for k, v in data.items() if isinstance(data[k], dict)} - - res = (find_by_key(data[k], key) for k in filtered.keys()) - - return next((r for r in res if r), None) - - -def get_project_packages_from_polylith_section(data) -> dict: - bricks = data["tool"].get("polylith", {}).get("bricks") - - return bricks if isinstance(bricks, dict) else {} - - -def get_hatch_project_packages(data) -> dict: - hatch_data = data["tool"]["hatch"] - build_data = hatch_data.get("build", {}) if isinstance(hatch_data, dict) else {} - - force_included = build_data.get("force-include") - - if force_included: - return force_included - - return get_project_packages_from_polylith_section(data) - - -def get_project_package_includes(namespace: str, data) -> List[dict]: - if repo.is_poetry(data): - return data["tool"]["poetry"].get("packages", []) - - if repo.is_hatch(data): - includes = get_hatch_project_packages(data) - - return [transform_to_package(namespace, key) for key in includes.keys()] - - return [] +from polylith import repo, toml, workspace def get_project_name(data) -> str: @@ -61,23 +13,9 @@ def get_project_name(data) -> str: return data["tool"]["poetry"]["name"] -def get_project_dependencies(data) -> dict: - if repo.is_poetry(data): - deps = data["tool"]["poetry"].get("dependencies", []) - - items = set(deps.keys()) - else: - deps = data["project"].get("dependencies", []) - - items = {re.split(r"[\^~=!<>]", dep)[0] for dep in deps} - - return {"items": items, "source": repo.default_toml} - - @lru_cache def get_toml(path: Path) -> tomlkit.TOMLDocument: - with path.open(encoding="utf-8", errors="ignore") as f: - return tomlkit.loads(f.read()) + return toml.read_toml_document(path) def get_project_files(root: Path) -> dict: @@ -104,16 +42,16 @@ def get_toml_files(root: Path) -> List[dict]: def get_packages_for_projects(root: Path) -> List[dict]: - tomls = get_toml_files(root) + toml_files = get_toml_files(root) namespace = workspace.parser.get_namespace_from_config(root) return [ { "name": get_project_name(d["toml"]), - "packages": get_project_package_includes(namespace, d["toml"]), + "packages": toml.get_project_package_includes(namespace, d["toml"]), "path": d["path"], "type": d["type"], - "deps": get_project_dependencies(d["toml"]), + "deps": toml.get_project_dependencies(d["toml"]), } - for d in tomls + for d in toml_files ] diff --git a/components/polylith/toml/__init__.py b/components/polylith/toml/__init__.py new file mode 100644 index 00000000..579d3f6e --- /dev/null +++ b/components/polylith/toml/__init__.py @@ -0,0 +1,13 @@ +from polylith.toml.core import ( + get_project_dependencies, + get_project_package_includes, + get_project_packages_from_polylith_section, + read_toml_document, +) + +__all__ = [ + "get_project_dependencies", + "get_project_package_includes", + "get_project_packages_from_polylith_section", + "read_toml_document", +] diff --git a/components/polylith/toml/core.py b/components/polylith/toml/core.py new file mode 100644 index 00000000..e09f0544 --- /dev/null +++ b/components/polylith/toml/core.py @@ -0,0 +1,67 @@ +import re +from pathlib import Path +from typing import List + +import tomlkit +from polylith import repo + + +def transform_to_package(namespace: str, include: str) -> dict: + path, _separator, brick = str.partition(include, f"/{namespace}/") + + return {"include": f"{namespace}/{brick}", "from": path} + + +def get_project_packages_from_polylith_section(data) -> dict: + bricks = data["tool"].get("polylith", {}).get("bricks") + + return bricks if isinstance(bricks, dict) else {} + + +def get_hatch_project_packages(data) -> dict: + hatch_data = data["tool"]["hatch"] + build_data = hatch_data.get("build", {}) if isinstance(hatch_data, dict) else {} + + force_included = build_data.get("force-include") + + if force_included: + return force_included + + return get_project_packages_from_polylith_section(data) + + +def get_project_package_includes(namespace: str, data) -> List[dict]: + if repo.is_poetry(data): + return data["tool"]["poetry"].get("packages", []) + + if repo.is_hatch(data): + includes = get_hatch_project_packages(data) + + return [transform_to_package(namespace, key) for key in includes.keys()] + + return [] + + +def get_project_name(data) -> str: + if repo.is_pep_621_ready(data): + return data["project"]["name"] + + return data["tool"]["poetry"]["name"] + + +def get_project_dependencies(data) -> dict: + if repo.is_poetry(data): + deps = data["tool"]["poetry"].get("dependencies", []) + + items = set(deps.keys()) + else: + deps = data["project"].get("dependencies", []) + + items = {re.split(r"[\^~=!<>]", dep)[0] for dep in deps} + + return {"items": items, "source": repo.default_toml} + + +def read_toml_document(path: Path) -> tomlkit.TOMLDocument: + with path.open(encoding="utf-8", errors="ignore") as f: + return tomlkit.loads(f.read()) diff --git a/projects/hatch-bricks-build-hook/poetry.lock b/projects/hatch-bricks-build-hook/poetry.lock new file mode 100644 index 00000000..bda475ca --- /dev/null +++ b/projects/hatch-bricks-build-hook/poetry.lock @@ -0,0 +1,95 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "editables" +version = "0.5" +description = "Editable installations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "editables-0.5-py3-none-any.whl", hash = "sha256:61e5ffa82629e0d8bfe09bc44a07db3c1ab8ed1ce78a6980732870f19b5e7d4c"}, + {file = "editables-0.5.tar.gz", hash = "sha256:309627d9b5c4adc0e668d8c6fa7bac1ba7c8c5d415c2d27f60f081f8e80d1de2"}, +] + +[[package]] +name = "hatchling" +version = "1.21.0" +description = "Modern, extensible Python build backend" +optional = false +python-versions = ">=3.8" +files = [ + {file = "hatchling-1.21.0-py3-none-any.whl", hash = "sha256:b33ef0ecdee6dbfd28c21ca30df459ba1d566050d033f8b5a1d0e26e5606d26b"}, + {file = "hatchling-1.21.0.tar.gz", hash = "sha256:5c086772357a50723b825fd5da5278ac7e3697cdf7797d07541a6c90b6ff754c"}, +] + +[package.dependencies] +editables = ">=0.3" +packaging = ">=21.3" +pathspec = ">=0.10.1" +pluggy = ">=1.0.0" +tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} +trove-classifiers = "*" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "trove-classifiers" +version = "2024.1.8" +description = "Canonical source for classifiers on PyPI (pypi.org)." +optional = false +python-versions = "*" +files = [ + {file = "trove-classifiers-2024.1.8.tar.gz", hash = "sha256:6e36caf430ff6485c4b57a4c6b364a13f6a898d16b9417c6c37467e59c14b05a"}, + {file = "trove_classifiers-2024.1.8-py3-none-any.whl", hash = "sha256:3c1ff4deb10149c7e39ede6e5bbc107def64362ef1ee7590ec98d71fb92f1b6a"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8.1" +content-hash = "bfd8ba737772a1d306e9f0a50eb38c85865939b6386f9fc3016f1f55e1cf3a1f" diff --git a/projects/hatch-bricks-build-hook/pyproject.toml b/projects/hatch-bricks-build-hook/pyproject.toml index 747591ee..7e8288b4 100644 --- a/projects/hatch-bricks-build-hook/pyproject.toml +++ b/projects/hatch-bricks-build-hook/pyproject.toml @@ -7,14 +7,10 @@ license = "MIT" packages = [ {include = "polylith/hatch_hooks", from = "../../bases"}, - {include = "polylith/files",from = "../../components"}, - {include = "polylith/readme",from = "../../components"}, - {include = "polylith/dirs",from = "../../components"}, {include = "polylith/repo",from = "../../components"}, {include = "polylith/parsing",from = "../../components"}, - {include = "polylith/workspace",from = "../../components"}, - {include = "polylith/project",from = "../../components"}, - {include = "polylith/development",from = "../../components"}, + {include = "polylith/hatch",from = "../../components"}, + {include = "polylith/toml",from = "../../components"}, ] [tool.poetry.dependencies] @@ -22,7 +18,7 @@ python = "^3.8.1" hatchling = "^1.21.0" [project.entry-points.hatch] -polylith-bricks = "hatch_hooks.bricks.hooks" +polylith-bricks = "hatch_hooks.hooks" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/projects/poetry_polylith_plugin/pyproject.toml b/projects/poetry_polylith_plugin/pyproject.toml index b55b20ae..3f4f2bd0 100644 --- a/projects/poetry_polylith_plugin/pyproject.toml +++ b/projects/poetry_polylith_plugin/pyproject.toml @@ -30,6 +30,7 @@ packages = [ {include = "polylith/reporting",from = "../../components"}, {include = "polylith/sync",from = "../../components"}, {include = "polylith/test",from = "../../components"}, + {include = "polylith/toml",from = "../../components"}, {include = "polylith/workspace",from = "../../components"}, ] diff --git a/projects/polylith-cli/pyproject.toml b/projects/polylith-cli/pyproject.toml index fd334836..27ef1b37 100644 --- a/projects/polylith-cli/pyproject.toml +++ b/projects/polylith-cli/pyproject.toml @@ -30,6 +30,7 @@ packages = [ {include = "polylith/sync",from = "../../components"}, {include = "polylith/test",from = "../../components"}, {include = "polylith/workspace",from = "../../components"}, + {include = "polylith/toml",from = "../../components"}, ] [tool.poetry.dependencies] diff --git a/pyproject.toml b/pyproject.toml index 9a74313d..59879341 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ packages = [ {include = "polylith/dirs",from = "components"}, {include = "polylith/distributions",from = "components"}, {include = "polylith/files",from = "components"}, + {include = "polylith/hatch",from = "components"}, {include = "polylith/imports",from = "components"}, {include = "polylith/info",from = "components"}, {include = "polylith/interface",from = "components"}, @@ -31,6 +32,7 @@ packages = [ {include = "polylith/reporting",from = "components"}, {include = "polylith/sync",from = "components"}, {include = "polylith/test",from = "components"}, + {include = "polylith/toml",from = "components"}, {include = "polylith/workspace",from = "components"}, {include = "development"}, ] diff --git a/test/components/polylith/hatch/__init__.py b/test/components/polylith/hatch/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/components/polylith/hatch/test_core.py b/test/components/polylith/hatch/test_core.py new file mode 100644 index 00000000..e5dacb29 --- /dev/null +++ b/test/components/polylith/hatch/test_core.py @@ -0,0 +1,5 @@ +from polylith.hatch.hooks import bricks + + +def test_sample(): + assert bricks is not None diff --git a/test/components/polylith/toml/__init__.py b/test/components/polylith/toml/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/components/polylith/project/test_project_get.py b/test/components/polylith/toml/test_core.py similarity index 82% rename from test/components/polylith/project/test_project_get.py rename to test/components/polylith/toml/test_core.py index 76b627f8..be83f880 100644 --- a/test/components/polylith/project/test_project_get.py +++ b/test/components/polylith/toml/test_core.py @@ -1,5 +1,5 @@ import tomlkit -from polylith import project +from polylith import toml namespace = "unittest" @@ -44,7 +44,7 @@ def test_get_poetry_package_includes(): data = tomlkit.loads(poetry_toml) - res = project.get.get_project_package_includes(namespace, data) + res = toml.get_project_package_includes(namespace, data) assert res == expected @@ -52,7 +52,7 @@ def test_get_poetry_package_includes(): def test_get_hatch_package_includes(): data = tomlkit.loads(hatch_toml) - res = project.get.get_project_package_includes(namespace, data) + res = toml.get_project_package_includes(namespace, data) assert res == expected @@ -60,7 +60,7 @@ def test_get_hatch_package_includes(): def test_get_hatch_package_includes_in_build_hook(): data = tomlkit.loads(hatch_toml_alternative) - res = project.get.get_project_package_includes(namespace, data) + res = toml.get_project_package_includes(namespace, data) assert res == expected @@ -68,6 +68,6 @@ def test_get_hatch_package_includes_in_build_hook(): def test_get_hatch_package_includes_from_default_when_in_both(): data = tomlkit.loads(hatch_toml_combined) - res = project.get.get_project_package_includes(namespace, data) + res = toml.get_project_package_includes(namespace, data) assert res == expected From bbd8d1749a3d2eadcc12c552ca8443fc8af0d5c7 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 12:35:05 +0100 Subject: [PATCH 09/31] refactor: extract into new toml brick, rearrange hatch build hook project --- components/polylith/hatch/hooks/__init__.py | 3 -- components/polylith/hatch/hooks/bricks.py | 46 +++++---------------- 2 files changed, 10 insertions(+), 39 deletions(-) diff --git a/components/polylith/hatch/hooks/__init__.py b/components/polylith/hatch/hooks/__init__.py index b8a46187..e69de29b 100644 --- a/components/polylith/hatch/hooks/__init__.py +++ b/components/polylith/hatch/hooks/__init__.py @@ -1,3 +0,0 @@ -from polylith.hatch.hooks import bricks - -__all__ = ["bricks"] diff --git a/components/polylith/hatch/hooks/bricks.py b/components/polylith/hatch/hooks/bricks.py index 5069704e..879d5869 100644 --- a/components/polylith/hatch/hooks/bricks.py +++ b/components/polylith/hatch/hooks/bricks.py @@ -3,37 +3,8 @@ from typing import Any, Dict from hatchling.builders.hooks.plugin.interface import BuildHookInterface -from polylith import toml, parsing, repo - - -def get_work_dir(config: dict) -> Path: - work_dir = config.get("work_dir", ".tmp") - - return Path(work_dir) - - -def parse_namespace(bricks: dict) -> str: - namespaces = parsing.parse_brick_namespace_from_path(bricks) - - return next(namespace for namespace in namespaces) - - -def copy_brick(source: str, brick: str, tmp_dir: Path) -> Path: - destination = Path(tmp_dir / brick).as_posix() - - return parsing.copy_brick(source, destination) - - -def rewrite_modules(path: Path, ns: str, top_ns: str) -> None: - modules = path.glob("**/*.py") - - for module in modules: - was_rewritten = parsing.rewrite_module(module, ns, top_ns) - - if was_rewritten: - print( - f"Updated {module.parent.name}/{module.name} with new top namespace for local imports." - ) +from polylith import repo, toml +from polylith.hatch import core class PolylithBricksHook(BuildHookInterface): @@ -41,7 +12,7 @@ class PolylithBricksHook(BuildHookInterface): def initialize(self, _version: str, build_data: Dict[str, Any]) -> None: top_ns = self.config.get("top_namespace") - work_dir = get_work_dir(self.config) + work_dir = core.get_work_dir(self.config) pyproject = Path(f"{self.root}/{repo.default_toml}") data = toml.read_toml_document(pyproject) @@ -54,17 +25,20 @@ def initialize(self, _version: str, build_data: Dict[str, Any]) -> None: build_data["force_include"] = bricks return - ns = parse_namespace(bricks) + ns = core.parse_namespace(bricks) for source, brick in bricks.items(): - path = copy_brick(source, brick, work_dir) - rewrite_modules(path, ns, top_ns) + path = core.copy_brick(source, brick, work_dir) + rewritten_bricks = core.rewrite_modules(path, ns, top_ns) + + for item in rewritten_bricks: + print(f"Updated {item} with new top namespace for local imports.") key = work_dir.as_posix() build_data["force_include"][key] = top_ns def finalize(self, *args, **kwargs) -> None: - work_dir = get_work_dir(self.config) + work_dir = core.get_work_dir(self.config) if not work_dir.exists() or not work_dir.is_dir(): return From c51373c20e73a5ac015e0cedd3e7dacef08f63d3 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 12:35:21 +0100 Subject: [PATCH 10/31] refactor: extract into new toml brick, rearrange hatch build hook project --- components/polylith/hatch/__init__.py | 3 ++ components/polylith/hatch/core.py | 41 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 components/polylith/hatch/__init__.py create mode 100644 components/polylith/hatch/core.py diff --git a/components/polylith/hatch/__init__.py b/components/polylith/hatch/__init__.py new file mode 100644 index 00000000..b88f76b6 --- /dev/null +++ b/components/polylith/hatch/__init__.py @@ -0,0 +1,3 @@ +from polylith.hatch import hooks + +__all__ = ["hooks"] diff --git a/components/polylith/hatch/core.py b/components/polylith/hatch/core.py new file mode 100644 index 00000000..64f5414e --- /dev/null +++ b/components/polylith/hatch/core.py @@ -0,0 +1,41 @@ +from pathlib import Path +from typing import List, Union + +from polylith import parsing + + +def get_work_dir(config: dict) -> Path: + work_dir = config.get("work_dir", ".tmp") + + return Path(work_dir) + + +def parse_namespace(bricks: dict) -> str: + namespaces = parsing.parse_brick_namespace_from_path(bricks) + + return next(namespace for namespace in namespaces) + + +def copy_brick(source: str, brick: str, tmp_dir: Path) -> Path: + destination = Path(tmp_dir / brick).as_posix() + + return parsing.copy_brick(source, destination) + + +def rewrite_module(module: Path, ns: str, top_ns: str) -> Union[str, None]: + was_rewritten = parsing.rewrite_module(module, ns, top_ns) + + return f"{module.parent.name}/{module.name}" if was_rewritten else None + + +def rewrite_modules(path: Path, ns: str, top_ns: str) -> List[str]: + """Rewrite modules in bricks with new top namespace + + returns a list of bricks that was rewritten + """ + + modules = path.glob("**/*.py") + + res = [rewrite_module(module, ns, top_ns) for module in modules] + + return [r for r in res if r] From 9a158782134f41a2a98d07a1139b8cd7e445748f Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 15:25:00 +0100 Subject: [PATCH 11/31] fix: check build system (i.e. poetry or hatch) by looking in the build-backend config --- components/polylith/repo/repo.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/polylith/repo/repo.py b/components/polylith/repo/repo.py index 7c2ddc7c..8c0cc5a7 100644 --- a/components/polylith/repo/repo.py +++ b/components/polylith/repo/repo.py @@ -57,12 +57,18 @@ def get_workspace_root(cwd: Path) -> Path: return root +def has_build_requires(pyproject: dict, value: str) -> bool: + backend = pyproject["build-system"]["build-backend"] + + return value in backend + + def is_poetry(pyproject: dict) -> bool: - return pyproject.get("tool", {}).get("poetry") is not None + return has_build_requires(pyproject, "poetry") def is_hatch(pyproject: dict) -> bool: - return pyproject.get("tool", {}).get("hatch") is not None + return has_build_requires(pyproject, "hatchling") def is_pep_621_ready(pyproject: dict) -> bool: From a8af736c0652366a918d1bb643951765c9562dbd Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 15:31:30 +0100 Subject: [PATCH 12/31] wip(hatch build hook): add project --- projects/hatch-bricks-build-hook/README.md | 2 + .../hatch-bricks-build-hook/pyproject.toml | 38 +++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 projects/hatch-bricks-build-hook/README.md diff --git a/projects/hatch-bricks-build-hook/README.md b/projects/hatch-bricks-build-hook/README.md new file mode 100644 index 00000000..7143f146 --- /dev/null +++ b/projects/hatch-bricks-build-hook/README.md @@ -0,0 +1,2 @@ +# Hatch Polylith Bricks Build Hook + diff --git a/projects/hatch-bricks-build-hook/pyproject.toml b/projects/hatch-bricks-build-hook/pyproject.toml index 7e8288b4..33fc73c1 100644 --- a/projects/hatch-bricks-build-hook/pyproject.toml +++ b/projects/hatch-bricks-build-hook/pyproject.toml @@ -1,25 +1,31 @@ -[tool.poetry] -name = "hatch-bricks-build-hook" +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "hatch-polylith-bricks" version = "0.1.0" description = "Hatch build hook plugin for Polylith bricks" -authors = ['David Vujic'] -license = "MIT" +readme = "README.md" +authors = [{ name = "David Vujic" }] + +requires-python = ">=3.8" -packages = [ - {include = "polylith/hatch_hooks", from = "../../bases"}, - {include = "polylith/repo",from = "../../components"}, - {include = "polylith/parsing",from = "../../components"}, - {include = "polylith/hatch",from = "../../components"}, - {include = "polylith/toml",from = "../../components"}, +dependencies = [ + "hatchling", ] -[tool.poetry.dependencies] -python = "^3.8.1" -hatchling = "^1.21.0" +classifiers = [ + "Framework :: Hatch", + "License :: OSI Approved :: MIT License", +] [project.entry-points.hatch] polylith-bricks = "hatch_hooks.hooks" -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +[tool.polylith.bricks] +"../../bases/polylith/hatch_hooks" = "polylith/hatch_hooks" +"../../components/polylith/repo" = "polylith/repo" +"../../components/polylith/parsing" = "polylith/parsing" +"../../components/polylith/hatch" = "polylith/hatch" +"../../components/polylith/toml" = "polylith/toml" \ No newline at end of file From 3d9223eb80e34351294b02a66253a493c8bb4794 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 15:32:49 +0100 Subject: [PATCH 13/31] fix(hatch hook): rename project --- .../{hatch-bricks-build-hook => hatch-polylith-bricks}/README.md | 0 .../poetry.lock | 0 .../pyproject.toml | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename projects/{hatch-bricks-build-hook => hatch-polylith-bricks}/README.md (100%) rename projects/{hatch-bricks-build-hook => hatch-polylith-bricks}/poetry.lock (100%) rename projects/{hatch-bricks-build-hook => hatch-polylith-bricks}/pyproject.toml (100%) diff --git a/projects/hatch-bricks-build-hook/README.md b/projects/hatch-polylith-bricks/README.md similarity index 100% rename from projects/hatch-bricks-build-hook/README.md rename to projects/hatch-polylith-bricks/README.md diff --git a/projects/hatch-bricks-build-hook/poetry.lock b/projects/hatch-polylith-bricks/poetry.lock similarity index 100% rename from projects/hatch-bricks-build-hook/poetry.lock rename to projects/hatch-polylith-bricks/poetry.lock diff --git a/projects/hatch-bricks-build-hook/pyproject.toml b/projects/hatch-polylith-bricks/pyproject.toml similarity index 100% rename from projects/hatch-bricks-build-hook/pyproject.toml rename to projects/hatch-polylith-bricks/pyproject.toml From ff84268900432c999fa9cb25ca6b739a1ba1e799 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 15:35:50 +0100 Subject: [PATCH 14/31] refactor: rename hatch and cli project folders --- .../{hatch-polylith-bricks => hatch_polylith_bricks}/README.md | 0 .../{hatch-polylith-bricks => hatch_polylith_bricks}/poetry.lock | 0 .../pyproject.toml | 0 projects/{polylith-cli => polylith_cli}/README.md | 0 projects/{polylith-cli => polylith_cli}/poetry.lock | 0 projects/{polylith-cli => polylith_cli}/pyproject.toml | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename projects/{hatch-polylith-bricks => hatch_polylith_bricks}/README.md (100%) rename projects/{hatch-polylith-bricks => hatch_polylith_bricks}/poetry.lock (100%) rename projects/{hatch-polylith-bricks => hatch_polylith_bricks}/pyproject.toml (100%) rename projects/{polylith-cli => polylith_cli}/README.md (100%) rename projects/{polylith-cli => polylith_cli}/poetry.lock (100%) rename projects/{polylith-cli => polylith_cli}/pyproject.toml (100%) diff --git a/projects/hatch-polylith-bricks/README.md b/projects/hatch_polylith_bricks/README.md similarity index 100% rename from projects/hatch-polylith-bricks/README.md rename to projects/hatch_polylith_bricks/README.md diff --git a/projects/hatch-polylith-bricks/poetry.lock b/projects/hatch_polylith_bricks/poetry.lock similarity index 100% rename from projects/hatch-polylith-bricks/poetry.lock rename to projects/hatch_polylith_bricks/poetry.lock diff --git a/projects/hatch-polylith-bricks/pyproject.toml b/projects/hatch_polylith_bricks/pyproject.toml similarity index 100% rename from projects/hatch-polylith-bricks/pyproject.toml rename to projects/hatch_polylith_bricks/pyproject.toml diff --git a/projects/polylith-cli/README.md b/projects/polylith_cli/README.md similarity index 100% rename from projects/polylith-cli/README.md rename to projects/polylith_cli/README.md diff --git a/projects/polylith-cli/poetry.lock b/projects/polylith_cli/poetry.lock similarity index 100% rename from projects/polylith-cli/poetry.lock rename to projects/polylith_cli/poetry.lock diff --git a/projects/polylith-cli/pyproject.toml b/projects/polylith_cli/pyproject.toml similarity index 100% rename from projects/polylith-cli/pyproject.toml rename to projects/polylith_cli/pyproject.toml From 67dfa24f21d7b9430dea9c7e02b2110c5800787d Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 15:47:29 +0100 Subject: [PATCH 15/31] fix: check build system (i.e. poetry or hatch) by looking in the build-backend config --- components/polylith/repo/repo.py | 2 +- test/components/polylith/repo/test_repo.py | 2 +- test/components/polylith/sync/test_update.py | 16 ++++++++++++++++ test/components/polylith/toml/test_core.py | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/components/polylith/repo/repo.py b/components/polylith/repo/repo.py index 8c0cc5a7..08c30ca0 100644 --- a/components/polylith/repo/repo.py +++ b/components/polylith/repo/repo.py @@ -58,7 +58,7 @@ def get_workspace_root(cwd: Path) -> Path: def has_build_requires(pyproject: dict, value: str) -> bool: - backend = pyproject["build-system"]["build-backend"] + backend = pyproject.get("build-system", {}).get("build-backend", {}) return value in backend diff --git a/test/components/polylith/repo/test_repo.py b/test/components/polylith/repo/test_repo.py index cb1cc277..251571d5 100644 --- a/test/components/polylith/repo/test_repo.py +++ b/test/components/polylith/repo/test_repo.py @@ -2,7 +2,7 @@ def test_is_pep_621_ready(): - poetry_section = {"tool": {"poetry": {}}} + poetry_section = {"build-system": {"build-backend": "poetry.core.masonry.api"}} project_section = {"project": {"name": "hello world"}} both = {**poetry_section, **project_section} diff --git a/test/components/polylith/sync/test_update.py b/test/components/polylith/sync/test_update.py index f190682f..7017e78d 100644 --- a/test/components/polylith/sync/test_update.py +++ b/test/components/polylith/sync/test_update.py @@ -76,6 +76,10 @@ def test_generate_updated_poetry_project(): """\ [tool.poetry] packages = [{include = "hello/first", from = "bases"}] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" """ ) @@ -89,6 +93,10 @@ def test_generate_updated_poetry_project(): def test_generate_updated_hatch_project(): data = tomlkit.parse( """\ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + [tool.hatch.build.force-include] "bases/hello/first" = "hello/first" """ @@ -104,6 +112,10 @@ def test_generate_updated_hatch_project(): def test_generate_updated_hatch_project_with_missing_build_config(): data = tomlkit.parse( """\ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + [tool.hatch] hello = "world" """ @@ -119,6 +131,10 @@ def test_generate_updated_hatch_project_with_missing_build_config(): def test_generate_updated_hatch_project_with_missing_force_include_config(): data = tomlkit.parse( """\ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + [tool.hatch.build] hello = "world" """ diff --git a/test/components/polylith/toml/test_core.py b/test/components/polylith/toml/test_core.py index be83f880..29d4e1c8 100644 --- a/test/components/polylith/toml/test_core.py +++ b/test/components/polylith/toml/test_core.py @@ -9,15 +9,27 @@ {include = "unittest/one",from = "../../bases"}, {include = "unittest/two",from = "../../components"} ] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" """ hatch_toml = """\ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + [tool.hatch.build.force-include] "../../bases/unittest/one" = "unittest/one" "../../components/unittest/two" = "unittest/two" """ hatch_toml_alternative = """\ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + [tool.hatch.build] something = "something" @@ -27,6 +39,10 @@ """ hatch_toml_combined = """\ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + [tool.hatch.build.force-include] "../../bases/unittest/one" = "unittest/one" "../../components/unittest/two" = "unittest/two" From 07bba5b5db64bad273d1957cb46ea296e23b8a50 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 16:06:31 +0100 Subject: [PATCH 16/31] remove poetry.lock file --- projects/hatch_polylith_bricks/poetry.lock | 95 ---------------------- 1 file changed, 95 deletions(-) delete mode 100644 projects/hatch_polylith_bricks/poetry.lock diff --git a/projects/hatch_polylith_bricks/poetry.lock b/projects/hatch_polylith_bricks/poetry.lock deleted file mode 100644 index bda475ca..00000000 --- a/projects/hatch_polylith_bricks/poetry.lock +++ /dev/null @@ -1,95 +0,0 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. - -[[package]] -name = "editables" -version = "0.5" -description = "Editable installations" -optional = false -python-versions = ">=3.7" -files = [ - {file = "editables-0.5-py3-none-any.whl", hash = "sha256:61e5ffa82629e0d8bfe09bc44a07db3c1ab8ed1ce78a6980732870f19b5e7d4c"}, - {file = "editables-0.5.tar.gz", hash = "sha256:309627d9b5c4adc0e668d8c6fa7bac1ba7c8c5d415c2d27f60f081f8e80d1de2"}, -] - -[[package]] -name = "hatchling" -version = "1.21.0" -description = "Modern, extensible Python build backend" -optional = false -python-versions = ">=3.8" -files = [ - {file = "hatchling-1.21.0-py3-none-any.whl", hash = "sha256:b33ef0ecdee6dbfd28c21ca30df459ba1d566050d033f8b5a1d0e26e5606d26b"}, - {file = "hatchling-1.21.0.tar.gz", hash = "sha256:5c086772357a50723b825fd5da5278ac7e3697cdf7797d07541a6c90b6ff754c"}, -] - -[package.dependencies] -editables = ">=0.3" -packaging = ">=21.3" -pathspec = ">=0.10.1" -pluggy = ">=1.0.0" -tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} -trove-classifiers = "*" - -[[package]] -name = "packaging" -version = "23.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "pluggy" -version = "1.3.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "trove-classifiers" -version = "2024.1.8" -description = "Canonical source for classifiers on PyPI (pypi.org)." -optional = false -python-versions = "*" -files = [ - {file = "trove-classifiers-2024.1.8.tar.gz", hash = "sha256:6e36caf430ff6485c4b57a4c6b364a13f6a898d16b9417c6c37467e59c14b05a"}, - {file = "trove_classifiers-2024.1.8-py3-none-any.whl", hash = "sha256:3c1ff4deb10149c7e39ede6e5bbc107def64362ef1ee7590ec98d71fb92f1b6a"}, -] - -[metadata] -lock-version = "2.0" -python-versions = "^3.8.1" -content-hash = "bfd8ba737772a1d306e9f0a50eb38c85865939b6386f9fc3016f1f55e1cf3a1f" From 83f94b1de147c87ce1818cb4aef6127c0ae102ea Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 16:07:05 +0100 Subject: [PATCH 17/31] fix(hatch hook): proper entry point --- projects/hatch_polylith_bricks/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/hatch_polylith_bricks/pyproject.toml b/projects/hatch_polylith_bricks/pyproject.toml index 33fc73c1..1d03d66b 100644 --- a/projects/hatch_polylith_bricks/pyproject.toml +++ b/projects/hatch_polylith_bricks/pyproject.toml @@ -21,7 +21,7 @@ classifiers = [ ] [project.entry-points.hatch] -polylith-bricks = "hatch_hooks.hooks" +polylith-bricks = "polylith.hatch_hooks.hooks" [tool.polylith.bricks] "../../bases/polylith/hatch_hooks" = "polylith/hatch_hooks" From 002235ee16420606f230e2cfa38bcd778d48bcaa Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 17:10:36 +0100 Subject: [PATCH 18/31] fix(hatch): use Poetry toml format, and the plugin field to set a compatible entry point --- projects/hatch_polylith_bricks/pyproject.toml | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/projects/hatch_polylith_bricks/pyproject.toml b/projects/hatch_polylith_bricks/pyproject.toml index 1d03d66b..79127638 100644 --- a/projects/hatch_polylith_bricks/pyproject.toml +++ b/projects/hatch_polylith_bricks/pyproject.toml @@ -1,31 +1,30 @@ -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[project] +[tool.poetry] name = "hatch-polylith-bricks" version = "0.1.0" description = "Hatch build hook plugin for Polylith bricks" readme = "README.md" -authors = [{ name = "David Vujic" }] - -requires-python = ">=3.8" +authors = ['David Vujic'] +license = "MIT" -dependencies = [ - "hatchling", +packages = [ + {include = "polylith/hatch_hooks", from = "../../bases"}, + {include = "polylith/repo",from = "../../components"}, + {include = "polylith/parsing",from = "../../components"}, + {include = "polylith/hatch",from = "../../components"}, + {include = "polylith/toml",from = "../../components"}, ] classifiers = [ "Framework :: Hatch", - "License :: OSI Approved :: MIT License", ] -[project.entry-points.hatch] +[tool.poetry.dependencies] +python = "^3.8.1" +hatchling = "^1.21.0" + +[tool.poetry.plugins.hatch] polylith-bricks = "polylith.hatch_hooks.hooks" -[tool.polylith.bricks] -"../../bases/polylith/hatch_hooks" = "polylith/hatch_hooks" -"../../components/polylith/repo" = "polylith/repo" -"../../components/polylith/parsing" = "polylith/parsing" -"../../components/polylith/hatch" = "polylith/hatch" -"../../components/polylith/toml" = "polylith/toml" \ No newline at end of file +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file From 36612de30c01a973695290dc484e089114ff4be0 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 17:10:55 +0100 Subject: [PATCH 19/31] dev(hatch): add lock file --- projects/hatch_polylith_bricks/poetry.lock | 95 ++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 projects/hatch_polylith_bricks/poetry.lock diff --git a/projects/hatch_polylith_bricks/poetry.lock b/projects/hatch_polylith_bricks/poetry.lock new file mode 100644 index 00000000..bda475ca --- /dev/null +++ b/projects/hatch_polylith_bricks/poetry.lock @@ -0,0 +1,95 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "editables" +version = "0.5" +description = "Editable installations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "editables-0.5-py3-none-any.whl", hash = "sha256:61e5ffa82629e0d8bfe09bc44a07db3c1ab8ed1ce78a6980732870f19b5e7d4c"}, + {file = "editables-0.5.tar.gz", hash = "sha256:309627d9b5c4adc0e668d8c6fa7bac1ba7c8c5d415c2d27f60f081f8e80d1de2"}, +] + +[[package]] +name = "hatchling" +version = "1.21.0" +description = "Modern, extensible Python build backend" +optional = false +python-versions = ">=3.8" +files = [ + {file = "hatchling-1.21.0-py3-none-any.whl", hash = "sha256:b33ef0ecdee6dbfd28c21ca30df459ba1d566050d033f8b5a1d0e26e5606d26b"}, + {file = "hatchling-1.21.0.tar.gz", hash = "sha256:5c086772357a50723b825fd5da5278ac7e3697cdf7797d07541a6c90b6ff754c"}, +] + +[package.dependencies] +editables = ">=0.3" +packaging = ">=21.3" +pathspec = ">=0.10.1" +pluggy = ">=1.0.0" +tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} +trove-classifiers = "*" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "trove-classifiers" +version = "2024.1.8" +description = "Canonical source for classifiers on PyPI (pypi.org)." +optional = false +python-versions = "*" +files = [ + {file = "trove-classifiers-2024.1.8.tar.gz", hash = "sha256:6e36caf430ff6485c4b57a4c6b364a13f6a898d16b9417c6c37467e59c14b05a"}, + {file = "trove_classifiers-2024.1.8-py3-none-any.whl", hash = "sha256:3c1ff4deb10149c7e39ede6e5bbc107def64362ef1ee7590ec98d71fb92f1b6a"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8.1" +content-hash = "bfd8ba737772a1d306e9f0a50eb38c85865939b6386f9fc3016f1f55e1cf3a1f" From a43cb8dd743d391fff4838e3b354db01a4445041 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sat, 20 Jan 2024 17:35:52 +0100 Subject: [PATCH 20/31] fixes --- components/polylith/hatch/core.py | 2 +- projects/hatch_polylith_bricks/pyproject.toml | 4 ++-- projects/polylith_cli/pyproject.toml | 2 +- test/components/polylith/hatch/test_core.py | 13 ++++++++++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/components/polylith/hatch/core.py b/components/polylith/hatch/core.py index 64f5414e..9f003fe4 100644 --- a/components/polylith/hatch/core.py +++ b/components/polylith/hatch/core.py @@ -5,7 +5,7 @@ def get_work_dir(config: dict) -> Path: - work_dir = config.get("work_dir", ".tmp") + work_dir = config.get("work_dir", ".polylith_tmp") return Path(work_dir) diff --git a/projects/hatch_polylith_bricks/pyproject.toml b/projects/hatch_polylith_bricks/pyproject.toml index 79127638..c298b390 100644 --- a/projects/hatch_polylith_bricks/pyproject.toml +++ b/projects/hatch_polylith_bricks/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "hatch-polylith-bricks" -version = "0.1.0" +version = "0.0.1" description = "Hatch build hook plugin for Polylith bricks" readme = "README.md" authors = ['David Vujic'] @@ -27,4 +27,4 @@ polylith-bricks = "polylith.hatch_hooks.hooks" [build-system] requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" \ No newline at end of file +build-backend = "poetry.core.masonry.api" diff --git a/projects/polylith_cli/pyproject.toml b/projects/polylith_cli/pyproject.toml index 27ef1b37..898be268 100644 --- a/projects/polylith_cli/pyproject.toml +++ b/projects/polylith_cli/pyproject.toml @@ -29,8 +29,8 @@ packages = [ {include = "polylith/reporting",from = "../../components"}, {include = "polylith/sync",from = "../../components"}, {include = "polylith/test",from = "../../components"}, - {include = "polylith/workspace",from = "../../components"}, {include = "polylith/toml",from = "../../components"}, + {include = "polylith/workspace",from = "../../components"}, ] [tool.poetry.dependencies] diff --git a/test/components/polylith/hatch/test_core.py b/test/components/polylith/hatch/test_core.py index e5dacb29..0e71ac9f 100644 --- a/test/components/polylith/hatch/test_core.py +++ b/test/components/polylith/hatch/test_core.py @@ -1,5 +1,12 @@ -from polylith.hatch.hooks import bricks +from polylith.hatch import core -def test_sample(): - assert bricks is not None +def test_parse_namespace(): + expected = "unittest" + + bricks = { + f"../../bases/{expected}/one": f"{expected}/one", + f"../../components/{expected}/two": f"{expected}/two", + } + + assert core.parse_namespace(bricks) == expected From 914fa4ad1f848fd7a66429535dc3c36dc01ef09d Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:45:24 +0100 Subject: [PATCH 21/31] wip(docs): add docs about the Hatch build hook --- components/polylith/hatch/core.py | 2 +- components/polylith/hatch/hooks/bricks.py | 2 +- projects/hatch_polylith_bricks/README.md | 86 ++++++++++++++++++- projects/hatch_polylith_bricks/pyproject.toml | 4 +- 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/components/polylith/hatch/core.py b/components/polylith/hatch/core.py index 9f003fe4..e7f0114c 100644 --- a/components/polylith/hatch/core.py +++ b/components/polylith/hatch/core.py @@ -5,7 +5,7 @@ def get_work_dir(config: dict) -> Path: - work_dir = config.get("work_dir", ".polylith_tmp") + work_dir = config.get("work-dir", ".polylith_tmp") return Path(work_dir) diff --git a/components/polylith/hatch/hooks/bricks.py b/components/polylith/hatch/hooks/bricks.py index 879d5869..cae404ac 100644 --- a/components/polylith/hatch/hooks/bricks.py +++ b/components/polylith/hatch/hooks/bricks.py @@ -11,7 +11,7 @@ class PolylithBricksHook(BuildHookInterface): PLUGIN_NAME = "polylith-bricks" def initialize(self, _version: str, build_data: Dict[str, Any]) -> None: - top_ns = self.config.get("top_namespace") + top_ns = self.config.get("top-namespace") work_dir = core.get_work_dir(self.config) pyproject = Path(f"{self.root}/{repo.default_toml}") diff --git a/projects/hatch_polylith_bricks/README.md b/projects/hatch_polylith_bricks/README.md index 7143f146..6e43460d 100644 --- a/projects/hatch_polylith_bricks/README.md +++ b/projects/hatch_polylith_bricks/README.md @@ -1,2 +1,86 @@ -# Hatch Polylith Bricks Build Hook +# Hatch Build Hook for Polylith +A plugin for [Hatch](https://github.com/pypa/hatch) and the Polylith Architecture. + +This build hook will look for Polylith `bricks` in `pyproject.toml` and __optionally__ re-write the imports made in the actual source code. + +## Installation +``` toml +[build-system] +requires = ["hatchling", "hatch-polylith-bricks"] +build-backend = "hatchling.build" +``` + +## But why re-write code? +Building libraries is supported in [the Python tools for the Polylith Architecture](https://davidvujic.github.io/python-polylith-docs), +but you will need to consider that code will share the same top namespace with any other library built from the same monorepo. + +This can be a problem when more than one of your libraries are installed into the same virtual environment. +Python libraries by default are installed in a "flat" folder structure, two libraries with the same top namespace will collide. + +The Solution: add a custom top namespace during packaging of the library with Hatch and this build hook plugin. + +##### How is this done? +The code in this repo uses __AST__ (Abstract Syntax Tree) parsing to modify source code. +The Python built-in `ast` module is used to parse and un-parse Python code. + + +### What's the output from this plugin? +#### The Default, without any custom namespace in the configuration + +No changes in the code, building and packaging as-is. + +```shell +my_namespace/ + /my_package + __init__.py + my_module.py +``` + +#### With a Top Namespace configuration + +``` toml +[tool.hatch.build.hooks.polylith-bricks] +top-namespace = "my_custom_namespace" +``` + +```shell +my_custom_namespace/ + my_namespace/ + /my_package + __init__.py + my_module.py +``` + +Before: +```python +from my_namespace.my_package import my_function +``` + +After: +```python +from my_custom_namespace.my_namespace.my_package import my_function +``` + +## Usage + +Now you'll need to configure the build scripts you want to run. This is done by adding +an array of scripts to the `tool.hatch.build.hooks.build-scripts.scripts` key in your +`pyproject.toml` file. Each script is configured with the following keys: + +| Key | Default | Description | +| --- | ------- | ----------- | +| `work-dir` | `".polylith_tmp"` | The temporary working directory for copying and re-writing source code. | +| `top-namespace` | None | A custom Top Namespace for the source code. When this is set, Polylith bricks will be updated with this namespace. | + + +This Plugin expects to find Polylith Bricks in the `pyproject.toml`: + +``` toml +[tool.polylith.bricks] +"../../bases/my_namespace/my_base" = "my_namespace/my_base" +"../../components/my_namespace/my_component" = "my_namespace/my_component +``` + +## Documentation +[the Python tools for the Polylith Architecture](https://davidvujic.github.io/python-polylith-docs) diff --git a/projects/hatch_polylith_bricks/pyproject.toml b/projects/hatch_polylith_bricks/pyproject.toml index c298b390..7fa0e9ee 100644 --- a/projects/hatch_polylith_bricks/pyproject.toml +++ b/projects/hatch_polylith_bricks/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "hatch-polylith-bricks" version = "0.0.1" -description = "Hatch build hook plugin for Polylith bricks" +description = "Hatch build hook plugin for Polylith" readme = "README.md" authors = ['David Vujic'] license = "MIT" @@ -19,7 +19,7 @@ classifiers = [ ] [tool.poetry.dependencies] -python = "^3.8.1" +python = "^3.9" hatchling = "^1.21.0" [tool.poetry.plugins.hatch] From 4f8b4d8b3aa253b9c1fc0987b14c2161f76f0582 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:46:05 +0100 Subject: [PATCH 22/31] fix(hatch): update lock file with python version --- projects/hatch_polylith_bricks/poetry.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/hatch_polylith_bricks/poetry.lock b/projects/hatch_polylith_bricks/poetry.lock index bda475ca..d2119e67 100644 --- a/projects/hatch_polylith_bricks/poetry.lock +++ b/projects/hatch_polylith_bricks/poetry.lock @@ -91,5 +91,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.8.1" -content-hash = "bfd8ba737772a1d306e9f0a50eb38c85865939b6386f9fc3016f1f55e1cf3a1f" +python-versions = "^3.9" +content-hash = "27ab6a70560989a8ab2926bac614a4cfab206dfe7c1a61f167b44d5dbe3368be" From 413501154033a006b2eae2e0f5b0b4ea8d7bcde2 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:49:21 +0100 Subject: [PATCH 23/31] wip(docs): add docs about the Hatch build hook --- projects/hatch_polylith_bricks/README.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/projects/hatch_polylith_bricks/README.md b/projects/hatch_polylith_bricks/README.md index 6e43460d..d1b03485 100644 --- a/projects/hatch_polylith_bricks/README.md +++ b/projects/hatch_polylith_bricks/README.md @@ -2,7 +2,7 @@ A plugin for [Hatch](https://github.com/pypa/hatch) and the Polylith Architecture. -This build hook will look for Polylith `bricks` in `pyproject.toml` and __optionally__ re-write the imports made in the actual source code. +This build hook will look for Polylith `bricks` in `pyproject.toml` and __optionally__ re-write the imports made in the source code. ## Installation ``` toml @@ -63,15 +63,10 @@ from my_custom_namespace.my_namespace.my_package import my_function ``` ## Usage - -Now you'll need to configure the build scripts you want to run. This is done by adding -an array of scripts to the `tool.hatch.build.hooks.build-scripts.scripts` key in your -`pyproject.toml` file. Each script is configured with the following keys: - | Key | Default | Description | | --- | ------- | ----------- | -| `work-dir` | `".polylith_tmp"` | The temporary working directory for copying and re-writing source code. | -| `top-namespace` | None | A custom Top Namespace for the source code. When this is set, Polylith bricks will be updated with this namespace. | +| `work-dir` | .polylith_tmp | The temporary working directory for copying and re-writing source code. | +| `top-namespace` | None | A custom top namespace. When set, Polylith bricks will be updated using this namespace. | This Plugin expects to find Polylith Bricks in the `pyproject.toml`: From 26d0f4ec5c410eff241d5504bb66404eafaad659 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:50:24 +0100 Subject: [PATCH 24/31] wip(docs): add docs about the Hatch build hook --- projects/hatch_polylith_bricks/README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/projects/hatch_polylith_bricks/README.md b/projects/hatch_polylith_bricks/README.md index d1b03485..9cc90702 100644 --- a/projects/hatch_polylith_bricks/README.md +++ b/projects/hatch_polylith_bricks/README.md @@ -30,13 +30,6 @@ The Python built-in `ast` module is used to parse and un-parse Python code. No changes in the code, building and packaging as-is. -```shell -my_namespace/ - /my_package - __init__.py - my_module.py -``` - #### With a Top Namespace configuration ``` toml @@ -65,8 +58,8 @@ from my_custom_namespace.my_namespace.my_package import my_function ## Usage | Key | Default | Description | | --- | ------- | ----------- | -| `work-dir` | .polylith_tmp | The temporary working directory for copying and re-writing source code. | -| `top-namespace` | None | A custom top namespace. When set, Polylith bricks will be updated using this namespace. | +| work-dir | .polylith_tmp | The temporary working directory for copying and re-writing source code. | +| top-namespace | None | A custom top namespace. When set, Polylith bricks will be updated using this namespace. | This Plugin expects to find Polylith Bricks in the `pyproject.toml`: From 7b81cb0e136a526345316561147092bd1f0dc82d Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:51:47 +0100 Subject: [PATCH 25/31] wip(docs): add docs about the Hatch build hook --- projects/hatch_polylith_bricks/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/projects/hatch_polylith_bricks/README.md b/projects/hatch_polylith_bricks/README.md index 9cc90702..987d2e73 100644 --- a/projects/hatch_polylith_bricks/README.md +++ b/projects/hatch_polylith_bricks/README.md @@ -20,15 +20,14 @@ Python libraries by default are installed in a "flat" folder structure, two libr The Solution: add a custom top namespace during packaging of the library with Hatch and this build hook plugin. -##### How is this done? +## How is this done? The code in this repo uses __AST__ (Abstract Syntax Tree) parsing to modify source code. The Python built-in `ast` module is used to parse and un-parse Python code. ### What's the output from this plugin? -#### The Default, without any custom namespace in the configuration -No changes in the code, building and packaging as-is. +Without any custom namespace in the configuration: no changes in the code. Building and packaging as-is. #### With a Top Namespace configuration From f083f6a1fc2b877036f2e37f2d4f9793b4a0e6e5 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:52:18 +0100 Subject: [PATCH 26/31] wip(docs): add docs about the Hatch build hook --- projects/hatch_polylith_bricks/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/hatch_polylith_bricks/README.md b/projects/hatch_polylith_bricks/README.md index 987d2e73..954ad727 100644 --- a/projects/hatch_polylith_bricks/README.md +++ b/projects/hatch_polylith_bricks/README.md @@ -18,7 +18,7 @@ but you will need to consider that code will share the same top namespace with a This can be a problem when more than one of your libraries are installed into the same virtual environment. Python libraries by default are installed in a "flat" folder structure, two libraries with the same top namespace will collide. -The Solution: add a custom top namespace during packaging of the library with Hatch and this build hook plugin. +_A Solution_: add a custom top namespace during packaging of the library with Hatch and this build hook plugin. ## How is this done? The code in this repo uses __AST__ (Abstract Syntax Tree) parsing to modify source code. From 48df53954937d62d7a6febca80a2b503fe968953 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:56:48 +0100 Subject: [PATCH 27/31] fix(hatch): messages to stdout --- components/polylith/hatch/hooks/bricks.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/polylith/hatch/hooks/bricks.py b/components/polylith/hatch/hooks/bricks.py index cae404ac..4e1c2e82 100644 --- a/components/polylith/hatch/hooks/bricks.py +++ b/components/polylith/hatch/hooks/bricks.py @@ -15,10 +15,13 @@ def initialize(self, _version: str, build_data: Dict[str, Any]) -> None: work_dir = core.get_work_dir(self.config) pyproject = Path(f"{self.root}/{repo.default_toml}") + print(f"Using {pyproject.as_posix()}.") + data = toml.read_toml_document(pyproject) bricks = toml.get_project_packages_from_polylith_section(data) if not bricks: + print("No bricks found.") return if not top_ns: From 863088da3eafcdb4be743bc67706a09b8ef14e8c Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 10:59:14 +0100 Subject: [PATCH 28/31] fix(hatch): add to list of ignored in copy brick function --- components/polylith/parsing/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/components/polylith/parsing/core.py b/components/polylith/parsing/core.py index b16fef3b..8700d2a3 100644 --- a/components/polylith/parsing/core.py +++ b/components/polylith/parsing/core.py @@ -8,6 +8,7 @@ def copy_brick(source: str, destination: str) -> Path: "__pycache__", ".venv", ".mypy_cache", + ".pytest_cache", "node_modules", ".git", ) From 24b804f276a48438eadd3620439e2bc63cbec422 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 11:01:41 +0100 Subject: [PATCH 29/31] fix(hatch): add project metadata --- projects/hatch_polylith_bricks/pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/projects/hatch_polylith_bricks/pyproject.toml b/projects/hatch_polylith_bricks/pyproject.toml index 7fa0e9ee..677e3cf8 100644 --- a/projects/hatch_polylith_bricks/pyproject.toml +++ b/projects/hatch_polylith_bricks/pyproject.toml @@ -2,9 +2,11 @@ name = "hatch-polylith-bricks" version = "0.0.1" description = "Hatch build hook plugin for Polylith" -readme = "README.md" authors = ['David Vujic'] +homepage = "https://davidvujic.github.io/python-polylith-docs/" +repository = "https://github.com/davidvujic/python-polylith" license = "MIT" +readme = "README.md" packages = [ {include = "polylith/hatch_hooks", from = "../../bases"}, From 8abd17f75477f1b23eb37684dfc4eb0bca1a1e67 Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 11:57:25 +0100 Subject: [PATCH 30/31] bump poetry plugin to 1.14.4 --- projects/poetry_polylith_plugin/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/poetry_polylith_plugin/pyproject.toml b/projects/poetry_polylith_plugin/pyproject.toml index 3f4f2bd0..0f35ed4d 100644 --- a/projects/poetry_polylith_plugin/pyproject.toml +++ b/projects/poetry_polylith_plugin/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "poetry-polylith-plugin" -version = "1.14.3" +version = "1.14.4" description = "A Poetry plugin that adds tooling support for the Polylith Architecture" authors = ["David Vujic"] homepage = "https://davidvujic.github.io/python-polylith-docs/" From f9eca699fde5a08d52de306f901a918deadb5c6a Mon Sep 17 00:00:00 2001 From: David Vujic Date: Sun, 21 Jan 2024 11:58:51 +0100 Subject: [PATCH 31/31] bump cli to 0.5.0 --- projects/polylith_cli/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/polylith_cli/pyproject.toml b/projects/polylith_cli/pyproject.toml index 898be268..b0a15ba9 100644 --- a/projects/polylith_cli/pyproject.toml +++ b/projects/polylith_cli/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "polylith-cli" -version = "0.4.0" +version = "0.5.0" description = "Python tooling support for the Polylith Architecture" authors = ['David Vujic'] homepage = "https://davidvujic.github.io/python-polylith-docs/"