From 4a3d0460fa7d914cb9d5444660f2b09487ad33df Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 04:13:13 +0000 Subject: [PATCH 1/3] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.0.285 → v0.0.290](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.285...v0.0.290) - [github.com/psf/black: 23.7.0 → 23.9.1](https://github.com/psf/black/compare/23.7.0...23.9.1) - [github.com/python-jsonschema/check-jsonschema: 0.24.1 → 0.26.3](https://github.com/python-jsonschema/check-jsonschema/compare/0.24.1...0.26.3) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e0e486fb..55f99aa8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,13 +1,13 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: 'v0.0.285' + rev: 'v0.0.290' hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] exclude: test.* - repo: https://github.com/psf/black - rev: 23.7.0 + rev: 23.9.1 hooks: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks @@ -59,6 +59,6 @@ repos: - id: interrogate exclude: test.* - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.24.1 + rev: 0.26.3 hooks: - id: check-azure-pipelines From a59ced8e5ed126cf2c43070d26d5a001982de962 Mon Sep 17 00:00:00 2001 From: Mauricio Villegas <5780272+mauvilsa@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:35:18 +0200 Subject: [PATCH 2/3] Removed bumpversion as a duplicate of the bump-my-version script. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 191cb107..a7d81049 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,6 @@ dependencies = [ [project.scripts] bump-my-version = "bumpversion.cli:cli" -bumpversion = "bumpversion.cli:cli" [project.urls] From 577aa4cd6408c7b6a46e8ba7cb5c54cd38cef769 Mon Sep 17 00:00:00 2001 From: Corey Oordt Date: Mon, 25 Sep 2023 18:21:57 -0500 Subject: [PATCH 3/3] Updated dependency from Pydantic 1 to 2. --- .pre-commit-config.yaml | 11 +++--- bumpversion/config.py | 39 ++++++++++----------- bumpversion/functions.py | 4 +-- bumpversion/version_part.py | 11 +++--- pyproject.toml | 11 +++++- requirements/dev.txt | 13 ++++++- requirements/docs.txt | 13 ++++++- requirements/prod.txt | 16 +++++++-- requirements/test.txt | 16 +++++++-- setup.cfg | 2 -- setup.py | 4 --- tests/fixtures/basic_cfg_expected.txt | 8 ++++- tests/fixtures/basic_cfg_expected.yaml | 9 ++++- tests/fixtures/basic_cfg_expected_full.json | 10 +++++- tests/test_version_part.py | 33 +++++++++++++++++ tools/generate-requirements.sh | 7 ++++ 16 files changed, 158 insertions(+), 49 deletions(-) delete mode 100644 setup.cfg delete mode 100644 setup.py create mode 100755 tools/generate-requirements.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e0e486fb..a2a90cf3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,15 +44,12 @@ repos: - id: mypy args: [--no-strict-optional, --ignore-missing-imports] additional_dependencies: ["pydantic<2.0", "toml", "types-all"] - - repo: https://github.com/terrencepreilly/darglint - rev: v1.8.1 + - repo: https://github.com/jsh9/pydoclint + rev: 0.3.2 hooks: - - id: darglint - exclude: test.*|cli\.py + - id: pydoclint args: - - -v 2 - - "--message-template={path}:{line} in `{obj}`:\n {msg_id}: {msg}" - - --strictness=short + - "--config=pyproject.toml" - repo: https://github.com/econchick/interrogate rev: 1.5.0 # or master if you're bold hooks: diff --git a/bumpversion/config.py b/bumpversion/config.py index 5e8daa2f..91245231 100644 --- a/bumpversion/config.py +++ b/bumpversion/config.py @@ -16,7 +16,8 @@ from bumpversion.scm import SCMInfo from bumpversion.version_part import VersionConfig -from pydantic import BaseModel, BaseSettings, Field +from pydantic import BaseModel, Field +from pydantic_settings import BaseSettings, SettingsConfigDict from bumpversion.exceptions import ConfigurationError @@ -26,24 +27,24 @@ class VersionPartConfig(BaseModel): """Configuration of a part of the version.""" - values: Optional[list] # Optional. Numeric is used if missing or no items in list - optional_value: Optional[str] # Optional. + values: Optional[list] = None # Optional. Numeric is used if missing or no items in list + optional_value: Optional[str] = None # Optional. # Defaults to first value. 0 in the case of numeric. Empty string means nothing is optional. - first_value: Optional[str] # Optional. Defaults to first value in values + first_value: Union[str, int, None] = None # Optional. Defaults to first value in values independent: bool = False class FileConfig(BaseModel): """Search and replace file config.""" - filename: Optional[str] - glob: Optional[str] # Conflicts with filename. If both are specified, glob wins - parse: Optional[str] # If different from outer scope - serialize: Optional[List[str]] # If different from outer scope - search: Optional[str] # If different from outer scope - replace: Optional[str] # If different from outer scope - no_regex: Optional[bool] # If different from outer scope - ignore_missing_version: Optional[bool] + filename: Optional[str] = None + glob: Optional[str] = None # Conflicts with filename. If both are specified, glob wins + parse: Optional[str] = None # If different from outer scope + serialize: Optional[List[str]] = None # If different from outer scope + search: Optional[str] = None # If different from outer scope + replace: Optional[str] = None # If different from outer scope + no_regex: Optional[bool] = None # If different from outer scope + ignore_missing_version: Optional[bool] = None class Config(BaseSettings): @@ -51,7 +52,7 @@ class Config(BaseSettings): current_version: Optional[str] parse: str - serialize: List[str] = Field(min_items=1) + serialize: List[str] = Field(min_length=1) search: str replace: str no_regex: bool @@ -67,11 +68,9 @@ class Config(BaseSettings): scm_info: Optional["SCMInfo"] parts: Dict[str, VersionPartConfig] files: List[FileConfig] - included_paths: List[str] = [] - excluded_paths: List[str] = [] - - class Config: - env_prefix = "bumpversion_" + included_paths: List[str] = Field(default_factory=list) + excluded_paths: List[str] = Field(default_factory=list) + model_config = SettingsConfigDict(env_prefix="bumpversion_") def add_files(self, filename: Union[str, List[str]]) -> None: """Add a filename to the list of files.""" @@ -177,7 +176,7 @@ def get_configuration(config_file: Union[str, Path, None] = None, **overrides) - Returns: The configuration """ - from bumpversion.scm import SCMInfo, get_scm_info + from bumpversion.scm import SCMInfo, SourceCodeManager, get_scm_info # noqa: F401 config_dict = DEFAULTS.copy() parsed_config = read_config_file(config_file) if config_file else {} @@ -195,7 +194,7 @@ def get_configuration(config_file: Union[str, Path, None] = None, **overrides) - config_dict["files"] = get_all_file_configs(config_dict) # Resolve the SCMInfo class for Pydantic's BaseSettings - Config.update_forward_refs(SCMInfo=SCMInfo) + Config.model_rebuild() config = Config(**config_dict) # type: ignore[arg-type] # Get the information about the SCM diff --git a/bumpversion/functions.py b/bumpversion/functions.py index eae2407b..798e63a2 100644 --- a/bumpversion/functions.py +++ b/bumpversion/functions.py @@ -31,12 +31,12 @@ class NumericFunction(PartFunction): FIRST_NUMERIC = re.compile(r"(\D*)(\d+)(.*)") - def __init__(self, optional_value: Optional[str] = None, first_value: Optional[str] = None): + def __init__(self, optional_value: Union[str, int, None] = None, first_value: Union[str, int, None] = None): if first_value is not None and not self.FIRST_NUMERIC.search(str(first_value)): raise ValueError(f"The given first value {first_value} does not contain any digit") self.first_value = str(first_value or 0) - self.optional_value = optional_value or self.first_value + self.optional_value = str(optional_value or self.first_value) def bump(self, value: Union[str, int]) -> str: """Increase the first numerical value by one.""" diff --git a/bumpversion/version_part.py b/bumpversion/version_part.py index 9f4d2fda..6c57e16f 100644 --- a/bumpversion/version_part.py +++ b/bumpversion/version_part.py @@ -3,7 +3,7 @@ import re import string from copy import copy -from typing import Any, Dict, List, MutableMapping, Optional +from typing import Any, Dict, List, MutableMapping, Optional, Union from click import UsageError @@ -23,12 +23,15 @@ class VersionPart: based on the configuration given. """ - def __init__(self, config: VersionPartConfig, value: Optional[str] = None): - self._value = value + def __init__(self, config: VersionPartConfig, value: Union[str, int, None] = None): + self._value = str(value) if value is not None else None self.config = config self.func: Optional[PartFunction] = None if config.values: - self.func = ValuesFunction(config.values, config.optional_value, config.first_value) + str_values = [str(v) for v in config.values] + str_optional_value = str(config.optional_value) if config.optional_value is not None else None + str_first_value = str(config.first_value) if config.first_value is not None else None + self.func = ValuesFunction(str_values, str_optional_value, str_first_value) else: self.func = NumericFunction(config.optional_value, config.first_value or "0") diff --git a/pyproject.toml b/pyproject.toml index 191cb107..78d1d6d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,8 @@ keywords = ["bumpversion", "version", "release"] dynamic = ["version"] dependencies = [ "click", - "pydantic<2.0.0", + "pydantic", + "pydantic-settings", "rich-click", "rich", "tomlkit", @@ -237,3 +238,11 @@ search = "Unreleased" filename = "CHANGELOG.md" search = "{current_version}...HEAD" replace = "{current_version}...{new_version}" + +[tool.pydoclint] +style = "google" +exclude = '\.git|tests' +require-return-section-when-returning-nothing = false +arg-type-hints-in-docstring = false +check-return-types = false +quiet = true diff --git a/requirements/dev.txt b/requirements/dev.txt index 6cccbe39..f7fce9ac 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -6,6 +6,8 @@ # alabaster==0.7.13 # via sphinx +annotated-types==0.5.0 + # via pydantic argopt==0.8.2 # via git-fame astroid==2.15.6 @@ -103,7 +105,13 @@ pluggy==1.0.0 # via pytest pre-commit==3.3.3 # via bump-my-version (pyproject.toml) -pydantic==1.10.9 +pydantic==2.4.0 + # via + # bump-my-version (pyproject.toml) + # pydantic-settings +pydantic-core==2.10.0 + # via pydantic +pydantic-settings==2.0.3 # via bump-my-version (pyproject.toml) pygments==2.15.1 # via @@ -123,6 +131,8 @@ pytest-mock==3.11.1 # via bump-my-version (pyproject.toml) python-dateutil==2.8.2 # via ghp-import +python-dotenv==1.0.0 + # via pydantic-settings pyyaml==6.0 # via # myst-parser @@ -197,6 +207,7 @@ typing-extensions==4.6.3 # via # astroid # pydantic + # pydantic-core # sphinx-autodoc2 # typer uc-micro-py==1.0.2 diff --git a/requirements/docs.txt b/requirements/docs.txt index 694fab37..59234144 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -6,6 +6,8 @@ # alabaster==0.7.13 # via sphinx +annotated-types==0.5.0 + # via pydantic astroid==2.15.6 # via sphinx-autodoc2 babel==2.12.1 @@ -57,7 +59,13 @@ myst-parser==2.0.0 # via bump-my-version (pyproject.toml) packaging==23.1 # via sphinx -pydantic==1.10.9 +pydantic==2.4.0 + # via + # bump-my-version (pyproject.toml) + # pydantic-settings +pydantic-core==2.10.0 + # via pydantic +pydantic-settings==2.0.3 # via bump-my-version (pyproject.toml) pygments==2.15.1 # via @@ -66,6 +74,8 @@ pygments==2.15.1 # sphinx python-dateutil==2.8.2 # via ghp-import +python-dotenv==1.0.0 + # via pydantic-settings pyyaml==6.0 # via myst-parser requests==2.31.0 @@ -121,6 +131,7 @@ typing-extensions==4.6.3 # via # astroid # pydantic + # pydantic-core # sphinx-autodoc2 uc-micro-py==1.0.2 # via linkify-it-py diff --git a/requirements/prod.txt b/requirements/prod.txt index d4138357..f0ccca20 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -4,6 +4,8 @@ # # pip-compile --output-file=requirements/prod.txt pyproject.toml # +annotated-types==0.5.0 + # via pydantic click==8.1.3 # via # bump-my-version (pyproject.toml) @@ -12,10 +14,18 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -pydantic==1.10.9 +pydantic==2.4.0 + # via + # bump-my-version (pyproject.toml) + # pydantic-settings +pydantic-core==2.10.0 + # via pydantic +pydantic-settings==2.0.3 # via bump-my-version (pyproject.toml) pygments==2.15.1 # via rich +python-dotenv==1.0.0 + # via pydantic-settings rich==13.4.2 # via # bump-my-version (pyproject.toml) @@ -25,4 +35,6 @@ rich-click==1.6.1 tomlkit==0.11.8 # via bump-my-version (pyproject.toml) typing-extensions==4.6.3 - # via pydantic + # via + # pydantic + # pydantic-core diff --git a/requirements/test.txt b/requirements/test.txt index 923b7ddd..05070747 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -4,6 +4,8 @@ # # pip-compile --extra=test --output-file=requirements/test.txt pyproject.toml # +annotated-types==0.5.0 + # via pydantic cfgv==3.3.1 # via pre-commit click==8.1.3 @@ -38,7 +40,13 @@ pluggy==1.0.0 # via pytest pre-commit==3.3.3 # via bump-my-version (pyproject.toml) -pydantic==1.10.9 +pydantic==2.4.0 + # via + # bump-my-version (pyproject.toml) + # pydantic-settings +pydantic-core==2.10.0 + # via pydantic +pydantic-settings==2.0.3 # via bump-my-version (pyproject.toml) pygments==2.15.1 # via rich @@ -51,6 +59,8 @@ pytest-cov==4.1.0 # via bump-my-version (pyproject.toml) pytest-mock==3.11.1 # via bump-my-version (pyproject.toml) +python-dotenv==1.0.0 + # via pydantic-settings pyyaml==6.0 # via pre-commit rich==13.4.2 @@ -66,7 +76,9 @@ tomli==2.0.1 tomlkit==0.11.8 # via bump-my-version (pyproject.toml) typing-extensions==4.6.3 - # via pydantic + # via + # pydantic + # pydantic-core virtualenv==20.23.1 # via pre-commit diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 471c3b27..00000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[darglint] -ignore = DAR402 diff --git a/setup.py b/setup.py deleted file mode 100644 index 00bdab42..00000000 --- a/setup.py +++ /dev/null @@ -1,4 +0,0 @@ -"""The setup script.""" -from setuptools import setup - -setup() diff --git a/tests/fixtures/basic_cfg_expected.txt b/tests/fixtures/basic_cfg_expected.txt index 771b0735..0333e2b7 100644 --- a/tests/fixtures/basic_cfg_expected.txt +++ b/tests/fixtures/basic_cfg_expected.txt @@ -52,7 +52,13 @@ 'optional_value': 'gamma', 'values': ['dev', 'gamma']}}, 'replace': '{new_version}', - 'scm_info': SCMInfo(tool=No SCM tool, commit_sha=None, distance_to_latest_tag=None, current_version=None, dirty=None), + 'scm_info': {'branch_name': None, + 'commit_sha': None, + 'current_version': None, + 'dirty': None, + 'distance_to_latest_tag': None, + 'short_branch_name': None, + 'tool': None}, 'search': '{current_version}', 'serialize': ['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}'], 'sign_tags': False, diff --git a/tests/fixtures/basic_cfg_expected.yaml b/tests/fixtures/basic_cfg_expected.yaml index 99f0b64d..4f2ef704 100644 --- a/tests/fixtures/basic_cfg_expected.yaml +++ b/tests/fixtures/basic_cfg_expected.yaml @@ -65,7 +65,14 @@ parts: - "dev" - "gamma" replace: "{new_version}" -scm_info: "SCMInfo(tool=No SCM tool, commit_sha=None, distance_to_latest_tag=None, current_version=None, dirty=None)" +scm_info: + branch_name: null + commit_sha: null + current_version: null + dirty: null + distance_to_latest_tag: null + short_branch_name: null + tool: null search: "{current_version}" serialize: - "{major}.{minor}.{patch}-{release}" diff --git a/tests/fixtures/basic_cfg_expected_full.json b/tests/fixtures/basic_cfg_expected_full.json index 0e0ba289..51335519 100644 --- a/tests/fixtures/basic_cfg_expected_full.json +++ b/tests/fixtures/basic_cfg_expected_full.json @@ -80,7 +80,15 @@ } }, "replace": "{new_version}", - "scm_info": "SCMInfo(tool=No SCM tool, commit_sha=None, distance_to_latest_tag=None, current_version=None, dirty=None)", + "scm_info": { + "branch_name": null, + "commit_sha": null, + "current_version": null, + "dirty": null, + "distance_to_latest_tag": null, + "short_branch_name": null, + "tool": null + }, "search": "{current_version}", "serialize": [ "{major}.{minor}.{patch}-{release}", diff --git a/tests/test_version_part.py b/tests/test_version_part.py index a99e3218..559cb1e9 100644 --- a/tests/test_version_part.py +++ b/tests/test_version_part.py @@ -1,3 +1,4 @@ +import logging from pathlib import Path import pytest @@ -330,3 +331,35 @@ def test_part_does_not_revert_to_zero_if_optional(tmp_path: Path) -> None: new_version = current_version.bump("build", version_config.order) assert version_config.serialize(new_version, get_context(conf)) == "0.3.1g1" + + +def test_order_of_serialization(tmp_path: Path, caplog: LogCaptureFixture) -> None: + """The order of serialization should be as specified in the config.""" + caplog.set_level(logging.DEBUG) + overrides = { + "current_version": "3.16.dev1", + "parse": r"(?P\d+)\.(?P\d+)\.(?P[a-z]+)?(?P\d+)?", + "serialize": [ + "{major}.{minor}.{release}{patch}", + "{major}.{minor}.{release}", + "{major}.{minor}.{patch}", + ], + "parts": { + "release": { + "optional_value": "prod", + "first_value": "dev", + "values": [ + "dev", + "prod", + ], + }, + }, + } + with inside_dir(tmp_path): + conf, version_config, current_version = get_config_data(overrides) + + new_version = current_version.bump("release", version_config.order) + new_version_str = version_config.serialize(new_version, get_context(conf)) + for msg in caplog.messages: + print(msg) + assert new_version_str == "3.16.prod" diff --git a/tools/generate-requirements.sh b/tools/generate-requirements.sh new file mode 100755 index 00000000..39c222b1 --- /dev/null +++ b/tools/generate-requirements.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + + +pip-compile --output-file=requirements/prod.txt pyproject.toml +pip-compile --extra=docs --output-file=requirements/docs.txt pyproject.toml +pip-compile --extra=test --output-file=requirements/test.txt pyproject.toml +pip-compile --extra=dev --extra=docs --extra=test --output-file=requirements/dev.txt pyproject.toml