Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
252b606
Add addition_to_excluded_paths and excluded_paths to BaseConfig
ArBridgeman Nov 27, 2025
380f335
Move PTB Config to using BaseConfig for excluded_paths
ArBridgeman Nov 27, 2025
0f92db1
Fix title to right capitalization
ArBridgeman Nov 27, 2025
097b817
Fix test to use BaseConfig provided values instead
ArBridgeman Nov 27, 2025
a0215d9
Make names more explicit as just for python files
ArBridgeman Nov 27, 2025
2707e6f
Rename python_files to get_filtered_python_files
ArBridgeman Nov 27, 2025
d2875ba
Rename fixture to match more closely to attribute name
ArBridgeman Nov 27, 2025
979e429
Add directory found in other PTB projects
ArBridgeman Nov 27, 2025
773dc0c
Alphabetize paths so less messy
ArBridgeman Nov 27, 2025
8580998
Add test for test_excluded_python_paths and update description
ArBridgeman Nov 27, 2025
1126324
Update cookiecutter template as now in BaseConfig
ArBridgeman Nov 27, 2025
2630022
Add blurb in documentation for
ArBridgeman Nov 27, 2025
54bba16
Add changelog entry
ArBridgeman Nov 27, 2025
557b764
Add type hint ignore
ArBridgeman Nov 27, 2025
f479d71
Remove empty test file
ArBridgeman Nov 27, 2025
838037f
Fix old reference in migrating.rst
ArBridgeman Nov 27, 2025
559950c
Fix changelog entry to sub-issue #614
ArBridgeman Nov 27, 2025
5c5afc5
Skip get_poetry.py as not maintained by us, but added for convenience
ArBridgeman Nov 27, 2025
eec672c
Add tests for lint:security, lint:typing, lint:code
ArBridgeman Nov 27, 2025
34f39f1
Merge branch 'main' into feature/613_move_path_filters_to_BaseConfig
ArBridgeman Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Unreleased

This major release removes `project:fix` and `project:format`
and replaces them with `format:fix` and `format:check`.

## Refactoring

* #606: Renamed nox session `project:fix` more aptly to `format:fix` and `project:format` to `format:check`

## Feature

* #614: Replaced `path_filters` with `BaseConfig.add_to_excluded_python_paths` and `BaseConfig.excluded_python_paths`
2 changes: 1 addition & 1 deletion doc/github_actions/github_actions.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. _github_actions:

:octicon:`play` Github Actions
:octicon:`play` GitHub Actions
===============================

.. toctree::
Expand Down
7 changes: 7 additions & 0 deletions doc/user_guide/features/formatting_code/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ experience across projects.
Nox sessions
++++++++++++

.. note::
To prevent Python files from being formatted, you can do one of the following:
* For a single file, use a comment in the files as described in :ref:`this table <prevent_auto_format>`.
* If it is a directory (i.e. ``.workspace``), then you can exclude it by
adding it to the ``add_to_excluded_python_paths`` in the project's ``Config``
defined in the ``noxconfig.py``.

For autoformatting, the following tools are used:

* `black <https://black.readthedocs.io/en/stable/the_black_code_style/index.html>`__ -
Expand Down
2 changes: 2 additions & 0 deletions doc/user_guide/features/formatting_code/troubleshooting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ you receive an error from ``format:check`` (i.e. ``isort`` or ``black``), it it
likely that you need to update your configuration to align with
:ref:`formatting_configuration`.

.. _prevent_auto_format:

The automatic formatting is doing x, but we shouldn't do that because of y
---------------------------------------------------------------------------
Usually, automatic formatting is helpful, but there are rare cases where a developer
Expand Down
4 changes: 2 additions & 2 deletions doc/user_guide/migrating.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ For example, if test execution isn't performed in the standard way (e.g., :code:
# ATTENTION:
# In cases where it is reasonable to use "internal" functions, please do those imports
# within the function to keep them isolated and simplify future removal or replacement.
from exasol.toolbox.nox._shared import python_files
from exasol.toolbox.nox._shared import get_filtered_python_files

py_files = [f"{file}" for file in python_files(PROJECT_CONFIG.root)]
py_files = get_filtered_python_files(PROJECT_CONFIG.root)
print("The original 'format:fix' task has been taken hostage by this overwrite")
print("Files:\n{files}".format(files="\n".join(py_files))

Expand Down
37 changes: 37 additions & 0 deletions exasol/toolbox/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ def valid_version_string(version_string: str) -> str:

ValidVersionStr = Annotated[str, AfterValidator(valid_version_string)]

DEFAULT_EXCLUDED_PATHS = {
".eggs",
".html-documentation",
".poetry",
".sonar",
".venv",
"dist",
"venv",
}


class BaseConfig(BaseModel):
"""
Expand Down Expand Up @@ -49,6 +59,15 @@ class BaseConfig(BaseModel):
default=False,
description="If true, creates also the major version tags (v*) automatically",
)
add_to_excluded_python_paths: tuple[str, ...] = Field(
default=(),
description="""
This is used to extend the default excluded_python_paths. If a more general
path that would be seen in other projects, like .venv, needs to be added into
this argument, please instead modify the
`exasol.toolbox.config.DEFAULT_EXCLUDED_PATHS`.
""",
)
model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)

@computed_field # type: ignore[misc]
Expand All @@ -65,6 +84,24 @@ def minimum_python_version(self) -> str:
index_min_version = versioned.index(min_version)
return self.python_versions[index_min_version]

@computed_field # type: ignore[misc]
@property
def excluded_python_paths(self) -> tuple[str, ...]:
"""
There are certain nox sessions:
- lint:code
- lint:security
- lint:typing
- format:fix
- format:check
where it is desired restrict which Python files are considered within the
source_path, like excluding `dist`, `.eggs`. As such, this property is used to
exclude such undesired paths.
"""
return tuple(
DEFAULT_EXCLUDED_PATHS.union(set(self.add_to_excluded_python_paths))
)

@computed_field # type: ignore[misc]
@property
def pyupgrade_argument(self) -> tuple[str, ...]:
Expand Down
6 changes: 3 additions & 3 deletions exasol/toolbox/nox/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Mode,
_version,
check_for_config_attribute,
python_files,
get_filtered_python_files,
)
from noxconfig import (
PROJECT_CONFIG,
Expand Down Expand Up @@ -45,7 +45,7 @@ def command(*args: str) -> Iterable[str]:
@nox.session(name="format:fix", python=False)
def fix_format(session: Session) -> None:
"""Runs all automated format fixes on the code base"""
py_files = python_files(PROJECT_CONFIG.root)
py_files = get_filtered_python_files(PROJECT_CONFIG.root)
_version(session, Mode.Fix)
_pyupgrade(session, config=PROJECT_CONFIG, files=py_files)
_ruff(session, mode=Mode.Fix, files=py_files)
Expand All @@ -55,6 +55,6 @@ def fix_format(session: Session) -> None:
@nox.session(name="format:check", python=False)
def check_format(session: Session) -> None:
"""Checks the project for correct formatting"""
py_files = python_files(PROJECT_CONFIG.root)
py_files = get_filtered_python_files(PROJECT_CONFIG.root)
_ruff(session, mode=Mode.Check, files=py_files)
_code_format(session=session, mode=Mode.Check, files=py_files)
21 changes: 12 additions & 9 deletions exasol/toolbox/nox/_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@
import tomlkit
from nox import Session

from exasol.toolbox.nox._shared import python_files
from exasol.toolbox.nox._shared import get_filtered_python_files
from exasol.toolbox.util.dependencies.shared_models import PoetryFiles
from noxconfig import PROJECT_CONFIG


def _pylint(session: Session, files: Iterable[str]) -> None:
json_file = PROJECT_CONFIG.root / ".lint.json"
txt_file = PROJECT_CONFIG.root / ".lint.txt"

session.run(
"pylint",
"--output-format",
"colorized,json:.lint.json,text:.lint.txt",
f"colorized,json:{json_file},text:{txt_file}",
*files,
)

Expand Down Expand Up @@ -47,7 +50,7 @@ def _security_lint(session: Session, files: Iterable[str]) -> None:
"--format",
"json",
"--output",
".security.json",
PROJECT_CONFIG.root / ".security.json",
"--exit-zero",
*files,
)
Expand Down Expand Up @@ -120,22 +123,22 @@ def report_illegal(illegal: dict[str, list[str]], console: rich.console.Console)
@nox.session(name="lint:code", python=False)
def lint(session: Session) -> None:
"""Runs the static code analyzer on the project"""
py_files = python_files(PROJECT_CONFIG.root / PROJECT_CONFIG.source)
_pylint(session, py_files)
py_files = get_filtered_python_files(PROJECT_CONFIG.root / PROJECT_CONFIG.source)
_pylint(session=session, files=py_files)


@nox.session(name="lint:typing", python=False)
def type_check(session: Session) -> None:
"""Runs the type checker on the project"""
py_files = [f"{file}" for file in python_files(PROJECT_CONFIG.root)]
_type_check(session, py_files)
py_files = get_filtered_python_files(PROJECT_CONFIG.root)
_type_check(session=session, files=py_files)


@nox.session(name="lint:security", python=False)
def security_lint(session: Session) -> None:
"""Runs the security linter on the project"""
py_files = python_files(PROJECT_CONFIG.root / PROJECT_CONFIG.source)
_security_lint(session, py_files)
py_files = get_filtered_python_files(PROJECT_CONFIG.root / PROJECT_CONFIG.source)
_security_lint(session=session, files=py_files)


@nox.session(name="lint:dependencies", python=False)
Expand Down
15 changes: 8 additions & 7 deletions exasol/toolbox/nox/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import argparse
from collections import ChainMap
from collections.abc import (
Iterable,
MutableMapping,
)
from enum import (
Expand All @@ -20,7 +19,6 @@
Config,
)

DEFAULT_PATH_FILTERS = {"dist", ".eggs", "venv", ".poetry"}
DOCS_OUTPUT_DIR = ".html-documentation"


Expand All @@ -40,14 +38,17 @@ class Mode(Enum):
Check = auto()


def python_files(project_root: Path) -> Iterable[str]:
def get_filtered_python_files(project_root: Path) -> list[str]:
"""
Returns iterable of python files after removing unwanted paths
Returns iterable of Python files after removing excluded paths
"""
deny_list = DEFAULT_PATH_FILTERS.union(set(PROJECT_CONFIG.path_filters))

check_for_config_attribute(config=PROJECT_CONFIG, attribute="excluded_python_paths")
files = project_root.glob("**/*.py")
return [f"{path}" for path in files if not set(path.parts).intersection(deny_list)]
return [
f"{path}"
for path in files
if not set(path.parts).intersection(PROJECT_CONFIG.excluded_python_paths)
]


def _version(session: Session, mode: Mode) -> None:
Expand Down
4 changes: 2 additions & 2 deletions exasol/toolbox/nox/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
def check(session: Session) -> None:
"""Runs all available checks on the project"""
context = _context(session, coverage=True)
py_files = python_files(PROJECT_CONFIG.root)
py_files = get_filtered_python_files(PROJECT_CONFIG.root)
_version(session, Mode.Check)
_code_format(session, Mode.Check, py_files)
_pylint(session, py_files)
Expand Down Expand Up @@ -65,7 +65,7 @@ def check(session: Session) -> None:
Mode,
_context,
_version,
python_files,
get_filtered_python_files,
)

from exasol.toolbox.nox._ci import (
Expand Down
15 changes: 9 additions & 6 deletions noxconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,19 @@ class Config(BaseConfig):
source: Path = Path("exasol/toolbox")
importlinter: Path = Path(__file__).parent / ".import_linter_config"
version_file: Path = Path(__file__).parent / "exasol" / "toolbox" / "version.py"
path_filters: Iterable[str] = (
"metrics-schema",
"project-template",
"idioms",
".github",
)
plugins: Iterable[object] = (UpdateTemplates,)


PROJECT_CONFIG = Config(
add_to_excluded_python_paths=(
# The cookiecutter placeholders do not work well with checks.
# Instead, the format & linting are checked in the
# ``test.integration.project-template``.
"project-template",
# This file comes from poetry (https://install.python-poetry.org/),
# so we should not modify it.
"get_poetry.py",
),
create_major_version_tags=True,
# The PTB does not have integration tests run with an Exasol DB,
# so for running in the CI, we take the first element.
Expand Down
1 change: 0 additions & 1 deletion project-template/{{cookiecutter.repo_name}}/noxconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class Config(BaseConfig):
/ "{{cookiecutter.package_name}}"
/ "version.py"
)
path_filters: Iterable[str] = ()
plugins: Iterable[object] = ()

PROJECT_CONFIG = Config()
20 changes: 20 additions & 0 deletions test/unit/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pydantic_core._pydantic_core import ValidationError

from exasol.toolbox.config import (
DEFAULT_EXCLUDED_PATHS,
BaseConfig,
valid_version_string,
)
Expand Down Expand Up @@ -66,3 +67,22 @@ def test_minimum_python_version():
def test_pyupgrade_argument(minimum_python_version):
conf = BaseConfig(python_versions=("3.11", minimum_python_version, "3.12"))
assert conf.pyupgrade_argument == ("--py310-plus",)


@pytest.mark.parametrize(
"add_to_excluded_python_paths,expected",
[
pytest.param((), tuple(DEFAULT_EXCLUDED_PATHS), id="no_additions"),
pytest.param(
(next(iter(DEFAULT_EXCLUDED_PATHS)),),
tuple(DEFAULT_EXCLUDED_PATHS),
id="duplicate_addition",
),
pytest.param(
("dummy",), tuple(DEFAULT_EXCLUDED_PATHS) + ("dummy",), id="add_a_new_entry"
),
],
)
def test_excluded_python_paths(add_to_excluded_python_paths, expected):
conf = BaseConfig(add_to_excluded_python_paths=add_to_excluded_python_paths)
assert sorted(conf.excluded_python_paths) == sorted(expected)
Loading