5. Contributing to PyAFV

First off, THANK YOU for considering contributing to PyAFV! We welcome contributions from the community.

Before working on a feature or major change, please raise an issue and/or get in touch with the developers. They may have insights on how to implement the feature or useful advice to save you time.

Note

Much of this guide is based on the pyqmc CONTRIBUTING.md, which itself draws from this excellent guide.

5.1. Code of Conduct

By participating in this project, you agree to abide by the PyAFV Code of Conduct.

5.2. How to contribute

5.2.1. Create a fork

Click the “Fork” button on the PyAFV GitHub page: https://github.com/wwang721/pyafv

Then clone your fork to your local machine and enter the repository directory

(.venv) $ cd pyafv

5.2.2. Set up your development environment

PyAFV uses uv for Python package management—a single tool to replace pip (⚡️10-100x faster), venv, and even conda.

Tip

If you’d like to use your own Python, ensure the which python version meets the requirement so uv doesn’t automatically download a different interpreter; otherwise, I recommend letting uv manage everything, including the Python interpreter.

After cloning, install PyAFV in editable mode and synchronize dependencies:

(.venv) $ uv sync

This installs the core package dependencies along with pytest required for development and testing.

Note

  • You can install additional packages as needed using uv add <package_name>.

  • In some environments (like HPC clusters), global Python path can contaminate the project environment. You may need to add the PYTHONPATH="" prefix to all uv commands to isolate the project.

  • The current version uses Cython to translate .pyx files into .cpp, (and therefore requires a working C/C++ compiler), though a fallback backend (based on early pure-Python release) is also implemented.

  • For Windows MinGW GCC users (rather than MSVC), add a setup.cfg file at the repository root

    # setup.cfg
    [build_ext]
    compiler=mingw32
    

    This is equivalent to pass the --compiler=mingw32 flag when invoking build commands such as python setup.py build_ext --inplace. To avoid accidentally committing this ad hoc file, do not modify .gitignore; instead, add it to local .git/info/exclude in the repository, which functions like .gitignore.

5.2.3. Create a feature branch and start development

Always branch from main, not from another feature branch

(.venv) $ git checkout main
(.venv) $ git checkout -b your-feature-name

You may then begin editing the codebase and developing new features.

Note

If you modify any *.pyx Cython source files, you must reinstall the package to ensure the changes take effect: uv sync --reinstall-package pyafv --inexact (the --inexact flag prevents uv from removing any installed packages).

  • If the compiled C/C++ extension is accidentally removed or corrupted (you will see a RuntimeWarning about falling back to the pure-Python implementation), you can also reinstall the package.

  • For the legacy pure-Python implementation with no C/C++ compiled dependencies, see v0.1.0 (also on GitLab). Starting from PyAFV v0.3.4, the pure-Python backend can be selected by passing backend="python" when creating the pyafv.FiniteVoronoiSimulator instance.

5.2.4. Keeping your fork up to date

Add the upstream repository as a remote (do this once):

(.venv) $ git remote add upstream https://github.com/wwang721/pyafv.git
(.venv) $ git remote -v

To sync with upstream (do this regularly):

(.venv) $ git fetch upstream
(.venv) $ git checkout main
(.venv) $ git merge upstream/main

If needed, update your feature branch with the latest changes:

(.venv) $ git checkout your-feature-name
(.venv) $ git rebase main

Note

We use rebase to keep the commit history clean.

5.3. Coding standards

  1. Single responsibility: Keep functions small and focused on one task. Each function should do one thing well.

  2. Avoid Python loops: Use numpy vectorized operations to avoid Python’s performance overhead. Operate on batches of data rather than looping. Performance-critical code may be accelerated using Cython.

  3. Minimize dependencies: Avoid adding new libraries unless absolutely necessary. If required, discuss with maintainers first.

  4. Code style: Follow PEP 8 style guidelines for Python code.

5.4. Documentation requirements

  1. Type annotations: Use type hints for function arguments and return values.

  2. Array dimensions: Add comments indicating dimensions for multidimensional arrays:

positions = np.zeros((100, 2))  # N x dimension
  1. Docstrings: Each function should have a docstring following PEP 257 and written in either Google style (currently used) or Numpy style so that it can be parsed by Sphinx via sphinx.ext.napoleon. The docstring should explain:

    • Purpose of the function

    • All input parameters

    • Return values

    • Any exceptions raised

5.5. Writing tests

Tests on all platforms pytest Codecov

Tests are located in the tests/ directory. Run the test suite with

(.venv) $ uv run pytest

For coverage reports:

(.venv) $ uv run pytest --cov

Current CI status of the test suite, run via GitHub Actions on Python 3.12 (with additional test jobs covering all supported platforms and Python versions), is shown in the badges above.

Note

  • A comparison against the MATLAB implementation from Ref. [1] is included in current test suite.

  • Unlike v0.1.0, the current test suite is designed to raise errors if the Cython-compiled C/C++ backend is not available, even though a pure-Python fallback implementation is provided and tested.

  • Pytest and related plugins (pytest-cov, pytest-benchmark) are included in the dev dependency group and are installed by default when running uv sync.

5.5.1. Testing strategies (in order of preference)

  1. Exact solutions: Compare numerical results to exact analytical solutions.

  2. Independent implementations: Compare results from two independent numerical methods.

  3. Regression tests: Ensure the function runs and produces consistent results with pre-computed references.

  4. Sanity checks: Verify that results make physical sense (e.g., energies decrease after optimization).

5.5.2. Benchmarking

There is also an implementation of small benchmarks in tests/test_benchmarks.py comparing the Cython and pure-Python backends using pytest-benchmark. To run them:

(.venv) $ uv run pytest --benchmark-only --benchmark-warmup on --benchmark-histogram

This will display the benchmark results and generate an SVG histogram file in the current directory (see here). You should write benchmarks for any new performance-critical code you add.

5.7. Submitting a pull request

Before submitting, ensure you have completed this checklist:

  • All new functions are documented with docstrings and type annotations

  • Tests are written for the new feature or bug fix

  • All tests pass: uv run pytest

  • Code follows the coding standards above

  • Relevant documentation is updated (README, examples, etc.)

  • The branch is up to date with main

5.7.1. Pull request process

  1. Push your feature branch to your fork:

(.venv) $ git push origin your-feature-name
  1. Go to the PyAFV repository and click “Pull Request”.

  2. In your pull request description:

    • Clearly describe the new feature or bug fix

    • Reference any related issues (e.g., “Fixes #123”)

    • For bug fixes, provide a minimal example demonstrating the bug and how the fix resolves it

    • For new features, explain the use case and provide example usage

  3. Be responsive to feedback from reviewers and be prepared to make changes.

5.8. Reporting issues

When reporting bugs or requesting features:

  1. Search existing issues to avoid duplicates

  2. Use a clear title that describes the problem

  3. Provide details:

    • For bugs: steps to reproduce, expected vs. actual behavior, error messages, environment details

    • For features: use case, proposed implementation (if any)

  4. Include code examples when relevant (minimal reproducible examples are best)

5.9. Code review process

All submissions require review before merging. Reviewers will check:

  • Code quality and adherence to coding standards

  • Test coverage and quality

  • Documentation completeness

  • Performance implications

  • Compatibility with existing code

5.10. Questions?

If you have questions about contributing, feel free to:

Thank you for helping make PyAFV better!