💅
Oida
Oida is Oda's linter that enforces code style and modularization in our Django projects.
Warning This project is still in early development. Expect breaking changes.
Installation
Oida requires Python 3.10 or newer and can be installed from PyPI:
pip install oida
Usage
Oida is mainly intended to be used as a flake8 plugin. Once you have installed Oida and flake8 you can enable the linting rules in the flake8 config:
[flake8]
extend-select = ODA
This will enable all our linting rules. You can also enable them one by one, for a complete list of the various violations we report on see the oida/checkers/base.py file.
Oida also provides its own command line tool. This can also be used to run the
linting rules, but its main purpose is to provide tools to help transitioning
an existing codebase into one that's modularized. For details see oida --help, but below is a quick summary of the provided commands:
oida lint
This command is just another way of running the same checks that can be run
through flake8. This command supports # noida comments to ignore specific
violations on individual lines (see below for details).
oida config
This command will generate configuration files for components, which will be automatically pre-filled with ignore rules for isolation violations. See below for details on the configuration files.
oida componentize
This command moves or renames a Django app, for example for moving an app into a component. In addition to moving the files in the app it also updates (or adds if needed) the app config and updates imports elsewhere in the project.
Concepts
Oida is a static code analyzer, that also looks at the project structure. The codebase is expected to be structured with a project as the top package and then Django apps or components as submodules below this, something like this:
project/
├── pyproject.toml
├── setup.cfg
└── project/
├── __init__.py
├── my_component/
│ ├── __init__.py
│ ├── first_app/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── ...
│ ├── second_app/
│ │ ├── __init__.py
│ │ └── ....
│ └── ...
├── third_app/
│ ├── __init__.py
│ └── ...
└── ...
A component is basically a collection of Django apps. Oida will enforce isolation of the apps inside the component, meaning that no code elsewhere in the project will be allowed to import from the apps inside a component. Instead a component should expose a public interface at the top level.
Because Oida is intended to be introduced in mature projects it's also possible
to grandfather in existing violations. That's done through a confcomponent.py
file placed at the root of the component. The only allowed statement in this
file is assigning a list of string literals to ALLOWED_IMPORTS:
ALLOWED_IMPORTS = ["my_component.app.models.MyModel"]
This will silence any warnings when importing my_component.app.models.MyModel
in the current app/component.
Ignoring Violations with # noida Comments
You can use inline # noida comments to ignore specific violations on individual lines:
# Ignore all violations on this line
from project.other_component.app.models import Model # noida
# Ignore a specific violation code
from project.other_component.app.models import Model # noida: ODA005
# Ignore multiple specific violation codes
from project.other_component.app.models import Model # noida: ODA005, ODA001
The # noida comments work with the oida lint command. Note that we use noida
instead of noqa to avoid conflicts with ruff, which doesn't accept noqa comments
that don't match ruff rules.
Checks
These are the checks currently implemented in Oida:
- component-isolation: Checks that relative imports do not cross app boundaries.
- config: Checks that component configuration files are valid
- relative-imports: Checks that no imports are done across components.
- django-select-for-update: Checks that all
.select_for_update()usage sets theofargument, to prevent unintended locking of tables - service-selector-keyword-only: Checks that all functions in service and selector
modules use keyword-only parameters (with the
*separator). This applies to files namedservices.pyorselectors.py, or files withinservices/orselectors/directories. Inner functions and methods of nested classes are excluded from this check.
Metadata
Release files for oida 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| oida-0.3.2.tar.gz | 20.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| oida-0.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.2 kB
Release files / oida-0.3.2.tar.gz
| Download URL | oida-0.3.2.tar.gz |
|---|---|
| Size | 20.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9d3c76193a1a780adb3de8f2e511dc9de3a5ecb76fb74aae327e99a23b54d21e
|
|
BLAKE2b-256 checksum How to use checksums |
c6839177ac7ed1dbd60dc105d70c19d268cea609ebfc61f7746b4c2660e56a9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.12.3 Linux/6.17.0-1015-azure
|
Release files / oida-0.3.2-py3-none-any.whl
| Download URL | oida-0.3.2-py3-none-any.whl |
|---|---|
| Size | 26.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bd9ef5c92855e2c5db4145dd945452a3c0f0da66371105e2b5c19a7c47df5bcf
|
|
BLAKE2b-256 checksum How to use checksums |
873f2cf06ce55cae64562ccbf85bdc6053d977981e02c069225fe13bfd42ccfd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.12.3 Linux/6.17.0-1015-azure
|
Security for oida 0.3.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.