Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
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.
Look through the GitHub issues for bugs. Anything tagged with "bug" and "help wanted" is open to whoever wants to implement it.
Look through the GitHub issues for features. Anything tagged with "enhancement" and "help wanted" is open to whoever wants to implement it.
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.
Extract a Portable Object Template (POT) file:
pybabel extract statemachine -o statemachine/locale/statemachine.potThen, 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.poThen 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 statemachineOn 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.pyThen open a pull request with your translation file.
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 :)
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/htmlNow you can serve the local documentation using a webserver, like the built-in included with python:
python -m http.server --directory docs/_build/htmlAnd 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.
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.
This project uses git-flow for release management and publishes to PyPI automatically via GitHub Actions when a version tag is pushed.
-
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.
The following steps use version X.Y.Z as a placeholder. Replace it with the actual version
number (e.g., 2.6.0).
git checkout develop
git pull origin develop
git flow release start X.Y.ZThis creates and switches to a release/X.Y.Z branch based on develop.
Update the version string in both files:
pyproject.toml— theversionfield under[project]statemachine/__init__.py— the__version__variable
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 statemachineThe `.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`
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).
uv run ruff check .
uv run ruff format --check .
uv run mypy statemachine/
uv run pytest -n autoAll checks must pass before committing.
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"git flow release finish X.Y.Z -m "vX.Y.Z"This will:
- Merge
release/X.Y.Zintomain - Create an annotated tag
X.Y.Zonmain - Merge
mainback intodevelop - Delete the
release/X.Y.Zbranch
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"`.
git tag latest -f
git push origin main develop --tags -fForce-pushing tags is needed to move the latest tag.
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 build - Publish to PyPI using trusted publishing
Monitor the workflow run at https://github.com/fgmacedo/python-statemachine/actions to
confirm the release was published successfully.
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-tagConfirm the rendered release at
https://github.com/fgmacedo/python-statemachine/releases/tag/vX.Y.Z.