Skip to content

Commit c60e57e

Browse files
authored
Move poetry specific to component (#144)
* feat(project): add support for PEP 621 project files, along with the existing Poetry format * dev: add dev readme for local test install * bump version to 1.13.0
1 parent 4a17fc7 commit c60e57e

File tree

15 files changed

+344
-61
lines changed

15 files changed

+344
-61
lines changed

components/polylith/poetry/commands/create_project.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from pathlib import Path
2+
from typing import Union
3+
14
from cleo.helpers import option
25
from poetry.console.commands.command import Command
36
from polylith import project
@@ -6,6 +9,31 @@
69
command_name = "poly create project"
710

811

12+
pyproject_template = """\
13+
[tool.poetry]
14+
name = "{name}"
15+
version = "0.1.0"
16+
description = "{description}"
17+
authors = {authors}
18+
license = ""
19+
20+
packages = []
21+
22+
[tool.poetry.dependencies]
23+
python = "{python_version}"
24+
25+
[tool.poetry.group.dev.dependencies]
26+
27+
[build-system]
28+
requires = ["poetry-core>=1.0.0"]
29+
build-backend = "poetry.core.masonry.api"
30+
"""
31+
32+
33+
def create_project(root: Path, _ns: str, name: str, description: Union[str, None]):
34+
project.create_project(root, pyproject_template, name, description or "")
35+
36+
937
class CreateProjectCommand(Command):
1038
name = command_name
1139
description = "Creates a <comment>Polylith</> project."
@@ -22,6 +50,6 @@ class CreateProjectCommand(Command):
2250
]
2351

2452
def handle(self) -> int:
25-
create(self, project.create_project)
53+
create(self, create_project)
2654

2755
return 0

components/polylith/project/create.py

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,31 @@
11
from pathlib import Path
2-
from typing import Union
32

43
import tomlkit
54
from polylith import repo
65
from polylith.dirs import create_dir
76
from polylith.repo import projects_dir
87

9-
template = """\
10-
[tool.poetry]
11-
name = "{name}"
12-
version = "0.1.0"
13-
description = "{description}"
14-
authors = {authors}
15-
license = ""
168

17-
packages = []
18-
19-
[tool.poetry.dependencies]
20-
python = "{python_version}"
21-
22-
[tool.poetry.group.dev.dependencies]
23-
24-
[build-system]
25-
requires = ["poetry-core>=1.0.0"]
26-
build-backend = "poetry.core.masonry.api"
27-
"""
28-
29-
30-
def get_workspace_toml(path: Path) -> dict:
31-
with open(str(path / repo.default_toml), "r", errors="ignore") as f:
32-
data: dict = tomlkit.loads(f.read())
33-
34-
return data
35-
36-
37-
def create_project_toml(
38-
name: str, template: str, workspace_toml: dict, description: str
39-
) -> tomlkit.TOMLDocument:
40-
authors = workspace_toml["tool"]["poetry"]["authors"]
41-
python_version = workspace_toml["tool"]["poetry"]["dependencies"]["python"]
42-
43-
content = template.format(
44-
name=name,
45-
description=description,
46-
authors=authors,
47-
python_version=python_version,
48-
)
9+
def create_project_toml(template: str, template_data: dict) -> tomlkit.TOMLDocument:
10+
content = template.format(**template_data)
4911

5012
return tomlkit.loads(content)
5113

5214

53-
def create_project(
54-
path: Path, _namespace: str, name: str, description: Union[str, None]
55-
) -> None:
15+
def create_project(path: Path, template: str, name: str, description: str) -> None:
5616
d = create_dir(path, f"{projects_dir}/{name}")
5717

58-
workspace_toml = get_workspace_toml(path)
18+
authors = repo.get_authors(path)
19+
python_version = repo.get_python_version(path)
20+
5921
project_toml = create_project_toml(
60-
name, template, workspace_toml, description or ""
22+
template,
23+
{
24+
"name": name,
25+
"description": description,
26+
"authors": authors,
27+
"python_version": python_version,
28+
},
6129
)
6230

6331
fullpath = d / repo.default_toml

components/polylith/project/get.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@
22
from typing import List
33

44
import tomlkit
5-
from polylith.repo import default_toml
5+
from polylith import repo, workspace
66

77

8-
def get_project_package_includes(data) -> List[dict]:
8+
def transform_to_package(namespace: str, include: str) -> dict:
9+
path, _separator, brick = str.partition(include, f"/{namespace}/")
10+
11+
return {"include": f"{namespace}/{brick}", "from": path}
12+
13+
14+
def get_project_package_includes(namespace: str, data) -> List[dict]:
15+
if repo.is_pep_621_ready(data):
16+
includes = data["project"].get("includes", [])
17+
return [transform_to_package(namespace, include) for include in includes]
18+
919
return data["tool"]["poetry"].get("packages", [])
1020

1121

1222
def get_project_name(data) -> str:
23+
if repo.is_pep_621_ready(data):
24+
return data["project"]["name"]
25+
1326
return data["tool"]["poetry"]["name"]
1427

1528

@@ -19,8 +32,8 @@ def get_toml(path: Path) -> tomlkit.TOMLDocument:
1932

2033

2134
def get_project_files(root: Path) -> dict:
22-
projects = sorted(root.glob(f"projects/**/{default_toml}"))
23-
development = Path(root / default_toml)
35+
projects = sorted(root.glob(f"projects/**/{repo.default_toml}"))
36+
development = Path(root / repo.default_toml)
2437

2538
proj = {"projects": projects}
2639
dev = {"development": [development]}
@@ -43,11 +56,12 @@ def get_toml_files(root: Path) -> List[dict]:
4356

4457
def get_packages_for_projects(root: Path) -> List[dict]:
4558
tomls = get_toml_files(root)
59+
namespace = workspace.parser.get_namespace_from_config(root)
4660

4761
return [
4862
{
4963
"name": get_project_name(d["toml"]),
50-
"packages": get_project_package_includes(d["toml"]),
64+
"packages": get_project_package_includes(namespace, d["toml"]),
5165
"path": d["path"],
5266
"type": d["type"],
5367
}

components/polylith/repo/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
1+
from polylith.repo.get import get_authors, get_python_version
12
from polylith.repo.repo import (
23
bases_dir,
34
components_dir,
45
default_toml,
56
development_dir,
67
get_workspace_root,
8+
is_pep_621_ready,
79
projects_dir,
810
readme_file,
911
workspace_file,
1012
)
1113

1214
__all__ = [
15+
"get_authors",
16+
"get_python_version",
1317
"bases_dir",
1418
"components_dir",
1519
"default_toml",
1620
"development_dir",
1721
"get_workspace_root",
22+
"is_pep_621_ready",
1823
"projects_dir",
1924
"readme_file",
2025
"workspace_file",

components/polylith/repo/get.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from functools import lru_cache
2+
from pathlib import Path
3+
4+
import tomlkit
5+
from polylith.repo.repo import default_toml, is_pep_621_ready
6+
7+
8+
@lru_cache
9+
def get_pyproject_data(path: Path) -> tomlkit.TOMLDocument:
10+
with open(str(path / default_toml), "r", errors="ignore") as f:
11+
return tomlkit.loads(f.read())
12+
13+
14+
def get_metadata_section(data: dict) -> dict:
15+
return data["project"] if is_pep_621_ready(data) else data["tool"]["poetry"]
16+
17+
18+
def get_authors(path: Path) -> list:
19+
data = get_pyproject_data(path)
20+
section = get_metadata_section(data)
21+
22+
return section.get("authors", [])
23+
24+
25+
def get_python_version(path: Path) -> str:
26+
data: dict = get_pyproject_data(path)
27+
28+
if is_pep_621_ready(data):
29+
return data["project"].get("requires-python", "")
30+
31+
return data["tool"]["poetry"]["dependencies"]["python"]

components/polylith/repo/repo.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,10 @@ def get_workspace_root(cwd: Path) -> Path:
5555
)
5656

5757
return root
58+
59+
60+
def is_pep_621_ready(pyproject: dict) -> bool:
61+
if pyproject.get("tool", {}).get("poetry") is not None:
62+
return False
63+
64+
return pyproject.get("project", {}).get("name") is not None

components/polylith/sync/update.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,36 @@ def to_package(namespace: str, brick: str, brick_path: str, theme: str) -> dict:
1212
return {"include": f"{namespace}/{brick}", "from": folder}
1313

1414

15-
def generate_updated_project(data: TOMLDocument, packages: List[dict]) -> str:
15+
def copy_toml_data(data: TOMLDocument) -> dict:
1616
original = tomlkit.dumps(data)
1717
copy: dict = tomlkit.parse(original)
1818

19+
return copy
20+
21+
22+
def generate_updated_pep_621_ready_project(
23+
data: TOMLDocument, packages: List[dict]
24+
) -> str:
25+
copy = copy_toml_data(data)
26+
27+
if copy["project"].get("includes") is None:
28+
copy["project"].add("includes", [])
29+
30+
for package in packages:
31+
brick = package["include"]
32+
relative_path = package.get("from", "")
33+
include = Path(relative_path, brick).as_posix()
34+
35+
copy["project"]["includes"].append(include)
36+
37+
copy["project"]["includes"].multiline(True)
38+
39+
return tomlkit.dumps(copy)
40+
41+
42+
def generate_updated_poetry_project(data: TOMLDocument, packages: List[dict]) -> str:
43+
copy = copy_toml_data(data)
44+
1945
if copy["tool"]["poetry"].get("packages") is None:
2046
copy["tool"]["poetry"].add("packages", [])
2147

@@ -27,6 +53,13 @@ def generate_updated_project(data: TOMLDocument, packages: List[dict]) -> str:
2753
return tomlkit.dumps(copy)
2854

2955

56+
def generate_updated_project(data: TOMLDocument, packages: List[dict]) -> str:
57+
if repo.is_pep_621_ready(data):
58+
return generate_updated_pep_621_ready_project(data, packages)
59+
60+
return generate_updated_poetry_project(data, packages)
61+
62+
3063
def to_packages(root: Path, namespace: str, diff: dict) -> List[dict]:
3164
theme = workspace.parser.get_theme_from_config(root)
3265

development/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Development
2+
3+
4+
## Build and install local version
5+
Make sure to uninstall the properly installed version you have via Poetry:
6+
7+
``` shell
8+
poetry self remove poetry-polylith-plugin
9+
```
10+
11+
Build a wheel from your local folder:
12+
``` shell
13+
poetry build-project --directory projects/poetry_polylith_plugin
14+
```
15+
16+
Install into the Poetry virtual environment (Mac OS X), with pip:
17+
``` shell
18+
~/Library/Application\ Support/pypoetry/venv/bin/pip install projects/poetry_polylith_plugin/dist/poetry_polylith_plugin-<INSERT-VERSION-HERE>-py3-none-any.whl
19+
```
20+
21+
When done testing, don't forget to uninstall the local test version:
22+
``` shell
23+
~/Library/Application\ Support/pypoetry/venv/bin/pip uninstall poetry-polylith-plugin
24+
```
25+

projects/poetry_polylith_plugin/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "poetry-polylith-plugin"
3-
version = "1.12.2"
3+
version = "1.13.0"
44
description = "A Poetry plugin that adds tooling support for the Polylith Architecture"
55
authors = ["David Vujic"]
66
homepage = "https://davidvujic.github.io/python-polylith-docs/"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import tomlkit
2+
from polylith.project.create import create_project_toml
3+
4+
5+
def test_create_project_toml():
6+
name = "unit test project"
7+
description = "this is a unit test"
8+
authors = ["one", "two", "three"]
9+
python_version = "something"
10+
11+
template = 'x = "{name}{description}{authors}{python_version}"'
12+
13+
data = {
14+
"name": name,
15+
"description": description,
16+
"authors": authors,
17+
"python_version": python_version,
18+
}
19+
20+
res = create_project_toml(template, data)
21+
22+
assert tomlkit.dumps(res) == f'x = "{name}{description}{authors}{python_version}"'

0 commit comments

Comments
 (0)