Skip to content
Merged
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 INTERNAL_DOCS/known-issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ Tracker for bugs, tech debt, and missing test coverage. Mark items with `[x]` as
- [ ] **HIGH: `serve` command missing from README** — No user-facing documentation for proxy server.
- [ ] **TEST: `run_script`** — Zero unit tests for core orchestration.
- [ ] **TEST: Missing server passthrough endpoint tests**
- [x] **HIGH: `parse_wheel_tags` build tag heuristic in download.py** — Same bug as the rename.py heuristic (used `parts[2][0].isdigit()` instead of counting from end). Fixed: now uses `parts[-3]`, `parts[-2]`, `parts[-1]`.
- [ ] **DOCS: `sync.py` functions missing from architecture.md, `test_sync.py` missing from testing.md**
13 changes: 13 additions & 0 deletions INTERNAL_DOCS/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ uv run python -m pytest -m integration # Integration tests (slower, network)

## Test File Locations

- Property-based tests: `test_properties.py` (Hypothesis)
- Unit tests: `test_rename.py`
- Tag/download tests: `test_download.py`
- Run/metadata parsing tests: `test_run.py`
Expand All @@ -33,6 +34,18 @@ Tests create isolated venvs and install both original and renamed packages to ve
4. No `sys.modules` contamination
5. No leaked references to old package name in renamed package

## Property-Based Tests (Hypothesis)

`tests/test_properties.py` uses Hypothesis to test invariants and roundtrip properties:

```bash
uv run pytest tests/test_properties.py -v
```

53 property tests covering: name normalization, filename parse/build roundtrip, import rewriting, wheel rename roundtrip, PEP 723 parsing, CLI rename parsing, dependency patching, RECORD hashing, metadata updates, wheel tag parsing, rename merging, comment/TOML extraction, cache key generation, server config parsing/normalization/lookup, root/project HTML generation, and filename rewriting roundtrips.

Slow tests (`rename_wheel_from_bytes` roundtrips) use `max_examples=50` and `deadline=5000`.

## Test Wheel Creation

Use `conftest.create_test_wheel()` to create synthetic wheels with version-tagged functions:
Expand Down
15 changes: 14 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,20 @@ dependencies = [
]

[project.optional-dependencies]
dev = ["pytest>=8.0", "pytest-cov>=4.0", "ruff>=0.8.0"]
server = [
"fastapi>=0.109.0",
"uvicorn[standard]>=0.27.0",
"httpx>=0.26.0",
]

[dependency-groups]
dev = [
"pytest>=8.0",
"pytest-cov>=4.0",
"ruff>=0.8.0",
"hypothesis>=6.100",
{include-group = "server"},
]
server = [
"fastapi>=0.109.0",
"uvicorn[standard]>=0.27.0",
Expand Down
18 changes: 5 additions & 13 deletions src/third_wheel/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,11 @@ def parse_wheel_tags(filename: str) -> list[Tag]:
if len(parts) < 5:
return []

# Handle optional build tag (starts with digit)
if len(parts) >= 6 and parts[2][0].isdigit():
py_tag = parts[3]
abi_tag = parts[4]
plat_tags = parts[5].split(".")
else:
py_tag = parts[2]
abi_tag = parts[3]
plat_tags = parts[4].split(".")

# All three tag fields can be dot-separated (e.g., py2.py3-none-any)
py_tags = py_tag.split(".")
abi_tags = abi_tag.split(".")
# Last 3 parts are always python-abi-platform (count from end to handle
# build tags and distribution names with hyphens correctly)
py_tags = parts[-3].split(".")
abi_tags = parts[-2].split(".")
plat_tags = parts[-1].split(".")
return [Tag(py, abi, plat) for py in py_tags for abi in abi_tags for plat in plat_tags]


Expand Down
Loading