Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,5 @@ cython_debug/

# PyPI configuration file
.pypirc
data/*
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this dir be incorporated into the tests suite?

testing.ipynb
19 changes: 19 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ You can run pytest on your work using the following example:
% uv run pytest
```

### Linting, testing, coverage, and updating coverage badges

We apply a custom script to update our coverage badge in the README during our CI workflow.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thanks for spelling this out.

When running `scripts/update_coverage_badge.py` the script will parse the `coverage.xml` file generated from pytest and update the badge in the README with the new coverage percentage.
When running `just all` locally, the coverage badge will not be updated since it is intended to be updated as part of the CI workflow.

```
just all
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider providing an indication of "which" "all" we're meaning when we call this from just. For example all-prep or something could help distinguish what you mean in the project.

```

the coverage badge will be automatically updated as part of the workflow.
If you want to update the covererage then just run:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If you want to update the covererage then just run:
If you want to update the coverage, run:


```
just coverage
```

This will run the tests and update the coverage badge in the README.

## Making changes to this repository

We welcome anyone to use [GitHub issues](https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues) (requires a GitHub login) or create [pull requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) (to directly make changes within this repository) to modify content found within this repository.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ZedProfiler

[![Coverage](https://img.shields.io/badge/coverage-94%25-brightgreen)](#quality-gates)
[![Coverage](https://img.shields.io/badge/coverage-97%25-brightgreen)](#quality-gates)

CPU-first 3D image feature extraction toolkit for high-content and high-throughput image-based profiling.

Expand Down
8 changes: 4 additions & 4 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ The roadmap is intended to be a living document and may be updated as needed.

1. PR 1: Packaging and environment baseline

- [ ] Python package scaffold, uv dependency management, version metadata 0.0.1, lint/test tooling, CI skeleton.
- [ ] Linux support and CPU-only scope statements in metadata and docs.
- [x] Python package scaffold, uv dependency management, version metadata 0.0.1, lint/test tooling, CI skeleton.
- [x] Linux support and CPU-only scope statements in metadata and docs.

2. PR 2: Core data model and API contracts

- [ ] Canonical input contracts, loader interfaces, common error types.
- [ ] Return schema contract (required keys, types, deterministic ordering).
- [x] Canonical input contracts, loader interfaces, common error types.
- [x] Return schema contract (required keys, types, deterministic ordering).

3. PR 3: RFC2119 naming specification and validators

Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ dependencies = [
"jinja2>=3.1.6",
"pandas>=3.0.2",
"pandera>=0.31.1",
"pyarrow>=23.0.1",
"pydantic>=2.10",
"scikit-image>=0.26",
"tomli>=2.4.1",
]
scripts.ZedProfiler = "ZedProfiler.cli:trigger"

Expand Down
77 changes: 77 additions & 0 deletions scripts/test_update_coverage_badge.py
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to add this as part of the tests suite? You could invoke just this test if needed for the coverage update (perhaps using an ignore pattern or marks or both).

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import importlib.util
from pathlib import Path

import pytest

# Load the module relative to this test file
_spec = importlib.util.spec_from_file_location(
"update_coverage_badge", Path(__file__).parent / "update_coverage_badge.py"
)
mod = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(mod)


def test_replaces_existing_badge(tmp_path: Path) -> None:
readme = tmp_path / "README.md"
original = (
"# Project\n\n"
"[![Coverage](https://img.shields.io/badge/coverage-42%25-red)](#quality-gates)\n\n"
"Some text\n"
)
readme.write_text(original, encoding="utf-8")

changed = mod.update_readme_badge(readme, 85)
assert changed is True

updated = readme.read_text(encoding="utf-8")
assert "coverage-85%25-green" in updated
assert updated.count("[![Coverage]") == 1
assert "coverage-42%25-red" not in updated


def test_inserts_badge_when_missing(tmp_path: Path) -> None:
readme = tmp_path / "README.md"
original = "# Project\nDescription line\n"
readme.write_text(original, encoding="utf-8")

changed = mod.update_readme_badge(readme, 60)
assert changed is True

updated = readme.read_text(encoding="utf-8")
lines = updated.splitlines()
# After insertion: title at 0, blank line at 1, badge at 2
assert lines[0] == "# Project"
assert lines[1] == ""
assert lines[2].startswith("[![Coverage]")
assert "coverage-60%25-yellow" in lines[2]


def test_preserves_trailing_newline_on_insert(tmp_path: Path) -> None:
readme = tmp_path / "README.md"
original = "# Project\nDescription line\n" # ends with newline
readme.write_text(original, encoding="utf-8")

changed = mod.update_readme_badge(readme, 70)
assert changed is True

updated = readme.read_text(encoding="utf-8")
assert updated.endswith("\n")


def test_no_change_returns_false_when_badge_already_exact(tmp_path: Path) -> None:
readme = tmp_path / "README.md"
# percent 75 -> color "yellowgreen" (per thresholds)
badge = "[![Coverage](https://img.shields.io/badge/coverage-75%25-yellowgreen)](#quality-gates)"
original = f"# Project\n\n{badge}\n\nMore\n"
readme.write_text(original, encoding="utf-8")

changed = mod.update_readme_badge(readme, 75)
assert changed is False
assert readme.read_text(encoding="utf-8") == original


def test_empty_readme_raises_value_error(tmp_path: Path) -> None:
readme = tmp_path / "README.md"
readme.write_text("", encoding="utf-8")
with pytest.raises(ValueError):
mod.update_readme_badge(readme, 50)
Loading
Loading