Welcome to the boa-restrictor - a custom Python linter from Ambient
- PyPI
- GitHub
- Full documentation
- Creator & Maintainer: Ambient Digital
This rule enforces that functions and methods don't contain any positional arguments.
This will make refactorings easier, is more explicit, and you avoid the boolean bug trap.
Wrong:
def my_func(a, b):
pass
Correct:
def my_func(*, a, b):
pass
This rule will enforce that you add a return type-hint to all methods and functions that contain a return
statement.
This way we can be more explicit and let the IDE help the next developer because it will add warnings if you use
wrong types.
Wrong:
def my_func(a, b):
return a * b
Correct:
def my_func(a, b) -> int:
return a * b
This rule will enforce that you never import a datetime object from the datetime module, but instead import the datetime module and get the object from there.
Since you can't distinguish in the code between a datetime
module and datetime
object without looking at the
imports, this leads to inconsistent and unclear code.
Importing the date
object can cause a namespace conflict with the Django template tag date
, therefore this is not
allowed as well.
Wrong:
from datetime import datetime
my_datetime = datetime(2024, 9, 19)
Correct:
import datetime
my_datetime = datetime.datetime(2024, 9, 19)
Note, that other imports from the datetime
module like UTC
are allowed since there are no known conflicts.
This rule will enforce that you use the kw_only
parameter in every dataclass decorator.
This will force the developer to set all dataclass attributes as kwargs instead of args, which is more explicit and easier to refactor.
Wrong:
from dataclasses import dataclass
@dataclass
class MyDataClass:
pass
Correct:
from dataclasses import dataclass
@dataclass(kw_only=True)
class MyDataClass:
pass
Add the following to your .pre-commit-config.yaml file:
- repo: https://github.com/ambient-innovation/boa-restrictor
rev: v1.2.1
hooks:
- id: boa-restrictor
args: [ --config=pyproject.toml ]
Now you can run the linter manually:
pre-commit run --all-files boa-restrictor
You can easily exclude certain files, for example, your tests, by using the exclude
parameter from pre-commit
:
- repo: https://github.com/ambient-innovation/boa-restrictor
rev: v1.2.1
hooks:
- id: boa-restrictor
...
exclude: |
(?x)^(
/.*/tests/.*
|.*/test_.*\.py
)$
You can disable any rule in your pyproject.toml
file as follows:
[tool.boa-restrictor]
exclude = [
"PBR001",
"PBR002",
]
You can disable rules on a per-file-basis in your pyproject.toml
file as follows:
[tool.boa-restrictor.per-file-excludes]
"*/tests/*" = [
"PBR001",
"PBR002",
]
"scripts/*" = [
"PBR003",
]
Take care that the path is relative to the location of your pyproject.toml. This means that example two targets all
files living in a scripts/
directory on the projects top level.
If you are using ruff
, you need to tell it about our linting rules. Otherwise, ruff will remove all # noqa
statements from your codebase.
[tool.ruff.lint]
# Avoiding flagging (and removing) any codes starting with `PBR` from any
# `# noqa` directives, despite Ruff's lack of support for `boa-restrictor`.
external = ["PBR"]
https://docs.astral.sh/ruff/settings/#lint_extend-unsafe-fixes
- Create a Python virtualenv and activate it
- Install "pip-tools" with
pip install -U pip-tools
- Compile the requirements with
pip-compile --extra dev, -o requirements.txt pyproject.toml --resolver=backtracking
- Sync the dependencies with your virtualenv with
pip-sync
- Create a new branch for your feature
- Change the dependency in your requirements.txt to a local (editable) one that points to your local file system:
-e /Users/workspace/boa-restrictor
or via pippip install -e /Users/workspace/boa-restrictor
- Ensure the code passes the tests
- Create a pull request
-
Run tests
pytest --ds settings tests
-
Check coverage
coverage run -m pytest tests coverage report -m
We use pre-push hooks to ensure that only linted code reaches our remote repository and pipelines aren't triggered in vain.
To enable the configured pre-push hooks, you need to install pre-commit and run once:
pre-commit install -t pre-push -t pre-commit --install-hooks
This will permanently install the git hooks for both, frontend and backend, in your local
.git/hooks
folder.
The hooks are configured in the .pre-commit-config.yaml
.
You can check whether hooks work as intended using the run command:
pre-commit run [hook-id] [options]
Example: run single hook
pre-commit run ruff --all-files --hook-stage push
Example: run all hooks of pre-push stage
pre-commit run --all-files --hook-stage push
- To build the documentation, run:
sphinx-build docs/ docs/_build/html/
. - Open
docs/_build/html/index.html
to see the documentation.
- Fetch the latest changes in GitHub mirror and push them
- Trigger new build at ReadTheDocs.io (follow instructions in admin panel at RTD) if the GitHub webhook is not yet set up.
-
Update documentation about new/changed functionality
-
Update the
Changelog
-
Increment version in main
__init__.py
-
Create pull request / merge to main
-
This project uses the flit package to publish to PyPI. Thus, publishing should be as easy as running:
flit publish
To publish to TestPyPI use the following to ensure that you have set up your .pypirc as shown here and use the following command:
flit publish --repository testpypi
To be able to use the latest version in pre-commit, you have to create a git tag for the current commit. So please tag your commit and push it to GitHub.
Please note that this package supports the ambient-package-update.
So you don't have to worry about the maintenance of this package. This updater is rendering all important
configuration and setup files. It works similar to well-known updaters like pyupgrade
or django-upgrade
.
To run an update, refer to the documentation page of the "ambient-package-update".