Coding conventions shared by all RERO+ projects. They are enforced by ruff for Python and ESLint for TypeScript, with the same configuration everywhere: line-length = 120, and config.py excluded from the checks.
Since mid-2025, every RERO+ Python project uses ruff to lint and format. Here is how to configure VSCode so that your code always conforms:
- Install the ruff extension
- Go to VSCode Settings CTRL+Shift+P "Preferences: Open User Settings (JSON)"
- Use these settings for python:
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.wordWrap": "off",
"editor.rulers": [120],
"editor.tabSize": 4,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},This will format and lint your Python code with ruff every time you save a python file. It will also add a vertical line at 120 characters.
Once the extension is installed and you have a .venv with ruff, the editor will inform you of any problems with the linter.
The rules are defined in the pyproject.toml of each project under [tool.ruff], and are deliberately kept identical across projects. Add an exception there if you really need one — and say why in the PR.
To format the files in your project
uv run poe formatTo check linting on the whole project:
uv run poe lintPython imports can be reorganized, sorted, and changed during development. ruff will sort and clean your imports automatically.
Here are some best practices about Python imports.
Python allows importing resources using a path that is either absolute or relative to the current file. The guideline is:
- Always give priority to absolute paths when importing resources/classes/methods from outside the current module.
- Use relative path when importing resources/classes/methods of the same module.
In the file rero_ils/modules/items/api/record.py:
# These imports reference classes/methods from the `items` module.
# As we stay into the same module, we use relative imports
from .api import ItemsSearch
from ..models import TypeOfItem
from ..utils import item_pid_to_object
# These imports reference classes/methods from outside the `items` module.
# Use absolute imports in this case, even within the same project
from rero_ils.modules.api import IlsRecord
from rero_ils.modules.location.api import Location
from rero_ils.modules.operation_logs.extensions import UntrackedFieldsOperationLogObserverExtension
from rero_ils.modules.utils import date_string_to_utc, extracted_data_from_refIntroduced since Python 3.5, typing allows to specify types for variables or functions. For RERO+ projects, this feature is not recommended, since it doesn't add any value to the code.
Exporting long lists of results from an ES query implies using scan() instead of execute(). execute() uses invenio-record-rest but not scan(). This means that we have to duplicate code when using scan().
- The REST layer is still
invenio-records-rest. When we need to stream an export withscan(), we use a specific mounting point. - Long-term, we can begin to migrate some resources to
invenio-records-resources, which is more flexible and allows class supercharging. - To avoid high server loads, limit the number of results for each export with a config variable. Above this limit, streaming is not allowed and requires an external task.
scan()can create ElasticSearch timeouts. Each export task should be possible with a CLI that avoids any nginx or ES timeout.
The three Angular projects (ng-core, rero-ils-ui, sonar-ui) use ESLint, with an eslint.config.js at the root of each.
Configure your editor so that it shows you errors and warnings directly in the code:
- Install the eslint extension
- Go to VSCode Settings CTRL+Shift+P "Preferences: Open User Settings (JSON)"
- Use these settings:
"typescript.validate.enable": false,
"css.lint.unknownAtRules": "ignore",
"scss.lint.unknownAtRules": "ignore",
"eslint.enable": true,
"eslint.format.enable": true,
"eslint.validate": ["javascript", "typescript", "html"],
"eslint.useFlatConfig": true,
"eslint.workingDirectories": ["../projects/**/src"],
"eslint.options": {
"overrideConfigFile": "eslint.config.js"
},
"[typescript]": {
"editor.wordWrap": "off",
"editor.formatOnSave": false,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.tabSize": 2,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
},Python is formatted by ruff. On the TypeScript/Angular side there is no agreed formatter yet: ESLint with --fix is what we have, so do not reformat whole files — the diff noise costs more than the gain.
Note
Cosmetic suggestions in a code review should be identified as such, and can be ignored by the author of the original code. See pull requests and code review.