Contributing
Fork the repository, implement your change, and open a pull request. Related features may share one PR; otherwise prefer one feature per PR.
Adding a new feature
Features live in src/melody_features/feature_definitions/.
get_all_features() discovers decorated callables
imported into melody_features.features — it does not use a hard-coded
list. Without correct decoration and export, a feature will not appear in
get_all_features, list_available_features, or the catalogue.
Implement in the right
feature_definitions/<family>.pymodule.Decorate with source(s), type, and domain (below).
Add to that module’s
__all__and import it infeatures.py.Write a NumPy-style docstring and type hints (docs are built from these).
Add tests; validate against the upstream implementation when possible (see
tests/test_jsymbolic_validation.py).Return native Python types (
int,float,list,dict, …).
Feature decorators
Defined in melody_features.feature_decorators. Stack one or more
sources, one type, and one domain:
from melody_features.feature_decorators import absolute, fantastic, jsymbolic, pitch
@fantastic
@jsymbolic
@absolute
@pitch
def pitch_range(pitches: list[int]) -> int:
...
Source:
@fantastic,@jsymbolic,@midi_toolbox,@idyom,@simile,@partitura,@must,@melsim,@novelType:
@absolute,@pitch_class,@interval,@contour,@tonality,@timing,@metre,@expectation,@complexity,@lexical_diversity,@corpusDomain:
@pitch,@rhythm, or@both
Only public, canonical bindings are collected (aliases like
ambitus = pitch_range are fine; do not re-decorate a second copy).
Docstrings
Sphinx API pages and the interactive catalogue are generated from feature docstrings and decorator metadata. Use NumPy style:
def example_feature(pitches: list[int]) -> float:
"""Short description (becomes the catalogue blurb).
Parameters
----------
pitches : list[int]
MIDI pitch values
Returns
-------
float
Meaning of the value
Notes
-----
Optional caveats.
Citation
--------
Author, A. (Year). Title.
"""
The opening paragraph is the catalogue description; annotate the return type
so metadata can label Descriptor vs Sequence. Cite literature when
the feature comes from a published method; use @novel for originals.
Tests and docs builds
Every pull request should include tests for the change (new coverage or updates to existing tests). CI runs the suite on each PR; please run it locally first:
pytest
# smoke-check discovery after adding a feature:
python -c "import melody_features as mf; assert 'your_feature' in mf.list_available_features()"
If you touch docs or docstrings that feed the API / catalogue, build the Sphinx site locally as well:
pip install -r docs/requirements.txt
cd docs && make dirhtml # open _build/dirhtml/index.html