6. 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.
6.1. Code of Conduct
By participating in this project, you agree to abide by the PyAFV Code of Conduct.
6.2. How to contribute
6.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
6.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 alluvcommands to isolate the project.The current version uses Cython to translate
.pyxfiles 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.cfgfile at the repository root# setup.cfg [build_ext] compiler=mingw32
This is equivalent to pass the
--compiler=mingw32flag when invoking build commands such aspython setup.py build_ext --inplace. To avoid accidentally committing this ad hoc file, do not modify.gitignore; instead, add it to local.git/info/excludein the repository, which functions like.gitignore.
6.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 thepyafv.FiniteVoronoiSimulatorinstance.
6.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.
6.3. Coding standards
Single responsibility: Keep functions small and focused on one task. Each function should do one thing well.
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.
Minimize dependencies: Avoid adding new libraries unless absolutely necessary. If required, discuss with maintainers first.
Code style: Follow PEP 8 style guidelines for Python code.
6.4. Documentation requirements
Type annotations: Use type hints for function arguments and return values.
Array dimensions: Add comments indicating dimensions for multidimensional arrays:
positions = np.zeros((100, 2)) # N x dimension
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
6.5. Writing tests
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.
6.5.1. Testing strategies (in order of preference)
Exact solutions: Compare numerical results to exact analytical solutions.
Independent implementations: Compare results from two independent numerical methods.
Regression tests: Ensure the function runs and produces consistent results with pre-computed references.
Sanity checks: Verify that results make physical sense (e.g., energies decrease after optimization).
6.5.2. Benchmarking
There is also a set of lightweight benchmarks in tests using pytest-benchmark, e.g., test_bench_build.py compares the runtimes of the Cython and pure-Python backends. 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 an example here). You should write benchmarks for any new performance-critical code you add.
6.6. Featured examples
To run current example scripts and notebooks in examples/, install all optional dependencies (e.g., tqdm, jupyter) via uv sync --extra examples or uv sync --all-extras (add the --inexact flag to avoid removing installed packages).
Extra dependencies: examples
Package |
Minimum version |
Usage |
|---|---|---|
tqdm |
4.67.1 |
Progress bars during calculations |
jupyter |
1.1.0 |
Jupyter Notebook / JupyterLab |
ipywidgets |
8.1.5 |
Jupyter HTML widgets |
Then you can simply run the scripts with
(.venv) $ uv run <script_name>.py
For developers to launch Jupyter Notebook: after
uvhas synced all extra dependencies, start Jupyter withuv run jupyter notebook. Do not use your system-level Jupyter, as the Python kernel of the currentuvenvironment is not registered there.
Note
Jupyter notebooks and media are stored via Git LFS. If you clone the repository without Git LFS installed, these files will appear as small text pointers. You can either install Git LFS to fetch them automatically or download the files manually (e.g., download the repository as a ZIP archive) from the GitHub web interface.
6.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 pytestCode follows the coding standards above
Relevant documentation is updated (README, examples, etc.)
The branch is up to date with
main
6.7.1. Pull request process
Push your feature branch to your fork:
(.venv) $ git push origin your-feature-name
Go to the PyAFV repository and click “Pull Request”.
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
Be responsive to feedback from reviewers and be prepared to make changes.
6.8. Reporting issues
When reporting bugs or requesting features:
Search existing issues to avoid duplicates
Use a clear title that describes the problem
Provide details:
For bugs: steps to reproduce, expected vs. actual behavior, error messages, environment details
For features: use case, proposed implementation (if any)
Include code examples when relevant (minimal reproducible examples are best)
6.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
6.10. Questions?
If you have questions about contributing, feel free to:
Open an issue on GitHub
Start a discussion in GitHub Discussion
Contact the maintainer via email: ww000721@gmail.com
Thank you for helping make PyAFV better!