Skip to content

Commit 34221a6

Browse files
feat(packages): add example monorepo package
- migrates original root package to pnt-functional - replaces root package with simplified package Signed-off-by: Cameron Smith <[email protected]>
1 parent 204b0a0 commit 34221a6

File tree

11 files changed

+230
-91
lines changed

11 files changed

+230
-91
lines changed
File renamed without changes.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
[project]
2+
authors = [
3+
{ name = "Your Name", email = "[email protected]" },
4+
]
5+
classifiers = [
6+
"Development Status :: 3 - Alpha",
7+
"License :: OSI Approved :: MIT License",
8+
"Operating System :: OS Independent",
9+
"Programming Language :: Python :: 3",
10+
"Programming Language :: Python :: 3.11",
11+
"Programming Language :: Python :: 3.12",
12+
]
13+
dependencies = [
14+
"beartype>=0.19.0,<0.20.0",
15+
"expression>=5.5.0",
16+
]
17+
description = "A Python package template using Nix and uv"
18+
license = { text = "Apache-2.0" }
19+
name = "pnt-functional"
20+
readme = "README.md"
21+
requires-python = ">=3.11"
22+
version = "0.1.0"
23+
24+
[project.scripts]
25+
pnt-functional = "pnt_functional.main:greet"
26+
27+
[build-system]
28+
build-backend = "hatchling.build"
29+
requires = ["hatchling"]
30+
31+
[project.optional-dependencies]
32+
33+
[dependency-groups]
34+
dev = [
35+
{ include-group = "interactive" },
36+
{ include-group = "lint" },
37+
{ include-group = "test" },
38+
{ include-group = "types" },
39+
]
40+
interactive = [
41+
"ipython>=8.32.0",
42+
]
43+
lint = [
44+
"ruff>=0.9.4",
45+
]
46+
test = [
47+
"hypothesis>=6.125.1",
48+
"pytest-cov>=6.0.0",
49+
"pytest>=8.3.4",
50+
"xdoctest>=1.2.0",
51+
]
52+
types = [
53+
"pyright>=1.1.395",
54+
]
55+
56+
[tool.uv]
57+
default-groups = ["lint", "test", "types"]
58+
59+
[tool.pixi.workspace]
60+
channels = ["conda-forge"]
61+
platforms = ["linux-64", "osx-arm64"]
62+
preview = ["pixi-build"]
63+
64+
[tool.pixi.dependencies]
65+
beartype = ">=0.19.0"
66+
expression = ">=5.5.0"
67+
python = ">=3.11"
68+
69+
[tool.pixi.pypi-dependencies]
70+
pnt-functional = { path = ".", editable = true }
71+
72+
[tool.pixi.environments]
73+
default = { solve-group = "default" }
74+
dev = { features = ["dev"], solve-group = "default" }
75+
interactive = { features = ["interactive"], solve-group = "default" }
76+
lint = { features = ["lint"], solve-group = "default" }
77+
test = { features = ["test"], solve-group = "default" }
78+
types = { features = ["types"], solve-group = "default" }
79+
80+
[tool.pixi.feature.test.tasks]
81+
test = "pytest"
82+
83+
[tool.pixi.feature.lint.tasks]
84+
lint = "ruff check --fix src/"
85+
lint-check = "ruff check src/"
86+
87+
[tool.pixi.feature.types.tasks]
88+
types = "pyright src/"
89+
90+
[tool.pixi.package]
91+
name = "pnt-functional"
92+
version = "0.1.0"
93+
94+
[tool.pixi.package.run-dependencies]
95+
beartype = ">=0.19.0"
96+
expression = ">=5.5.0"
97+
98+
[tool.pixi.package.host-dependencies]
99+
hatchling = "*"
100+
101+
[tool.pixi.package.build]
102+
backend = { name = "pixi-build-python", version = "0.1.*" }
103+
channels = [
104+
"https://prefix.dev/conda-forge",
105+
"https://prefix.dev/pixi-build-backends",
106+
]
107+
108+
[tool.hatch.build.targets.wheel]
109+
packages = ["src/pnt_functional"]
110+
111+
[tool.pytest.ini_options]
112+
addopts = """
113+
-rA
114+
--xdoctest
115+
--disable-warnings
116+
--cov=src/pnt_functional/
117+
--cov-report=term-missing
118+
--durations=0
119+
"""
120+
log_level = "INFO"
121+
testpaths = [
122+
"src/pnt_functional/tests",
123+
]
124+
125+
[tool.ruff]
126+
line-length = 88
127+
src = ["src"]
128+
target-version = "py311"
129+
130+
[tool.ruff.lint]
131+
select = [
132+
"B", # flake8-bugbear
133+
"E", # pycodestyle errors
134+
"F", # pyflakes
135+
"I", # isort
136+
"W", # pycodestyle warnings
137+
]

packages/pnt-functional/src/.keep

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""A Python package template using Nix and uv."""
2+
3+
__version__ = "0.1.0"
4+
5+
from pnt_functional.main import greet
6+
7+
__all__ = [
8+
"greet",
9+
]

src/python_nix_template/main.py renamed to packages/pnt-functional/src/pnt_functional/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Main module for python_nix_template demonstrating functional programming patterns."""
1+
"""Main module for pnt_functional demonstrating functional programming patterns."""
22

33
from beartype import beartype
44
from expression import Error, Ok, Result
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Tests for main module."""
2+
3+
from expression import Error, Ok
4+
5+
from pnt_functional.main import create_greeting, greet, validate_name
6+
7+
8+
def test_validate_name_valid():
9+
"""Test name validation with valid input."""
10+
assert validate_name("alice") == Ok("Alice")
11+
assert validate_name(" bob ") == Ok("Bob")
12+
13+
14+
def test_validate_name_invalid():
15+
"""Test name validation with invalid input."""
16+
assert validate_name("") == Error("Name cannot be empty")
17+
assert validate_name(" ") == Error("Name cannot be empty")
18+
assert validate_name("a") == Error("Name must be at least 2 characters")
19+
assert validate_name("x" * 51) == Error("Name must be at most 50 characters")
20+
21+
22+
def test_create_greeting_valid():
23+
"""Test greeting creation with valid input."""
24+
assert create_greeting("alice") == Ok("Hello, Alice!")
25+
assert create_greeting(" bob ") == Ok("Hello, Bob!")
26+
27+
28+
def test_create_greeting_invalid():
29+
"""Test greeting creation with invalid input."""
30+
result = create_greeting("")
31+
assert result.is_error()
32+
33+
result = create_greeting("a")
34+
assert result.is_error()
35+
36+
37+
def test_greet_default():
38+
"""Test greet function with default argument."""
39+
result = greet()
40+
assert result == "Hello, World!"
41+
42+
43+
def test_greet_custom():
44+
"""Test greet function with custom name."""
45+
result = greet("Alice")
46+
assert result == "Hello, Alice!"
47+
48+
49+
def test_greet_invalid():
50+
"""Test greet function with invalid input."""
51+
result = greet("a")
52+
assert result == "This is supposed to be a hello world program, but it failed."

pyproject.toml

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,28 @@
22
authors = [
33
{ name = "Your Name", email = "[email protected]" },
44
]
5-
classifiers = [
6-
"Development Status :: 3 - Alpha",
7-
"License :: OSI Approved :: MIT License",
8-
"Operating System :: OS Independent",
9-
"Programming Language :: Python :: 3",
10-
"Programming Language :: Python :: 3.11",
11-
"Programming Language :: Python :: 3.12",
12-
]
13-
dependencies = [
14-
"beartype>=0.19.0",
15-
"expression>=5.5.0",
16-
]
17-
description = "A Python package template using Nix and uv"
18-
license = { text = "Apache-2.0" }
5+
dependencies = []
6+
description = "Add your description here"
197
name = "python-nix-template"
208
readme = "README.md"
219
requires-python = ">=3.11"
2210
version = "0.1.0"
2311

2412
[project.scripts]
25-
python-nix-template = "python_nix_template.main:greet"
13+
python-nix-template = "python_nix_template:main"
2614

2715
[build-system]
2816
build-backend = "hatchling.build"
2917
requires = ["hatchling"]
3018

31-
[project.optional-dependencies]
19+
# [tool.uv.sources]
20+
# pnt-functional = { workspace = true }
21+
22+
# [tool.uv.workspace]
23+
# members = ["packages/*"]
24+
25+
[tool.hatch.build.targets.wheel]
26+
packages = ["src/python_nix_template"]
3227

3328
[dependency-groups]
3429
dev = [
@@ -62,9 +57,7 @@ platforms = ["linux-64", "osx-arm64"]
6257
preview = ["pixi-build"]
6358

6459
[tool.pixi.dependencies]
65-
beartype = ">=0.19.0"
66-
expression = ">=5.5.0"
67-
python = ">=3.11"
60+
python = ">=3.11"
6861

6962
[tool.pixi.pypi-dependencies]
7063
python-nix-template = { path = ".", editable = true }
@@ -77,23 +70,11 @@ lint = { features = ["lint"], solve-group = "default" }
7770
test = { features = ["test"], solve-group = "default" }
7871
types = { features = ["types"], solve-group = "default" }
7972

80-
[tool.pixi.feature.test.tasks]
81-
test = "pytest"
82-
83-
[tool.pixi.feature.lint.tasks]
84-
lint = "ruff check --fix src/"
85-
lint-check = "ruff check src/"
86-
87-
[tool.pixi.feature.types.tasks]
88-
types = "pyright src/"
89-
9073
[tool.pixi.package]
9174
name = "python-nix-template"
9275
version = "0.1.0"
9376

9477
[tool.pixi.package.run-dependencies]
95-
beartype = ">=0.19.0"
96-
expression = ">=5.5.0"
9778

9879
[tool.pixi.package.build]
9980
backend = { name = "pixi-build-python", version = "0.1.*" }
@@ -102,10 +83,12 @@ channels = [
10283
"https://prefix.dev/pixi-build-backends",
10384
]
10485

105-
[tool.hatch.build.targets.wheel]
106-
packages = ["src/python_nix_template"]
86+
[tool.pixi.package.host-dependencies]
87+
hatchling = "*"
10788

10889
[tool.pytest.ini_options]
90+
# Add source locations to pytest-cov e.g.:
91+
# --cov=packages/pnt-functional/src/pnt_functional/
10992
addopts = """
11093
-rA
11194
--xdoctest
@@ -116,6 +99,8 @@ addopts = """
11699
"""
117100
log_level = "INFO"
118101
testpaths = [
102+
# Add test locations e.g.:
103+
# "packages/pnt-functional/src/pnt_functional/tests",
119104
"src/python_nix_template/tests",
120105
]
121106

src/python_nix_template/__init__.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,2 @@
1-
"""A Python package template using Nix and uv."""
2-
3-
__version__ = "0.1.0"
4-
5-
from python_nix_template.main import greet
6-
7-
__all__ = [
8-
"greet",
9-
]
1+
def main() -> None:
2+
print("Hello from python-nix-template!")

src/python_nix_template/tests/.keep

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This file is intentionally left empty to mark the directory as a Python package
Lines changed: 10 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,14 @@
1-
"""Tests for main module."""
1+
from python_nix_template import main
22

3-
from expression import Error, Ok
43

5-
from python_nix_template.main import create_greeting, greet, validate_name
4+
def test_main(capsys):
5+
"""Test that the main function prints the expected greeting."""
6+
main()
7+
captured = capsys.readouterr()
8+
assert "Hello from python-nix-template!" in captured.out
69

710

8-
def test_validate_name_valid():
9-
"""Test name validation with valid input."""
10-
assert validate_name("alice") == Ok("Alice")
11-
assert validate_name(" bob ") == Ok("Bob")
12-
13-
14-
def test_validate_name_invalid():
15-
"""Test name validation with invalid input."""
16-
assert validate_name("") == Error("Name cannot be empty")
17-
assert validate_name(" ") == Error("Name cannot be empty")
18-
assert validate_name("a") == Error("Name must be at least 2 characters")
19-
assert validate_name("x" * 51) == Error("Name must be at most 50 characters")
20-
21-
22-
def test_create_greeting_valid():
23-
"""Test greeting creation with valid input."""
24-
assert create_greeting("alice") == Ok("Hello, Alice!")
25-
assert create_greeting(" bob ") == Ok("Hello, Bob!")
26-
27-
28-
def test_create_greeting_invalid():
29-
"""Test greeting creation with invalid input."""
30-
result = create_greeting("")
31-
assert result.is_error()
32-
33-
result = create_greeting("a")
34-
assert result.is_error()
35-
36-
37-
def test_greet_default():
38-
"""Test greet function with default argument."""
39-
result = greet()
40-
assert result == "Hello, World!"
41-
42-
43-
def test_greet_custom():
44-
"""Test greet function with custom name."""
45-
result = greet("Alice")
46-
assert result == "Hello, Alice!"
47-
48-
49-
def test_greet_invalid():
50-
"""Test greet function with invalid input."""
51-
result = greet("a")
52-
assert result == "This is supposed to be a hello world program, but it failed."
11+
def test_main_returns_none():
12+
"""Test that the main function returns None."""
13+
result = main()
14+
assert result is None

0 commit comments

Comments
 (0)