Skip to content

feat(python): add the python port of trackparse - #3

Merged
4matic merged 4 commits into
mainfrom
feat/python-port
Oct 1, 2026
Merged

4matic merged 4 commits into
mainfrom
feat/python-port

Conversation

@4matic

@4matic 4matic commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the Python port: the PyPI package trackparse for Python 3.9+, with zero dependencies. It passes all 11,891 shared fixtures, and its output is byte-identical to JS: scripts/compare-ports.mjs diffs the full JSON of every fixture case across both ports and finds 0 differences.

from trackparse import parse
t = parse("Wilkinson ft. Becky Hill - Afterglow (Sub Focus VIP Remix)")
t.artists[1].role        # 'featured'
t.versions[0].modifiers  # ('vip',)
t.to_dict()              # the spec's camelCase JSON, identical to JS

Commits (please use Rebase and merge, so release-please lists each one in the changelog)

  • feat(spec): R0.6 now defines a letter as Unicode general category L (JS \p{L}, Python isalpha()). Two new fixtures pin the change.
  • fix(js): a malformed knownArtists or keyword option threw a TypeError, which breaks R0.8. Found in code review; Python already handled it.
  • perf(js): trailing junk stripping (R8.4) was quadratic. A 40k-character input took about 1.7 s and now takes about 35 ms. Both ports have a regression test.
  • feat(python): the port itself (python/), CI, release wiring and docs.

Python package

  • src/trackparse/ mirrors js/src module for module, with the same rule-ID comments. Results are frozen dataclasses with snake_case attributes, and to_dict()/from_dict() convert to and from the spec JSON.
  • API: parse, parse_artists, format_track, normalize, all_artists, create_parser, SPEC_VERSION, __version__.
  • Tests: 991 pytest tests covering every fixture, schema validation of every output, Hypothesis versions of the spec invariants, and the API.

CI and release

  • python.yml: ruff, mypy --strict and pytest on Python 3.9–3.14. A build job installs the wheel into a clean venv and runs conformance.py --strict against it.
  • spec.yml: checks that the js, spec and python versions all match.
  • release-please: python joins the linked group, so the next release is 0.2.0 for js, spec and python. release.yml has a new publish-pypi job that uses trusted publishing (environment pypi).
  • Docs: AGENTS.md, README (Python install and quick start, PyPI badges), python/README.md (the PyPI page), .github/release-notes/0.2.0.md.

Before merging the release PR

The PyPI pending publisher must exist: project trackparse, owner 4matic, repo trackparse, workflow release.yml, environment pypi.

Test plan

  • JS: 981 tests; compat on the ESM and CJS builds, 11,891/11,891
  • Python: 991 tests on 3.9, 3.12 and 3.13; ruff, mypy --strict, gen_data check; wheel conformance at 100%
  • compare-ports.mjs: 0 differences across all 11,891 cases
  • actionlint; fixture validation; gen:check
  • CI green on this PR

4matic added 4 commits October 1, 2026 04:39
R0.6 used Unicode Alphabetic, which Python's str.isalpha() cannot match (it excludes Nl and
combining marks). Only R6.7 uses the test. Two fixtures pin the new definition.
A non-array knownArtists or keyword list (and non-object keyword maps) threw a TypeError, breaking
R0.8. Only arrays of strings and plain objects' string values are used now, matching the Python port.
R8.4 rescanned the whole title for every stripped phrase, so repeated trailing junk was quadratic
(40k code points took ~1.7 s). Word spans are now computed once and walked backwards.
PyPI package trackparse for Python 3.9+, zero dependencies, frozen dataclasses with to_dict() giving
the spec JSON. Passes all 11,891 shared fixtures with output byte-identical to JS
(scripts/compare-ports.mjs). Adds python.yml CI (3.9-3.14 + wheel conformance), python joins the
linked release group, and release.yml publishes to PyPI via trusted publishing.
@4matic
4matic merged commit a618a42 into main Oct 1, 2026
13 checks passed
@4matic
4matic deleted the feat/python-port branch October 1, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant