Contributing¶
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/fgmacedo/python-statemachine/issues.
If you are reporting a bug, please include:
Your operating system name and version.
Any details about your local setup that might be helpful in troubleshooting.
Detailed steps to reproduce the bug.
Fix Bugs¶
Look through the GitHub issues for bugs. Anything tagged with “bug” and “help wanted” is open to whoever wants to implement it.
Implement Features¶
Look through the GitHub issues for features. Anything tagged with “enhancement” and “help wanted” is open to whoever wants to implement it.
Write Documentation¶
Python State Machine could always use more documentation, whether as part of the official Python State Machine docs, in docstrings, or even on the web in blog posts, articles, and such.
Add a translation¶
Extract a Portable Object Template (POT) file:
pybabel extract statemachine -o statemachine/locale/statemachine.pot
Then, copy the template as a .po file into the target locale folder. For example, if you’re adding support for Brazilian Portuguese language, the code is pt_BR, and the file path should be statemachine/locale/pt_BR/LC_MESSAGES/statemachine.po:
cp statemachine/locale/statemachine.pot statemachine/locale/pt_BR/LC_MESSAGES/statemachine.po
Then open the statemachine.po and translate.
After translation, to get the new language working locally, you need to compile the .po files into .mo (binary format). Run:
pybabel compile -d statemachine/locale/ -D statemachine
On Linux (Debian based), you can test changing the LANGUAGE environment variable.
# If the last line is `Can't guess when in Won.` something went wrong.
LANGUAGE=pt_BR python tests/examples/guess_the_number_machine.py
Then open a pull request with your translation file.
Submit Feedback¶
The best way to send feedback is to file an issue at https://github.com/fgmacedo/python-statemachine/issues.
If you are proposing a feature:
Explain in detail how it would work.
Keep the scope as narrow as possible, to make it easier to implement.
Remember that this is a volunteer-driven project, and that contributions are welcome :)
Get Started!¶
Ready to contribute? Here’s how to set up python-statemachine for local development.
Install dependencies.
Fork the
python-statemachinerepository on GitHub.Clone the forked repository to your local machine by running::
git clone https://github.com/YOUR-USERNAME/python-statemachine.git.
Run
uv synconce to install all the development dependencies and create a virtual environment::uv sync --all-extras
Install the pre-commit validations:
pre-commit install
Create a branch for local development:
git checkout -b <name-of-your-bugfix-or-feature>
Make changes to the code.
Run tests to ensure they pass by running:
uv run pytest
Update the documentation as needed.
Build the documentation:
uv run sphinx-build docs docs/_build/html
Now you can serve the local documentation using a webserver, like the built-in included with python:
python -m http.server --directory docs/_build/html
And access your browser at http://localhost:8000/
If you’re specially writting documentation, I strongly recommend using
sphinx-autobuildas it improves the workflow watching for file changes and with live reloading:uv run sphinx-autobuild docs docs/_build/html --re-ignore "auto_examples/.*"
Sometimes you need a full fresh of the files being build for docs, you can safely remove all automatically generated files to get a clean state by running:
rm -rf docs/_build/ docs/auto_examples
Commit your changes and push them to your forked repository:
git add -A . git commit -s -m "Your detailed description of your changes." git push origin name-of-your-bugfix-or-feature
Create a pull request on the original repository for your changes to be reviewed and potentially merged. Be sure to follow the project’s code of conduct and contributing guidelines.
Use
exitto leave the virtual environment.
Pull Request Guidelines¶
Before you submit a pull request, check that it meets these guidelines:
The pull request should include tests.
If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in the next release notes.
Consider adding yourself to the contributor’s list.
The pull request should work for all supported Python versions.
Releasing a New Version¶
This project uses git-flow for release management and publishes to PyPI automatically via GitHub Actions when a version tag is pushed.
Prerequisites¶
You must be on the
developbranch with a clean working tree.git-flowmust be installed and initialized:brew install git-flow # macOS git flow init # use main for production, develop for next release
All changes intended for the release must already be merged into
develop.
Step-by-step release process¶
The following steps use version X.Y.Z as a placeholder. Replace it with the actual version
number (e.g., 2.6.0).
1. Start the release branch¶
git checkout develop
git pull origin develop
git flow release start X.Y.Z
This creates and switches to a release/X.Y.Z branch based on develop.
2. Bump the version number¶
Update the version string in both files:
pyproject.toml— theversionfield under[project]statemachine/__init__.py— the__version__variable
3. Update translations¶
Extract new translatable strings, merge them into all existing .po files, translate the
new entries, and compile:
uv run pybabel extract statemachine -o statemachine/locale/statemachine.pot
uv run pybabel update -i statemachine/locale/statemachine.pot -d statemachine/locale/ -D statemachine
# Edit each .po file to translate new empty msgstr entries
uv run pybabel compile -d statemachine/locale/ -D statemachine
Note
The .pot and .mo files are git-ignored. Only the .po source files are committed.
The compiled .mo files may cause test failures if your system locale matches a translated
language (error messages will appear translated instead of in English). Delete them after
verifying translations work: rm -f statemachine/locale/*/LC_MESSAGES/statemachine.mo
4. Write release notes¶
Create docs/releases/X.Y.Z.md documenting all changes since the previous release. Include
sections for new features, bugfixes, performance improvements, and miscellaneous changes.
Reference GitHub issues/PRs where applicable.
Add the new file to the toctree in docs/releases/index.md (at the top of the appropriate
major version section).
Update any related documentation pages (e.g., if a bugfix adds a new behavior that users should know about).
5. Run linters and tests¶
uv run ruff check .
uv run ruff format --check .
uv run mypy statemachine/
uv run pytest -n auto
All checks must pass before committing.
6. Commit¶
Stage all changed files and commit. The pre-commit hooks will run ruff, mypy, and pytest automatically.
git add <files>
git commit -m "chore: prepare release X.Y.Z"
7. Finish the release¶
git flow release finish X.Y.Z -m "vX.Y.Z"
This will:
Merge
release/X.Y.ZintomainCreate an annotated tag
X.Y.ZonmainMerge
mainback intodevelopDelete the
release/X.Y.Zbranch
Note
If tagging fails (e.g., GPG or editor issues), create the tag manually and re-run:
git tag -a X.Y.Z -m "vX.Y.Z" then git flow release finish X.Y.Z -m "vX.Y.Z".
8. Update the latest tag and push¶
git tag latest -f
git push origin main develop --tags -f
Force-pushing tags is needed to move the latest tag.
9. Verify the release¶
The tag push triggers the release GitHub Actions workflow (.github/workflows/release.yml),
which will:
Check out the tag
Run the full test suite
Build the sdist and wheel with
uv buildPublish to PyPI using trusted publishing
Monitor the workflow run at https://github.com/fgmacedo/python-statemachine/actions to
confirm the release was published successfully.
10. Publish the GitHub release¶
Create the GitHub release from the freshly pushed tag using the release notes file as the body. Two adjustments are needed when going from MyST/Sphinx markdown to GitHub-flavored markdown:
Convert MyST directives (
```{note},```{warning}, etc.) to GitHub’s alert syntax (> [!NOTE],> [!WARNING]) or to plain blockquotes.Rewrite intra-docs links. Relative links like
[3.1.0 release notes](3.1.0.md)resolve on ReadTheDocs but not on github.com. Replace them with absolute URLs against the matching tag, e.g.https://github.com/fgmacedo/python-statemachine/blob/vX.Y.Z/docs/releases/X.Y.Z.md. Avoid linking tohttps://python-statemachine.readthedocs.io/en/vX.Y.Z/immediately after publishing because the ReadTheDocs build for the new tag may still be in progress.
Then create the release. Use the converted notes as the body:
gh release create vX.Y.Z \
--title "vX.Y.Z" \
--notes-file /tmp/release-X.Y.Z-notes.md \
--target main \
--verify-tag
Confirm the rendered release at
https://github.com/fgmacedo/python-statemachine/releases/tag/vX.Y.Z.