Contribution guide๐Ÿ”—

Thanks for taking the time to contribute! MNE-LSL is an open-source project sustained mostly by volunteer effort. We welcome contributions from anyone as long as they abide by our Code of Conduct.

You can propose a change; a bugfix, a docstring improvement or a new feature; by following those steps:

  • Fork the MNE-LSL repository on GitHub

  • Clone your fork locally

  • (optional, recommended) Create a new branch for your changes

  • Make your changes locally and push them to your fork

  • Open a pull request with a clear title and description

Install in editable mode๐Ÿ”—

To modify MNE-LSL, it is recommended to install it in a separate environment in editable mode. This way, you can test your changes without having to reinstall the package each time. To install MNE-LSL in editable mode, run:

$ pip install -e .[all]

Note

The [all] extra installs all optional dependencies, including those required for testing and documentation.

Note

This command will build liblsl and will thus require:

    1. A clone of the mne-lsl repository including the submodules

    1. Compilers and build tools installed on your system

Code style๐Ÿ”—

MNE-LSL enforces style rules which are checked by the pre-commit framework. The rules are configured in the projectโ€™s pyproject.toml. To install the pre-commit hooks, run:

$ pre-commit install

Once installed, the hooks will run automatically before each commit. If you want to manually run the hooks, you can use:

$ pre-commit run --all-files

Note

If a PR is opened with failing pre-commit checks, the CIs will attempt to fix the failures automatically with an autofix commit.

Documentation๐Ÿ”—

The documentation uses Sphinx and numpydoc to generate the HTML pages. The numpydoc convention is used. To build the documentation locally, navigate to the doc directory and run:

$ make html

The HTML pages will be generated in the doc/_build/html directory. You can run the following command to open a browser with the documentation:

$ make view

Finally, building the tutorials and examples is a slow process. To skip running the examples and tutorials, run:

$ make html-noplot

Tests๐Ÿ”—

The unit tests are written using pytest and can be run from the root of the repository with:

$ pytest mne_lsl

When adding a feature or fixing a bug, it is important to write a short test to ensure that the code behaves as expected. Separate features should be tested in separate tests to help keep the test function code short and readable. Finally, a test should use short files and run as quickly as possible. Any tests that takes more than 5 seconds to run locally should be marked with the @pytest.mark.slow decorator.

Tests are stored in the tests directory in each module. As much as possible, the tests within a module should not test a different module, but this is obviously not simple or mandatory as many modules require the creation of mock LSL stream to run the tests.

Fixtures used in a single module should be defined within the module itself. If a fixture is used in multiple modules, it should be defined in the mne_lsl/conftest.py file.

Finally, writing reliable tests with mock LSL stream or StreamInlet and StreamOutlet can be tricky. Here are a couple of tips to help you write reliable tests:

  • If you create a mock LSL stream with PlayerLSL, use the fixture chunk_size which returns a large chunk size suitable for CIs.

  • If you need to create inlets or outlets, always close the inlets first before closing or destroying the outlets.

    Note

    A StreamLSL or PlayerLSL have underlying LSL inlets and outlets. Donโ€™t forget to call mne_lsl.stream.StreamLSL.disconnect() followed by mne_lsl.player.PlayerLSL.stop() at the end of your test.

  • If you need to create StreamInlet or StreamOutlet directly, use the close_io fixture which returns a function to call at the end of your test to remove the inlets and outlets.

  • If the objects in your test use separate threads for acquisition or processing, donโ€™t forget to include sleep periods to ensure that the threads have time to work.