If you have questions about using Mido, contributing code or suggestions for how to make contributing easier, please write at

Bugs & Feature Requests


If you don’t have a precise idea, please use the questions section outlined above instead of opening an issue.

If you encounter a bug that is reproducible or want to suggest a new feature - including its implementation details - that would fit the project nicely, feel free to open an issue at

Please provide as much information as possible to allow us to analyze, including but not limited to:

  • Operating system name & version

  • Python version

  • mido package version & installation method (Distribution repository, PyPI, source…)

  • backend used (amidi, portmidi, rtmidi, PyGame… Defaults to python-rtmidi.)

Forking & Pull Requests

The project welcomes all contributions!

If you wish to make a change, be it code or documentation, please fork the repository from and send your pull request to

Your changes will be reviewed by a maintainer and integrated for publication in the next version of mido once approved.



For general usage, see Installing.

If you wish to install from source, run the following command from the sources root directory:

python3 -m pip install --editable .

Or, alternatively if you want to use ports:

python3 -m pip install --editable .[ports-rtmidi]


No support will be provided if you install from source.



We recommend that you first setup a virtual environment to avoid conflicts with already installed files.

Then, to install the development dependencies, you can run the following command from inside your virtual environment:

python3 -m pip install --editable .[dev]

Or, alternatively, if you want to use ports:

python3 -m pip install --editable .[dev,ports-rtmidi]

This will install all needed dependencies for linting, testing, documentation generation and publishing releases.

Code Checks


The following code checks are done automatically using a GitHub Actions Workflow (Defined in .github/workflow/tests.yml) for each push to the main branch and each Pull Request.

It’s good practice to check your changes locally before submitting.


Linting is done with ruff. Its configuration can be found in pyproject.toml.

You can lint your code using:

ruff check .


pytest is used for unit testing. The tests are found in tests/test_*.py. The default configuration is declared in the tool.pytest.ini_options section of pyproject.toml.

The test suite can be run using the command:


Checking the Release Manifest

To make sure the repository and source code manifest ( are in sync:

check-manifest --verbose

Building the Documentation

The documentation is generated using Sphinx.

To generate the HTML documentation:

sphinx-build -j auto -q -W -E --keep-going docs docs/_build

If you wish to build a PDF version for local use:

  1. Install a LaTeX distribution

  2. Install ImageMagick

  3. use:

    sphinx-build -M latexpdf docs docs/_build

You’ll find the resulting PDF file at docs/_build/latex/Mido.pdf.

Once generated and copied in a safe place, you may want to remove the build artifacts:

sphinx-build -M clean docs docs/_build

Testing MIDI File Support

Test Files

The Lakh MIDI Dataset is a great resource for testing the MIDI file parser.


The processes are now automated.


The whole team has access to manual publishing to PyPI and Read the Docs in case of automation defect.


To generate the official documentation, we use Read the Docs integration services for GitHub. Every time a new commit is pushed or merged onto our main development branch on GitHub, the latest version of the documentation is updated by Read the Docs. Each time a new version is tagged, the new documentation version is created, built, published and eventually promoted to stable following Semantic Versioning. The stable version of the documentation is the one served by default if no specific version is chosen.

We also build a mirror of the current main development branch documentation using a GitHub Workflow and hosted on GitHub pages.

All of this is defined by .github/workflow/documentation.yml


The process uses GitHub Action Workflow defined by .github/workflow/release.yml and is triggered upon receiving a tag.


Make sure all the tests pass, documentation has been updated and everything is in good order before proceeding.


The version number should be PEP 440 & SemVer compliant.

X.Y.Z is the version, for example 1.1.18 or 1.2.0.

  1. update the changelog in docs/changes.rst. The following commands may prove useful to retrieve all Pull Requests & all commits:

    previous_release_tag=git describe --abbrev=0
    git log --oneline --merges --reverse "${previous_release_tag}.."
    git log --oneline --no-merges --reverse "${previous_release_tag}.."
  2. update version and date in docs/changes.rst

  3. commit the changes:

    git commit -a -c "Prepare <X.Y.Z> release."
  4. set the version number by tagging the release:

    git tag -a <X.Y.Z> -m "mido version <X.Y.Z>"


    We use an annotated tag here to retain all information about the tagger and create a proper object in the GIT database instead of a commit alias.

  5. don’t forget to push your changes including the tags to GitHub to trigger the auto-release process:

    git push --tags

Manual steps (Recovery)


Only use if the automatic process fails for some reason.

  1. Prepare a clean environment:

    git clone --branch <X.Y.Z> --single-branch mido-<X.Y.Z>
    cd mido-<X.Y.Z>
    python3 -m venv mido-build
  2. Build:

    source mido-build/bin/activate
    python3 -m pip install --upgrade pip setuptools wheel build twine
    python3 -m build
  3. Publish on Test PyPI:

    python3 -m build
    twine upload --repository testpypi dist/*
  4. Check that the published package is good:

    python3 -m pip install --index-url --no-deps mido
    python3 -c "import mido; print(mido.version_info)"


    Now would be a good time to run some integration tests once we have them.

  5. Publish on PyPI:

    twine upload dist/*


    This is the most critical step of the process. This cannot be undone. Make sure everything is in good order before pressing the “big red button”!