Skip to content

Commit 263a0d3

Browse files
committed
updated README, this version is now ready to merge to main
1 parent 32bf799 commit 263a0d3

7 files changed

Lines changed: 55 additions & 22 deletions

File tree

‎README.md‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ uv run ruff check src/
7979

8080
## Documentation
8181

82-
A full class listing and documentations can be found here :-
82+
A full class listing and documentations can be found here :-
8383

8484
- **Docs site:** <https://ncca.github.io/PyNGL/>
8585
- **Getting started / tutorials:** <https://ncca.github.io/PyNGL/tutorials/> (Getting Started and Tutorials sections)
@@ -89,7 +89,7 @@ The site covers the math API design rules, vectors/matrices/quaternions, transfo
8989
### Knowledge wiki
9090

9191
Alongside the API reference, [`wiki/`](wiki/index.md) is an agent-maintained
92-
knowledge base about *how PyNGL works* — architecture narratives, module
92+
knowledge base about _how PyNGL works_ — architecture narratives, module
9393
deep-dives, design decisions, and gotchas — written for both people and
9494
coding agents. Start at [`wiki/index.md`](wiki/index.md).
9595

@@ -105,6 +105,14 @@ source files that changed. If you use Claude Code, `/wiki status`,
105105
`/wiki update`, and `/wiki build` maintain the wiki for you (see
106106
`.claude/skills/wiki/SKILL.md`).
107107

108+
## AI Usage
109+
110+
This project has use various AI tools ([Claude](https://claude.ai) and [Codex](https://openai.com/codex/) and [OpenCode](https://opencode.ai/)) to assist with development.
111+
112+
The initial phases were for the full port of NGL to PyNGL (C++ to Python conversion) and additional testing. Most of the work is shown in the docs section of the repository, and I have also written about various things on my blog [her](https://nccastaff.bournemouth.ac.uk/jmacey/post/).
113+
114+
There will be a full write-up of my setup and usage of AI on the Blog soon.
115+
108116
## License
109117

110118
See [LICENSE.txt](LICENSE.txt) or just use the [Beerware License](https://scancode-licensedb.aboutcode.org/beerware.html)

‎run_coverage_nogpu.py‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/env -S uv run --script
2-
"""
3-
Run coverage tests without GPU dependencies.
2+
"""Run coverage tests without GPU dependencies.
43
This script separates CPU-only tests from GPU/Qt-dependent tests.
54
"""
65

@@ -32,7 +31,6 @@ def run_command(cmd: str, description: str) -> bool:
3231

3332
def main():
3433
"""Main function to run coverage without GPU."""
35-
3634
# CPU-only tests (no OpenGL context, no Qt)
3735
cpu_only_tests = [
3836
"tests/test_vec2.py",

‎tests/test_perspective_widget.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ def test_show_mode_true_shows_combobox(qt_app, qtbot):
159159

160160
def test_mode_switch_changes_matrix(qt_app, qtbot):
161161
"""Test that changing mode produces a different matrix (WebGPU vs OpenGL)."""
162-
widget = PerspectiveWidget(show_mode=True, fov=50.0, aspect=1.5, near=0.5, far=200.0)
162+
widget = PerspectiveWidget(
163+
show_mode=True, fov=50.0, aspect=1.5, near=0.5, far=200.0
164+
)
163165
qtbot.addWidget(widget)
164166

165167
opengl_matrix = widget.matrix()
@@ -172,7 +174,9 @@ def test_mode_switch_changes_matrix(qt_app, qtbot):
172174

173175
def test_set_mode_programmatically_without_show_mode(qt_app, qtbot):
174176
"""Test that mode can still be set programmatically when show_mode=False."""
175-
widget = PerspectiveWidget(show_mode=False, fov=50.0, aspect=1.5, near=0.5, far=200.0)
177+
widget = PerspectiveWidget(
178+
show_mode=False, fov=50.0, aspect=1.5, near=0.5, far=200.0
179+
)
176180
qtbot.addWidget(widget)
177181

178182
widget.set_mode(PerspMode.Vulkan)

‎tests/test_qml_mat3_model.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import pytest
2-
31
from ncca.ngl import Mat3
42

53

‎tests/test_qml_mat_grid_models.py‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import pytest
22

33
from ncca.ngl import Mat2, Mat3, Mat4
4-
from ncca.ngl.mat_base import MatrixError
54

65
WIDGET_CASES = [
76
("ncca.ngl.qml.mat2_model", "Mat2Model", Mat2, 2),
@@ -34,7 +33,9 @@ def test_get_and_set_cell_round_trip(qt_app, module_name, class_name, mat_cls, s
3433

3534

3635
@pytest.mark.parametrize("module_name,class_name,mat_cls,size", WIDGET_CASES)
37-
def test_set_cell_emits_value_changed(qt_app, qtbot, module_name, class_name, mat_cls, size):
36+
def test_set_cell_emits_value_changed(
37+
qt_app, qtbot, module_name, class_name, mat_cls, size
38+
):
3839
model = _load_model_cls(module_name, class_name)()
3940

4041
with qtbot.waitSignal(model.valueChanged, timeout=1000):
@@ -53,7 +54,9 @@ def test_zero_then_identity_round_trip(qt_app, module_name, class_name, mat_cls,
5354

5455

5556
@pytest.mark.parametrize("module_name,class_name,mat_cls,size", WIDGET_CASES)
56-
def test_transpose_reflects_current_value(qt_app, module_name, class_name, mat_cls, size):
57+
def test_transpose_reflects_current_value(
58+
qt_app, module_name, class_name, mat_cls, size
59+
):
5760
model = _load_model_cls(module_name, class_name)()
5861
model.set_cell(0, 1, 7.0)
5962

‎tests/test_wiki_check_sync.py‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
import pytest
1010

11-
_MODULE_PATH = Path(__file__).resolve().parent.parent / "wiki" / "tools" / "check_sync.py"
11+
_MODULE_PATH = (
12+
Path(__file__).resolve().parent.parent / "wiki" / "tools" / "check_sync.py"
13+
)
1214
_spec = importlib.util.spec_from_file_location("check_sync", _MODULE_PATH)
1315
check_sync = importlib.util.module_from_spec(_spec)
1416
sys.modules["check_sync"] = check_sync
@@ -55,7 +57,11 @@ class TestGlobToRegex:
5557
[
5658
("src/ncca/ngl/vec*.py", "src/ncca/ngl/vec3.py", True),
5759
("src/ncca/ngl/vec*.py", "src/ncca/ngl/vec3_array.py", True),
58-
("src/ncca/ngl/vec*.py", "src/ncca/ngl/opengl/vec3.py", False), # * stays in one dir
60+
(
61+
"src/ncca/ngl/vec*.py",
62+
"src/ncca/ngl/opengl/vec3.py",
63+
False,
64+
), # * stays in one dir
5965
("src/ncca/ngl/webgpu/**", "src/ncca/ngl/webgpu/line_pipeline.py", True),
6066
("**/conftest.py", "tests/conftest.py", True),
6167
("**/conftest.py", "conftest.py", True), # **/ also matches zero dirs
@@ -99,27 +105,35 @@ def wiki_repo(tmp_path):
99105

100106
class TestCheckPage:
101107
def test_fresh_when_sources_unchanged(self, wiki_repo):
102-
status = check_sync.check_page(wiki_repo, wiki_repo / "wiki" / "modules" / "math.md")
108+
status = check_sync.check_page(
109+
wiki_repo, wiki_repo / "wiki" / "modules" / "math.md"
110+
)
103111
assert status.state == "fresh"
104112
assert status.changed == []
105113

106114
def test_stale_when_source_changes_after_sync(self, wiki_repo):
107115
(wiki_repo / "src" / "ncca" / "ngl" / "vec3.py").write_text("x = 2\n")
108116
_git(wiki_repo, "commit", "-am", "change vec3")
109-
status = check_sync.check_page(wiki_repo, wiki_repo / "wiki" / "modules" / "math.md")
117+
status = check_sync.check_page(
118+
wiki_repo, wiki_repo / "wiki" / "modules" / "math.md"
119+
)
110120
assert status.state == "stale"
111121
assert status.changed == ["src/ncca/ngl/vec3.py"]
112122

113123
def test_fresh_when_unrelated_file_changes(self, wiki_repo):
114124
(wiki_repo / "README.md").write_text("hello\n")
115125
_git(wiki_repo, "add", ".")
116126
_git(wiki_repo, "commit", "-m", "add readme")
117-
status = check_sync.check_page(wiki_repo, wiki_repo / "wiki" / "modules" / "math.md")
127+
status = check_sync.check_page(
128+
wiki_repo, wiki_repo / "wiki" / "modules" / "math.md"
129+
)
118130
assert status.state == "fresh"
119131

120132
def test_error_on_unknown_synced_commit(self, wiki_repo):
121133
page = wiki_repo / "wiki" / "modules" / "math.md"
122-
page.write_text("---\nsources:\n - src/ncca/ngl/vec*.py\nsynced: " + "0" * 40 + "\n---\n")
134+
page.write_text(
135+
"---\nsources:\n - src/ncca/ngl/vec*.py\nsynced: " + "0" * 40 + "\n---\n"
136+
)
123137
status = check_sync.check_page(wiki_repo, page)
124138
assert status.state == "error"
125139
assert "commit" in status.message

‎wiki/tools/check_sync.py‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ def parse_frontmatter(text: str) -> Frontmatter:
5656
if not lines or lines[0].strip() != "---":
5757
raise FrontmatterError("page does not start with a '---' frontmatter block")
5858
try:
59-
end = next(i for i, line in enumerate(lines[1:], start=1) if line.strip() == "---")
59+
end = next(
60+
i for i, line in enumerate(lines[1:], start=1) if line.strip() == "---"
61+
)
6062
except StopIteration:
6163
raise FrontmatterError("frontmatter block is never closed with '---'") from None
6264

@@ -197,7 +199,9 @@ def check_page(repo_root: Path, page: Path) -> PageStatus:
197199
message=f"synced commit {fm.synced} not found in repository",
198200
frontmatter=fm,
199201
)
200-
out = _git(repo_root, "diff", "--name-only", f"{fm.synced}..HEAD", "--", *fm.sources)
202+
out = _git(
203+
repo_root, "diff", "--name-only", f"{fm.synced}..HEAD", "--", *fm.sources
204+
)
201205
changed = [line for line in out.splitlines() if line]
202206
state = "stale" if changed else "fresh"
203207
return PageStatus(path=page, state=state, changed=changed, frontmatter=fm)
@@ -241,7 +245,9 @@ def main(argv: list[str] | None = None) -> int:
241245
0 when every page is fresh, 1 when any page is stale or in error.
242246
"""
243247
parser = argparse.ArgumentParser(description=__doc__)
244-
parser.add_argument("--wiki-dir", type=Path, default=Path(__file__).resolve().parent.parent)
248+
parser.add_argument(
249+
"--wiki-dir", type=Path, default=Path(__file__).resolve().parent.parent
250+
)
245251
parser.add_argument("--repo-root", type=Path, default=None)
246252
parser.add_argument("--json", action="store_true", dest="as_json")
247253
args = parser.parse_args(argv)
@@ -278,7 +284,9 @@ def main(argv: list[str] | None = None) -> int:
278284
if s.state == "fresh":
279285
print(f"FRESH {rel}")
280286
elif s.state == "stale":
281-
print(f"STALE {rel} — {len(s.changed)} changed since {s.frontmatter.synced[:7]}:")
287+
print(
288+
f"STALE {rel} — {len(s.changed)} changed since {s.frontmatter.synced[:7]}:"
289+
)
282290
for f in s.changed:
283291
print(f" {f}")
284292
else:

0 commit comments

Comments
 (0)