Contributing
This document describes how to contribute to the development of this software.
Bug Reports
If you find a but we need to know about it so we can fix it. Please report your bugs on our GitHub Issues page.
Feature Requests
If you find AFMReader useful but think it can be improved you can make a feature request.
Code Contributions
If you would like to fix a bug or add a new feature that is great, Pull Requests are very welcome.
However, we have adopted a number of good software development practises that ensure the code and documentation is linted and that unit and regression tests pass both locally and on Continuous Integration. The rest of this page helps explain how to set yourself up with these various tools.
Virtual Environments
Use of virtual environments, particularly during development of Python packages, is encouraged. There are lots of options out there for you to choose from including...
Which you choose is up to you, although you should be wary of using the Miniconda distribution from Anaconda if any of your work is carried out for or in conjunction with a commercial entity.
uv
Developers are using the uv package manager to setup and control environments to which end a uv.lock
file is included in the repository. uv supports managing virtual environments so you may wish to install and use
this tool at the system level to manage your virtual environments for this package.
Cloning the Repository
Once you have setup your virtual environment you should clone the repository from GitHub
Install development
Once you have cloned the AFMReader repository you should install all the package along with all development and documentation dependencies in "editable" mode. This means you can test the changes you make in real time.
Git
Git is used to version control development of the package. The main
branch on GitHub and the pre-commit
hooks have protections in place that prevent committing/pushing directly to the main
branch. This means you should create a branch to undertake development or fix bugs.
Issues
Ideally an issue should have been created detailing the feature request. If it is a large amount of work this should be captured in an issue labelled "Epic" and the steps taken to achieve all work broken down into smaller issues.
Branch nomenclature
When undertaking work on a particular issue it is useful to use informative branch names. These convey information about
what the branch is for beyond simply "adding-feature-x
". We ask that you create the branch using your GitHub username,
followed by the issue number and a short description of the work being undertaken. For example
ns-rse/1021-add-xyz-support
as this allows others to know who has been undertaking the work, what issue the work
relates to and has an informative name as to the nature of that work.
Conventional Commits
We also ask that you try and follow the Conventional Commits pattern for titling your commits and where required include additional information on why you have made the changes you are committing.
Linting
Linting is the practice of following a consistent coding style. For Python that style is defined in PEP8. By following a consistent style across a code base it is easier to read and understand the code written by others (including your past self!). We use the following linters implemented as pre-commit hooks
- Python
- Black
- Blacken-docs
- flake8
- Numpydoc
- Ruff
- Other
- Codespell (Spelling across all filesyy)
- markdownlint-cli2 (Markdown)
- prettier (Markdown, YAML)
Pre-commit
Style checks are made using the pre-commit framework which is one of the development dependencies and
should have been installed in the previous step. You can check if its is installed in your virtual environment with pip
show pre-commit
. If you have pre-commit installed install the hook using...
This adds a file to .git/hooks/pre-commit
that will run all of the hooks specified in .pre-commit-config.yaml
. The
first time these are run it will take a little while as a number of virtual environments are downloaded for the first
time. It might be a good time to run these manually on the code base you have just cloned which should pass all checks.
These should all pass. Now whenever you try to make a git commit
these checks will run before the commit is made and
if any fail you will be advised of what has failed. Some of the linters such as Black and Ruff will
automatically correct any errors that they find and you will have to stage the files that have changed again. Not all
errors can be automatically corrected (e.g. Numpydoc validation and Pylint) and you
will have to manually correct these.
Docstrings
It is sensible and easiest to write informative docstrings when first defining your modules, classes and methods/functions. Doing so is a useful adie-memoire not only for others but your future self and with modern Language Servers that will, on configuration, show you the docstrings when using the functions it helps save time.
You will find your commits fail the numpydoc-validation pre-commit hook if you do not write docstrings and will be prompted to add one.
Testing
We use the pytest framework with various plugins in our testing suite. When correcting bugs and adding features at a bare minimum the existing tests should not fail. Where possible we would be grateful of contributions to the test suite. This means if an edge case has been identified and a solution derived a test is added that checks the edge case is correctly handled. For new features would ideally mean writing unit-tests to ensure each function or method works as intended and for larger classes that behaviour is as expected. Sometimes tests will need updating in light of bug fixes and features which is to be expected, but remember to commit updates to tests as well as to code to ensure the Continuous Integration tests pass.
Pytest-testmon
To shorten the feedback loop during development the pytest-testmon plugin is used as a pre-commit hook so that only the tests affected by the changes that are being committed are run. This requires that on first installing the package you create a local database of the state of the tests by running the following...
This creates the files .testmondata
which stores the current state of tests. Once created commits will only run
affected tests. However if your environment has changed, such as adding new packages or updating installed packages you
will have to recreate the database.
Pull Requests
Once you have made your changes and committed them you will at some point wish to make a Pull Request to merge
them into the main
branch.
In order to keep Git history clean and easier to understand you can perform an interactive git rebase -i
on your feature branch to squash related commits and tidy up your commit history.
When your branch is ready for merging with main
open a Pull Request. You can use the GitHub
keywords of close[s|d]
/fix[es|ed]
/ resolve[s|d]
followed by the issue number in the body of your
commit message which will change the status of the issue to "Closed" when the Pull Request is merged.
Pull Requests will be reviewed in a timely and hopefully constructive manner.