From 903cf6356082375b1e0023a60e45bd2b79b02994 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 12:46:24 +0200 Subject: [PATCH 1/7] Switch to getting version from package itself --- exasol/toolbox/__init__.py | 3 +++ .../{{cookiecutter.package_name}}/__init__.py | 3 +++ test/integration/project-template/conftest.py | 8 ++++++-- test/integration/project-template/poetry_test.py | 15 +++++++++++++++ test/unit/package_init_test.py | 7 +++++++ 5 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/unit/package_init_test.py diff --git a/exasol/toolbox/__init__.py b/exasol/toolbox/__init__.py index e5276f400c..ff9745c1df 100644 --- a/exasol/toolbox/__init__.py +++ b/exasol/toolbox/__init__.py @@ -1,5 +1,6 @@ import logging import os +from importlib.metadata import version import structlog from structlog.dev import ConsoleRenderer @@ -9,6 +10,8 @@ format_exc_info, ) +__version__ = version("exasol-toolbox") + log_level = os.getenv("LOG_LEVEL", "INFO").upper() structlog.configure( diff --git a/project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/__init__.py b/project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/__init__.py index e69de29bb2..659d5d7b5b 100644 --- a/project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/__init__.py +++ b/project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/__init__.py @@ -0,0 +1,3 @@ +from importlib.metadata import version + +__version__ = version("{{cookiecutter.pypi_package_name}}") diff --git a/test/integration/project-template/conftest.py b/test/integration/project-template/conftest.py index 979ee7e0bb..b115521175 100644 --- a/test/integration/project-template/conftest.py +++ b/test/integration/project-template/conftest.py @@ -14,11 +14,15 @@ def cwd(tmp_path_factory): return tmp_path_factory.mktemp("project_template_test") +@pytest.fixture(scope="session") +def package_name(): + return "package" + + @pytest.fixture(scope="session", autouse=True) -def new_project(cwd): +def new_project(cwd, package_name): project_name = "project" repo_name = "repo" - package_name = "package" project_path = cwd / repo_name subprocess.run(["mkdir", "-p", project_path]) diff --git a/test/integration/project-template/poetry_test.py b/test/integration/project-template/poetry_test.py index 05626ab78b..a2186f2af3 100644 --- a/test/integration/project-template/poetry_test.py +++ b/test/integration/project-template/poetry_test.py @@ -14,3 +14,18 @@ def test_poetry_check_passes(new_project): assert output.stderr == "" assert output.stdout == "All set!\n" + + +def test_package_version_is_set(run_command, package_name): + output = run_command( + [ + "poetry", + "run", + "python", + "-c", + f"import exasol.{package_name}; print(exasol.{package_name}.__version__)", + ] + ) + + assert output.stderr == "" + assert output.stdout.strip() == "0.1.0" diff --git a/test/unit/package_init_test.py b/test/unit/package_init_test.py new file mode 100644 index 0000000000..8c54cdeb16 --- /dev/null +++ b/test/unit/package_init_test.py @@ -0,0 +1,7 @@ +import exasol.toolbox +from exasol.toolbox.util.version import Version + + +def test_package_version_is_set(): + assert isinstance(exasol.toolbox.__version__, str) + assert Version.from_string(exasol.toolbox.__version__) From f2f3853306bda66ea23ec0f76bf44d7ab25fce33 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 14:36:47 +0200 Subject: [PATCH 2/7] Remove version updating from release:prepare and formatting --- exasol/toolbox/nox/_format.py | 2 -- exasol/toolbox/nox/_release.py | 12 ------------ exasol/toolbox/nox/_shared.py | 6 ------ exasol/toolbox/nox/tasks.py | 2 -- test/unit/nox/_format_test.py | 5 +---- 5 files changed, 1 insertion(+), 26 deletions(-) diff --git a/exasol/toolbox/nox/_format.py b/exasol/toolbox/nox/_format.py index e05eaf2d84..eb51e939ef 100644 --- a/exasol/toolbox/nox/_format.py +++ b/exasol/toolbox/nox/_format.py @@ -8,7 +8,6 @@ from exasol.toolbox.config import BaseConfig from exasol.toolbox.nox._shared import ( Mode, - _version, get_filtered_python_files, ) from noxconfig import ( @@ -44,7 +43,6 @@ def command(*args: str) -> Iterable[str]: def fix_format(session: Session) -> None: """Runs all automated format fixes on the code base""" py_files = get_filtered_python_files(PROJECT_CONFIG.root_path) - _version(session, Mode.Fix) _pyupgrade(session, config=PROJECT_CONFIG, files=py_files) _ruff(session, mode=Mode.Fix, files=py_files) _code_format(session, Mode.Fix, py_files) diff --git a/exasol/toolbox/nox/_release.py b/exasol/toolbox/nox/_release.py index ad50104ce5..5b5f0932e5 100644 --- a/exasol/toolbox/nox/_release.py +++ b/exasol/toolbox/nox/_release.py @@ -8,10 +8,6 @@ import nox from nox import Session -from exasol.toolbox.nox._shared import ( - Mode, - _version, -) from exasol.toolbox.nox.plugin import NoxTasks from exasol.toolbox.util.dependencies.shared_models import PoetryFiles from exasol.toolbox.util.git import Git @@ -58,12 +54,6 @@ def _create_parser() -> argparse.ArgumentParser: return parser -def _update_project_version(session: Session, version: Version) -> Version: - session.run("poetry", "version", f"{version}") - _version(session, Mode.Fix) - return version - - def _get_changelogs(version: Version) -> Changelog: return Changelog( changes_path=PROJECT_CONFIG.documentation_path / "changes", @@ -130,8 +120,6 @@ def prepare_release(session: Session) -> None: if not args.no_branch and not args.no_add: Git.create_and_switch_to_branch(f"release/prepare-{new_version}") - _ = _update_project_version(session, new_version) - changed_files = ( _get_changelogs(version=new_version).prepare_release().get_changed_files() ) diff --git a/exasol/toolbox/nox/_shared.py b/exasol/toolbox/nox/_shared.py index acf705583d..b80cfa724f 100644 --- a/exasol/toolbox/nox/_shared.py +++ b/exasol/toolbox/nox/_shared.py @@ -39,12 +39,6 @@ def exclude(path: Path): return [f"{path}" for path in files if not exclude(path)] -def _version(session: Session, mode: Mode) -> None: - command = ["nox", "-s", "version:check", "--"] - command = command if mode == Mode.Check else command + ["--fix"] - session.run(*command) - - def _context_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter diff --git a/exasol/toolbox/nox/tasks.py b/exasol/toolbox/nox/tasks.py index 20c4e53033..fc7914f202 100644 --- a/exasol/toolbox/nox/tasks.py +++ b/exasol/toolbox/nox/tasks.py @@ -35,7 +35,6 @@ def check(session: Session) -> None: """Runs all available checks on the project""" context = _context(session, coverage=True) py_files = get_filtered_python_files(PROJECT_CONFIG.root_path) - _version(session, Mode.Check) _code_format(session, Mode.Check, py_files) _pylint(session, py_files) _type_check(session, py_files) @@ -63,7 +62,6 @@ def check(session: Session) -> None: from exasol.toolbox.nox._shared import ( Mode, _context, - _version, get_filtered_python_files, ) diff --git a/test/unit/nox/_format_test.py b/test/unit/nox/_format_test.py index f1298685a2..5d7965ec54 100644 --- a/test/unit/nox/_format_test.py +++ b/test/unit/nox/_format_test.py @@ -162,10 +162,7 @@ def file_with_multiple_problems(tmp_path): @pytest.mark.slow def test_fix_format(nox_session, config, file_with_multiple_problems): with patch("exasol.toolbox.nox._format.PROJECT_CONFIG", new=config): - with patch("exasol.toolbox.nox._format._version") as version: - # Simulate version is up-to-date, as version check is out of the scope of the test case - version.return_value = True - fix_format(nox_session) + fix_format(nox_session) assert file_with_multiple_problems.read_text() == cleandoc(""" import numpy as np From 6477a1ef698e9bdedefe48781cf9152adc0881a3 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 14:55:46 +0200 Subject: [PATCH 3/7] Remove version.py files --- .gitattributes | 1 - .github/workflows/checks.yml | 29 +---- .../features/creating_a_release.rst | 6 +- doc/user_guide/features/metrics/sonar.rst | 2 +- exasol/toolbox/config.py | 10 -- exasol/toolbox/nox/_package_version.py | 103 ------------------ exasol/toolbox/nox/_release.py | 1 - exasol/toolbox/nox/tasks.py | 2 - .../toolbox/sphinx/multiversion/__init__.py | 6 +- exasol/toolbox/sphinx/multiversion/sphinx.py | 4 +- .../templates/github/workflows/checks.yml | 21 ---- exasol/toolbox/util/version.py | 17 --- exasol/toolbox/version.py | 15 --- .../{{cookiecutter.repo_name}}/.gitattributes | 1 - .../{{cookiecutter.package_name}}/version.py | 14 --- .../{{cookiecutter.repo_name}}/pyproject.toml | 4 +- pyproject.toml | 1 - .../project-template/pre_commit_test.py | 6 +- test/unit/config_test.py | 1 - test/unit/nox/_package_version_test.py | 69 ------------ test/unit/util/version_test.py | 21 ---- 21 files changed, 16 insertions(+), 318 deletions(-) delete mode 100644 exasol/toolbox/nox/_package_version.py delete mode 100644 exasol/toolbox/version.py delete mode 100644 project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/version.py delete mode 100644 test/unit/nox/_package_version_test.py diff --git a/.gitattributes b/.gitattributes index 36e7d27cb7..9e7da37ade 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,5 @@ # Core Data and Locks poetry.lock linguist-generated=true -exasol/toolbox/version.py linguist-generated=true doc/changes/changelog.md linguist-generated=true .github/actions/python-environment/ext/get_poetry.py linguist-generated=true diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 07dc171469..5a041f498e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -4,27 +4,6 @@ on: workflow_call: jobs: - check-version: - name: Check Version - runs-on: "ubuntu-24.04" - permissions: - contents: read - steps: - - name: Check out Repository - id: check-out-repository - uses: actions/checkout@v6 - - - name: Set up Python & Poetry Environment - id: set-up-python-and-poetry-environment - uses: exasol/python-toolbox/.github/actions/python-environment@v6 - with: - python-version: "3.10" - poetry-version: "2.3.0" - - - name: Check Version - id: check-version - run: poetry run -- nox -s version:check - build-documentation-and-check-links: name: Docs runs-on: "ubuntu-24.04" @@ -80,7 +59,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - name: Check out Repository id: check-out-repository @@ -114,7 +93,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - name: Check out Repository @@ -140,7 +119,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - name: Check out Repository @@ -238,7 +217,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - name: Check out Repository diff --git a/doc/user_guide/features/creating_a_release.rst b/doc/user_guide/features/creating_a_release.rst index 12f2a64e46..ae8c84cee2 100644 --- a/doc/user_guide/features/creating_a_release.rst +++ b/doc/user_guide/features/creating_a_release.rst @@ -10,11 +10,11 @@ Preparing a Release nox -s release:prepare -- --type {major,minor,patch} - The ``release:prepare`` nox session affects the ``pyproject.toml``, - ``version.py``, and files in the ``doc/changes`` directory: + The ``release:prepare`` nox session affects the ``pyproject.toml`` and files in the + ``doc/changes`` directory: * Creates & switches to a release branch (can be skipped with ``--no-branch``) - * Updates the version in the ``pyproject.toml`` and ``version.py`` + * Updates the version in the ``pyproject.toml`` * Moves the content of unreleased changes file ``unreleased.md`` to a versioned changes file ``changes_.md`` * Describes additional changes in the versioned changes file by comparing diff --git a/doc/user_guide/features/metrics/sonar.rst b/doc/user_guide/features/metrics/sonar.rst index 0cfd90f3f9..4856fda1a6 100644 --- a/doc/user_guide/features/metrics/sonar.rst +++ b/doc/user_guide/features/metrics/sonar.rst @@ -52,7 +52,7 @@ In the Code projectKey = "" host.url = "https://sonarcloud.io" organization = "exasol" - exclusions = "/version.py,//*" + exclusions = "//*" .. note:: For more information, see the :ref:`General remarks ` section. diff --git a/exasol/toolbox/config.py b/exasol/toolbox/config.py index 1d50e60a33..dd2427ff94 100644 --- a/exasol/toolbox/config.py +++ b/exasol/toolbox/config.py @@ -264,16 +264,6 @@ def source_code_path(self) -> Path: """ return self.root_path / "exasol" / self.project_name - @computed_field # type: ignore[misc] - @property - def version_filepath(self) -> Path: - """ - Path to the ``version.py`` file included in the project. This is an - autogenerated file which contains the version of the code. It is maintained by - the nox sessions ``version:check`` and ``release:prepare``. - """ - return self.source_code_path / "version.py" - @computed_field # type: ignore[misc] @property def github_workflow_directory(self) -> Path: diff --git a/exasol/toolbox/nox/_package_version.py b/exasol/toolbox/nox/_package_version.py deleted file mode 100644 index d4710c3099..0000000000 --- a/exasol/toolbox/nox/_package_version.py +++ /dev/null @@ -1,103 +0,0 @@ -import argparse -from argparse import ( - ArgumentParser, - Namespace, -) -from inspect import cleandoc -from pathlib import Path - -import nox -from nox import Session - -from exasol.toolbox.config import BaseConfig -from exasol.toolbox.util.version import Version -from noxconfig import ( - PROJECT_CONFIG, -) - -_SUCCESS = 0 -_FAILURE = 1 - -# fmt: off -_VERSION_MODULE_TEMPLATE = cleandoc(''' - """ - ATTENTION: - This file is generated by exasol/toolbox/nox/_package_version.py when using: - * either "poetry run -- nox -s format:fix" - * or "poetry run -- nox -s version:check -- --fix" - Do not edit this file manually! - If you need to change the version, do so in the pyproject.toml, e.g. by using - `poetry version X.Y.Z`. - """ - - MAJOR = {major} - MINOR = {minor} - PATCH = {patch} - VERSION = f"{{MAJOR}}.{{MINOR}}.{{PATCH}}" - __version__ = VERSION -''') + "\n" -# fmt: on - - -def write_version_module(version: Version, version_file: Path) -> None: - with version_file.open(mode="w", encoding="utf-8") as f: - f.write( - _VERSION_MODULE_TEMPLATE.format( - major=version.major, minor=version.minor, patch=version.patch - ) - ) - - -def _create_parser() -> ArgumentParser: - parser = ArgumentParser( - prog="nox -s version:check --", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - parser.add_argument( - "-d", - "--debug", - action="store_true", - default=False, - help="enabled debug mode for execution.", - ) - parser.add_argument( - "-f", - "--fix", - action="store_true", - default=False, - help="updates the `version.py`, instead of performing a check.", - ) - return parser - - -def _version_check(args: Namespace, config: BaseConfig) -> int: - version_file = config.version_filepath - - module_version = Version.from_python_module(version_file) - poetry_version = Version.from_poetry() - if args.fix: - print( - f"Updating version in {version_file} from {module_version} to {poetry_version}" - ) - write_version_module(version=poetry_version, version_file=version_file) - module_version = Version.from_python_module(version_file) - - if module_version != poetry_version: - print( - f"Version in pyproject.toml ({poetry_version}) and {version_file} ({module_version}) do not match!" - ) - return _FAILURE - - return _SUCCESS - - -@nox.session(name="version:check", python=False) -def version_check(session: Session) -> None: - """ - Compare the version in the `version.py` to that - declared in the `pyproject.toml`. - """ - parser = _create_parser() - args = parser.parse_args(session.posargs) - if _version_check(args=args, config=PROJECT_CONFIG): - session.error() diff --git a/exasol/toolbox/nox/_release.py b/exasol/toolbox/nox/_release.py index 5b5f0932e5..0756a03fb0 100644 --- a/exasol/toolbox/nox/_release.py +++ b/exasol/toolbox/nox/_release.py @@ -134,7 +134,6 @@ def prepare_release(session: Session) -> None: changed_files += [ PROJECT_CONFIG.root_path / PoetryFiles.pyproject_toml, - PROJECT_CONFIG.version_filepath, ] results = pm.hook.prepare_release_add_files(session=session, config=PROJECT_CONFIG) changed_files += [f for plugin_response in results for f in plugin_response] diff --git a/exasol/toolbox/nox/tasks.py b/exasol/toolbox/nox/tasks.py index fc7914f202..0fe726fbf0 100644 --- a/exasol/toolbox/nox/tasks.py +++ b/exasol/toolbox/nox/tasks.py @@ -84,8 +84,6 @@ def check(session: Session) -> None: audit ) -from exasol.toolbox.nox._package_version import version_check - from exasol.toolbox.nox._package import package_check from exasol.toolbox.nox._workflow import generate_workflow diff --git a/exasol/toolbox/sphinx/multiversion/__init__.py b/exasol/toolbox/sphinx/multiversion/__init__.py index 683b6c7697..a03a2988d0 100644 --- a/exasol/toolbox/sphinx/multiversion/__init__.py +++ b/exasol/toolbox/sphinx/multiversion/__init__.py @@ -2,7 +2,7 @@ Git based multi version support for sphinx. This module/plugin provides support for creating a multi version output for the documented project. -Version's are defined using git tags and branches, the only supported output format is html. +Versions are defined using git tags and branches, the only supported output format is HTML. NOTICE: The original version of this package was published under the BSD license and can be found `here `_. @@ -15,11 +15,11 @@ The original version and its defaults were minimally adjusted to work in Exasol's projects with the defaults and without adding an extra template. The [Shibuya](https://github.com/lepture/shibuya) theme is expected to be used for HTML, which already evaluates the versions field in the HTML context and generates an appropriate selector for the versions. """ +from exasol.toolbox import __version__ from exasol.toolbox.sphinx.multiversion.main import main from exasol.toolbox.sphinx.multiversion.sphinx import setup -from exasol.toolbox.version import VERSION -__version__ = VERSION +__version__ = __version__ __all__ = [ "setup", diff --git a/exasol/toolbox/sphinx/multiversion/sphinx.py b/exasol/toolbox/sphinx/multiversion/sphinx.py index 91db2b8813..1f18f6c43c 100644 --- a/exasol/toolbox/sphinx/multiversion/sphinx.py +++ b/exasol/toolbox/sphinx/multiversion/sphinx.py @@ -9,8 +9,8 @@ from sphinx.locale import _ from sphinx.util import i18n as sphinx_i18n +from exasol.toolbox import __version__ as plugin_version from exasol.toolbox.util.version import Version as ExasolVersion -from exasol.toolbox.version import VERSION as PLUGIN_VERSION logger = logging.getLogger(__name__) @@ -253,7 +253,7 @@ def setup(app): app.connect("config-inited", config_inited) return { - "version": PLUGIN_VERSION, + "version": plugin_version, "parallel_read_safe": True, "parallel_write_safe": True, } diff --git a/exasol/toolbox/templates/github/workflows/checks.yml b/exasol/toolbox/templates/github/workflows/checks.yml index d81b8f7599..d5b99d28c3 100644 --- a/exasol/toolbox/templates/github/workflows/checks.yml +++ b/exasol/toolbox/templates/github/workflows/checks.yml @@ -4,27 +4,6 @@ on: workflow_call: jobs: - check-version: - name: Check Version - runs-on: "(( os_version ))" - permissions: - contents: read - steps: - - name: Check out Repository - id: check-out-repository - uses: actions/checkout@v6 - - - name: Set up Python & Poetry Environment - id: set-up-python-and-poetry-environment - uses: exasol/python-toolbox/.github/actions/python-environment@v6 - with: - python-version: "(( minimum_python_version ))" - poetry-version: "(( dependency_manager_version ))" - - - name: Check Version - id: check-version - run: poetry run -- nox -s version:check - build-documentation-and-check-links: name: Docs runs-on: "(( os_version ))" diff --git a/exasol/toolbox/util/version.py b/exasol/toolbox/util/version.py index 86dc177e2d..9ff6055472 100644 --- a/exasol/toolbox/util/version.py +++ b/exasol/toolbox/util/version.py @@ -7,9 +7,7 @@ total_ordering, wraps, ) -from pathlib import Path from shutil import which -from typing import Any from exasol.toolbox.error import ToolboxError @@ -106,18 +104,3 @@ def upgrade_version_from_poetry(t: ReleaseTypes): text=True, ) return Version.from_string(output.stdout.strip()) - - @staticmethod - def from_python_module(path: Path) -> Version: - """Retrieve version information from the `version` module""" - with open(path, encoding="utf-8") as file: - _locals: dict[str, Any] = {} - _globals: dict[str, Any] = {} - exec(file.read(), _locals, _globals) - - try: - version = _globals["VERSION"] - except KeyError as ex: - raise ToolboxError("Couldn't find version within module") from ex - - return Version.from_string(version) diff --git a/exasol/toolbox/version.py b/exasol/toolbox/version.py deleted file mode 100644 index 9cd7a2afe7..0000000000 --- a/exasol/toolbox/version.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -ATTENTION: - This file is generated by exasol/toolbox/nox/_package_version.py when using: - * either "poetry run -- nox -s format:fix" - * or "poetry run -- nox -s version:check -- --fix" -Do not edit this file manually! -If you need to change the version, do so in the pyproject.toml, e.g. by using -`poetry version X.Y.Z`. -""" - -MAJOR = 6 -MINOR = 4 -PATCH = 0 -VERSION = f"{MAJOR}.{MINOR}.{PATCH}" -__version__ = VERSION diff --git a/project-template/{{cookiecutter.repo_name}}/.gitattributes b/project-template/{{cookiecutter.repo_name}}/.gitattributes index ba692cde5a..d223213297 100644 --- a/project-template/{{cookiecutter.repo_name}}/.gitattributes +++ b/project-template/{{cookiecutter.repo_name}}/.gitattributes @@ -1,3 +1,2 @@ poetry.lock linguist-generated=true -exasol/{{cookiecutter.import_package}}/version.py linguist-generated=true doc/changes/changelog.md linguist-generated=true diff --git a/project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/version.py b/project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/version.py deleted file mode 100644 index d9066af99d..0000000000 --- a/project-template/{{cookiecutter.repo_name}}/exasol/{{cookiecutter.package_name}}/version.py +++ /dev/null @@ -1,14 +0,0 @@ -"""ATTENTION: -This file is generated by exasol/toolbox/nox/_package_version.py when using: - * either "poetry run -- nox -s format:fix" - * or "poetry run -- nox -s version:check -- --fix" -Do not edit this file manually! -If you need to change the version, do so in the pyproject.toml, e.g. by using -`poetry version X.Y.Z`. -""" - -MAJOR = 0 -MINOR = 1 -PATCH = 0 -VERSION = f"{MAJOR}.{MINOR}.{PATCH}" -__version__ = VERSION diff --git a/project-template/{{cookiecutter.repo_name}}/pyproject.toml b/project-template/{{cookiecutter.repo_name}}/pyproject.toml index 846847f94e..db6d6ca7d6 100644 --- a/project-template/{{cookiecutter.repo_name}}/pyproject.toml +++ b/project-template/{{cookiecutter.repo_name}}/pyproject.toml @@ -3,7 +3,7 @@ name = "{{cookiecutter.pypi_package_name}}" version = "0.1.0" description = "{{cookiecutter.description}}" authors = [ - {name = "{{cookiecutter.author_full_name}}", email = "{{cookiecutter.author_email}}"}, + { name = "{{cookiecutter.author_full_name}}", email = "{{cookiecutter.author_email}}" }, ] requires-python = ">={{cookiecutter.python_version_min}},<4.0" readme = "README.rst" @@ -12,7 +12,6 @@ license-files = ["LICENSE"] keywords = ['exasol', '{{cookiecutter.package_name}}'] classifiers = [ "Programming Language :: Python :: 3", - ] dependencies = [] @@ -92,4 +91,3 @@ ignore_errors = true projectKey = "com.exasol:{{cookiecutter.repo_name}}" host.url = "https://sonarcloud.io" organization = "exasol" -exclusions = "exasol/{{cookiecutter.package_name}}/version.py" diff --git a/pyproject.toml b/pyproject.toml index bb50415a45..b97c3fa5a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -152,4 +152,3 @@ markers = [ projectKey = "com.exasol:python-toolbox" host.url = "https://sonarcloud.io" organization = "exasol" -exclusions = "exasol/toolbox/version.py" diff --git a/test/integration/project-template/pre_commit_test.py b/test/integration/project-template/pre_commit_test.py index 9e6f72999f..67c99ab021 100644 --- a/test/integration/project-template/pre_commit_test.py +++ b/test/integration/project-template/pre_commit_test.py @@ -18,8 +18,6 @@ def _command(poetry_path: str, stage: str) -> list[str]: "run", "--hook-stage", stage, - "--files", - "exasol/package/version.py", ] def test_stage_pre_commit(self, pre_commit, poetry_path, run_command): @@ -27,7 +25,7 @@ def test_stage_pre_commit(self, pre_commit, poetry_path, run_command): output = run_command(command, check=False) assert "Failed" not in output.stdout - assert "Passed" in output.stdout + assert any(word in output.stdout for word in ("Passed", "Skipped")) assert output.returncode == 0 def test_stage_pre_push(self, pre_commit, poetry_path, run_command): @@ -35,5 +33,5 @@ def test_stage_pre_push(self, pre_commit, poetry_path, run_command): output = run_command(command, check=False) assert "Failed" not in output.stdout - assert "Passed" in output.stdout + assert any(word in output.stdout for word in ("Passed", "Skipped")) assert output.returncode == 0 diff --git a/test/unit/config_test.py b/test/unit/config_test.py index 035f7a6b04..be6a326bf5 100644 --- a/test/unit/config_test.py +++ b/test/unit/config_test.py @@ -59,7 +59,6 @@ def test_works_as_defined(tmp_path, test_project_config_factory): "root_path": root_path, "sonar_code_path": Path("exasol/test"), "source_code_path": root_path / "exasol" / "test", - "version_filepath": root_path / "exasol" / "test" / "version.py", } @staticmethod diff --git a/test/unit/nox/_package_version_test.py b/test/unit/nox/_package_version_test.py deleted file mode 100644 index 03f986f5de..0000000000 --- a/test/unit/nox/_package_version_test.py +++ /dev/null @@ -1,69 +0,0 @@ -from unittest import mock - -import pytest - -from exasol.toolbox.config import BaseConfig -from exasol.toolbox.nox._package_version import ( - _create_parser, - _version_check, - write_version_module, -) -from exasol.toolbox.util.version import Version - -DEFAULT_VERSION = Version(major=0, minor=1, patch=0) -ALTERNATE_VERSION = Version(major=0, minor=2, patch=0) - - -@pytest.fixture -def config(test_project_config_factory) -> BaseConfig: - config = test_project_config_factory() - # We need to set up the directory path so that version_file can execute - config.source_code_path.mkdir(parents=True, exist_ok=True) - return config - - -@pytest.fixture -def version_file(config): - version_file = config.version_filepath - write_version_module(version=DEFAULT_VERSION, version_file=version_file) - return version_file - - -def test_write_version_module(version_file) -> None: - write_version_module(version=ALTERNATE_VERSION, version_file=version_file) - assert version_file.exists() - - with version_file.open(mode="r", encoding="utf-8") as f: - result = f.read() - assert "MAJOR = 0\nMINOR = 2\nPATCH = 0\n" in result - - -class TestVersionCheck: - @staticmethod - @mock.patch.object(Version, "from_poetry", return_value=DEFAULT_VERSION) - def test_same_value_is_successful(from_poetry, config, version_file): - Version(major=0, minor=1, patch=0) - parser = _create_parser() - args = parser.parse_args([]) - - result = _version_check(args=args, config=config) - assert result == 0 - - @staticmethod - @mock.patch.object(Version, "from_poetry", return_value=ALTERNATE_VERSION) - def test_different_value_is_failure(from_poetry, config, version_file): - Version(major=0, minor=1, patch=0) - parser = _create_parser() - args = parser.parse_args([]) - - result = _version_check(args=args, config=config) - assert result == 1 - - @staticmethod - @mock.patch.object(Version, "from_poetry", return_value=ALTERNATE_VERSION) - def test_with_fix(from_poetry, config, version_file): - parser = _create_parser() - args = parser.parse_args(["--fix"]) - - result = _version_check(args=args, config=config) - assert result == 0 diff --git a/test/unit/util/version_test.py b/test/unit/util/version_test.py index 96455a7c70..ec6251d487 100644 --- a/test/unit/util/version_test.py +++ b/test/unit/util/version_test.py @@ -86,24 +86,3 @@ def test(): with pytest.raises(ToolboxError): test() - - -def test_version_from_python_module(tmp_path): - tmp_file = tmp_path / "file" - file = """ -MAJOR = 1 -MINOR = 2 -PATCH = 3 -VERSION = f"{MAJOR}.{MINOR}.{PATCH}" -__version__ = VERSION - """ - tmp_file.write_text(file) - assert Version.from_python_module(tmp_file) == Version.from_string("1.2.3") - - -def test_version_from_python_no_module_error(tmp_path): - file_path = tmp_path / "file" - file_path.write_text("") - with pytest.raises(ToolboxError) as ex: - Version.from_python_module(file_path) - assert str(ex.value) == "Couldn't find version within module" From 53bfe19080a872c1b80be83c210e2a59c990f125 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 15:13:47 +0200 Subject: [PATCH 4/7] Add changelog entry --- doc/changes/unreleased.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index b1179794c6..1d529adc43 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -2,7 +2,20 @@ ## Summary +In this major release, support for the `version.py`file has been removed. Users should: +- delete the `version.py` file +- add in their project's `__init__.py` module + + ```python + from importlib.metadata import version + __version__ = version("") + ``` +This is required for the nox session `docs:multiversion` to successfully complete, +and it is a Python standard for users to check in the terminal which version they are +using. + ## Refactoring * #800: Removed tbx security pretty-print, tbx lint pretty-print, and creation of .lint.txt, as superseded by Sonar and .lint.json usage * #791: Resolved Sonar concerns: accepted specific `subprocess` import usage & improved minor maintainability items +* #629: Replace `version.py` with version from the `__init__.py` From b6b18287deab2b5ee1bbf57b9307493f883a5749 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 15:19:24 +0200 Subject: [PATCH 5/7] Use workflow:generate to ensure sameness --- .github/workflows/checks.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 5a041f498e..a258fef3ac 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -59,7 +59,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] + python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Check out Repository id: check-out-repository @@ -93,7 +93,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] + python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Check out Repository @@ -119,7 +119,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] + python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Check out Repository @@ -217,7 +217,7 @@ jobs: strategy: fail-fast: false matrix: - python-versions: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] + python-versions: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Check out Repository From f9a4f6dba9063930a892d4a9f71cb34cacfa2534 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 15:22:48 +0200 Subject: [PATCH 6/7] Remove unused function --- exasol/toolbox/cli.py | 11 ----------- test/unit/cli_test.py | 39 --------------------------------------- 2 files changed, 50 deletions(-) delete mode 100644 exasol/toolbox/cli.py delete mode 100644 test/unit/cli_test.py diff --git a/exasol/toolbox/cli.py b/exasol/toolbox/cli.py deleted file mode 100644 index 377572ee44..0000000000 --- a/exasol/toolbox/cli.py +++ /dev/null @@ -1,11 +0,0 @@ -from argparse import ArgumentTypeError - -from exasol.toolbox.util.version import Version - - -def version(arg: str) -> Version: - try: - return Version.from_string(arg) - except Exception as ex: - msg = f"Expected format: .., e.g. 1.2.3, actual: {arg}" - raise ArgumentTypeError(msg) from ex diff --git a/test/unit/cli_test.py b/test/unit/cli_test.py deleted file mode 100644 index e97c365443..0000000000 --- a/test/unit/cli_test.py +++ /dev/null @@ -1,39 +0,0 @@ -from argparse import ArgumentTypeError - -import pytest - -from exasol.toolbox.cli import version -from exasol.toolbox.util.version import Version - - -@pytest.mark.parametrize( - "version_string,expected_error", - [ - ("4.4.4.4", ArgumentTypeError), - ("1.b.a", ArgumentTypeError), - ("F.b.a", ArgumentTypeError), - ("F", ArgumentTypeError), - ("Something", ArgumentTypeError), - ("1.1.1b", ArgumentTypeError), - ("1.1.1-pre", ArgumentTypeError), - ], -) -def test_version_throws_exception_on_invalid_version_string( - version_string, expected_error -): - with pytest.raises(expected_error): - _ = version(version_string) - - -@pytest.mark.parametrize( - "version_string,expected", - [ - ("1.2.3", Version(1, 2, 3)), - ("1.0.0", Version(1, 0, 0)), - ("1.0", Version(1, 0, 0)), - ("1", Version(1, 0, 0)), - ], -) -def test_version_gets_parsed_successfully(version_string, expected): - actual = version(version_string) - assert expected == actual From 75d2962696e37d628f464912609df88a26dd509c Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 15:58:32 +0200 Subject: [PATCH 7/7] Make cleaner with import as looked off --- exasol/toolbox/sphinx/multiversion/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exasol/toolbox/sphinx/multiversion/__init__.py b/exasol/toolbox/sphinx/multiversion/__init__.py index a03a2988d0..8fd846a02b 100644 --- a/exasol/toolbox/sphinx/multiversion/__init__.py +++ b/exasol/toolbox/sphinx/multiversion/__init__.py @@ -15,11 +15,11 @@ The original version and its defaults were minimally adjusted to work in Exasol's projects with the defaults and without adding an extra template. The [Shibuya](https://github.com/lepture/shibuya) theme is expected to be used for HTML, which already evaluates the versions field in the HTML context and generates an appropriate selector for the versions. """ -from exasol.toolbox import __version__ +from exasol.toolbox import __version__ as plugin_version from exasol.toolbox.sphinx.multiversion.main import main from exasol.toolbox.sphinx.multiversion.sphinx import setup -__version__ = __version__ +__version__ = plugin_version __all__ = [ "setup",