Skip to content

Commit 11c8bce

Browse files
committed
Get groups for direct dependencies from pyproject.toml
1 parent 61d1add commit 11c8bce

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
from typing import Optional, Tuple
5+
6+
import tomlkit
7+
from pydantic import BaseModel, model_validator
8+
from tomlkit import TOMLDocument
9+
10+
11+
class PoetryGroup(BaseModel):
12+
name: str
13+
toml_section: str
14+
15+
16+
class PoetryToml(BaseModel):
17+
file_path: Path = Path("pyproject.toml")
18+
_content: Optional[TOMLDocument] = None
19+
20+
@model_validator(mode="before")
21+
def read_content(cls, values):
22+
file_path = values["file_path"]
23+
if not file_path.exists():
24+
raise ValueError(f"File not found: {file_path}")
25+
26+
try:
27+
text = file_path.read_text()
28+
cls._content = tomlkit.loads(text)
29+
except Exception as e:
30+
raise ValueError(f"Error reading file: {str(e)}")
31+
return values
32+
33+
def get_section_dict(self, section: str) -> dict | None:
34+
current = self._content.copy()
35+
for section in section.split('.'):
36+
if section not in current:
37+
return None
38+
current = current[section]
39+
return current
40+
41+
@property
42+
def groups(self) -> Tuple[PoetryGroup, ...]:
43+
groups = []
44+
45+
main_key = "project.dependencies"
46+
if self.get_section_dict(main_key):
47+
groups.append(PoetryGroup(name="main", toml_section=main_key))
48+
49+
# present in some Poetry 2.x pyproject.tomls
50+
main_dynamic_key = "tool.poetry.dependencies"
51+
if self.get_section_dict(main_dynamic_key):
52+
groups.append(
53+
PoetryGroup(name="main", toml_section=main_dynamic_key)
54+
)
55+
56+
group_key = "tool.poetry.group"
57+
if group_dict := self.get_section_dict(group_key):
58+
for group, content in group_dict.items():
59+
if "dependencies" in content:
60+
groups.append(
61+
PoetryGroup(
62+
name=group,
63+
toml_section=f"{group_key}.{group}.dependencies",
64+
)
65+
)
66+
return tuple(groups)
67+
68+
# @property
69+
# def dependencies(self) -> Tuple[Group, ...]:
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import subprocess
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
from toolbox.util.dependencies import PoetryToml, PoetryGroup
7+
8+
MAIN_GROUP = PoetryGroup(name="main", toml_section="project.dependencies")
9+
DEV_GROUP = PoetryGroup(name="dev", toml_section="tool.poetry.group.dev.dependencies")
10+
ANALYSIS_GROUP = PoetryGroup(name="analysis",
11+
toml_section="tool.poetry.group.analysis.dependencies")
12+
13+
14+
@pytest.fixture(scope="module")
15+
def pyproject_toml_path(tmp_path_factory) -> Path:
16+
project_name = "project"
17+
path = tmp_path_factory.mktemp("test")
18+
subprocess.run(["poetry", "new", project_name], cwd=path)
19+
20+
project_path = path / project_name
21+
subprocess.run(["poetry", "add", "numpy"], cwd=project_path)
22+
subprocess.run(["poetry", "add", "pylint"], cwd=project_path)
23+
subprocess.run(["poetry", "add", "--group", "dev", "isort"], cwd=project_path)
24+
subprocess.run(["poetry", "add", "--group", "analysis", "black"], cwd=project_path)
25+
return project_path / "pyproject.toml"
26+
27+
28+
@pytest.fixture(scope="module")
29+
def pyproject_toml(pyproject_toml_path):
30+
return PoetryToml(file_path=pyproject_toml_path)
31+
32+
33+
class TestPoetryToml:
34+
@staticmethod
35+
def test_get_section_dict_exists(pyproject_toml):
36+
result = pyproject_toml.get_section_dict("project")
37+
assert result is not None
38+
39+
@staticmethod
40+
def test_get_section_dict_does_not_exist(pyproject_toml):
41+
result = pyproject_toml.get_section_dict("test")
42+
assert result is None
43+
44+
@staticmethod
45+
def test_groups(pyproject_toml):
46+
assert pyproject_toml.groups == (MAIN_GROUP, DEV_GROUP, ANALYSIS_GROUP)

0 commit comments

Comments
 (0)