Skip to content

Commit

Permalink
Refactored FileConfig to FileChange.
Browse files Browse the repository at this point in the history
This better describes what the class does: describe a file change.

Also moved `get_search_pattern` to the class, since it is specific to each instance
  • Loading branch information
coordt committed Dec 10, 2023
1 parent a4c90b2 commit 249a999
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 101 deletions.
2 changes: 1 addition & 1 deletion bumpversion/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def commit_and_tag(

extra_args = shlex.split(config.commit_args) if config.commit_args else []

commit_files = {f.path for f in configured_files}
commit_files = {f.file_change.filename for f in configured_files}
if config_file:
commit_files |= {str(config_file)}

Expand Down
4 changes: 2 additions & 2 deletions bumpversion/config/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def update_config_file(
context: The context to use for serialization.
dry_run: True if the update should be a dry run.
"""
from bumpversion.config.models import FileConfig
from bumpversion.config.models import FileChange
from bumpversion.files import DataFileUpdater

if not config_file:
Expand All @@ -129,7 +129,7 @@ def update_config_file(
return

# TODO: Eventually this should be transformed into another default "files_to_modify" entry
datafile_config = FileConfig(
datafile_config = FileChange(
filename=str(config_path),
key_path="tool.bumpversion.current_version",
search=config.search,
Expand Down
47 changes: 40 additions & 7 deletions bumpversion/config/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""Bump My Version configuration models."""
from __future__ import annotations

from typing import TYPE_CHECKING, Dict, List, Optional, Union
import logging
import re
from typing import TYPE_CHECKING, Dict, List, MutableMapping, Optional, Tuple, Union

from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings, SettingsConfigDict
Expand All @@ -10,6 +12,8 @@
from bumpversion.scm import SCMInfo
from bumpversion.version_part import VersionConfig

logger = logging.getLogger(__name__)


class VersionPartConfig(BaseModel):
"""Configuration of a part of the version."""
Expand All @@ -21,8 +25,8 @@ class VersionPartConfig(BaseModel):
independent: bool = False


class FileConfig(BaseModel):
"""Search and replace file config."""
class FileChange(BaseModel):
"""A change to make to a file."""

parse: str
serialize: List[str]
Expand All @@ -34,6 +38,35 @@ class FileConfig(BaseModel):
glob: Optional[str] = None # Conflicts with filename. If both are specified, glob wins
key_path: Optional[str] = None # If specified, and has an appropriate extension, will be treated as a data file

def get_search_pattern(self, context: MutableMapping) -> Tuple[re.Pattern, str]:
"""
Render the search pattern and return the compiled regex pattern and the raw pattern.
Args:
context: The context to use for rendering the search pattern
Returns:
A tuple of the compiled regex pattern and the raw pattern as a string.
"""
# the default search pattern is escaped, so we can still use it in a regex
raw_pattern = self.search.format(**context)
default = re.compile(re.escape(raw_pattern), re.MULTILINE | re.DOTALL)
if not self.regex:
logger.debug("No RegEx flag detected. Searching for the default pattern: '%s'", default.pattern)
return default, raw_pattern

re_context = {key: re.escape(str(value)) for key, value in context.items()}
regex_pattern = self.search.format(**re_context)
try:
search_for_re = re.compile(regex_pattern, re.MULTILINE | re.DOTALL)
logger.debug("Searching for the regex: '%s'", search_for_re.pattern)
return search_for_re, raw_pattern
except re.error as e:
logger.error("Invalid regex '%s': %s.", default, e)

logger.debug("Invalid regex. Searching for the default pattern: '%s'", raw_pattern)
return default, raw_pattern


class Config(BaseSettings):
"""Bump Version configuration."""
Expand All @@ -55,7 +88,7 @@ class Config(BaseSettings):
commit_args: Optional[str]
scm_info: Optional["SCMInfo"]
parts: Dict[str, VersionPartConfig]
files: List[FileConfig]
files: List[FileChange]
included_paths: List[str] = Field(default_factory=list)
excluded_paths: List[str] = Field(default_factory=list)
model_config = SettingsConfigDict(env_prefix="bumpversion_")
Expand All @@ -67,7 +100,7 @@ def add_files(self, filename: Union[str, List[str]]) -> None:
if name in self.resolved_filemap:
continue
self.files.append(
FileConfig(
FileChange(
filename=name,
glob=None,
key_path=None,
Expand All @@ -81,7 +114,7 @@ def add_files(self, filename: Union[str, List[str]]) -> None:
)

@property
def resolved_filemap(self) -> Dict[str, FileConfig]:
def resolved_filemap(self) -> Dict[str, FileChange]:
"""Return a map of filenames to file configs, expanding any globs."""
from bumpversion.config.utils import resolve_glob_files

Expand All @@ -95,7 +128,7 @@ def resolved_filemap(self) -> Dict[str, FileConfig]:
return {file_cfg.filename: file_cfg for file_cfg in new_files}

@property
def files_to_modify(self) -> List[FileConfig]:
def files_to_modify(self) -> List[FileChange]:
"""Return a list of files to modify."""
files_not_excluded = [
file_cfg.filename
Expand Down
8 changes: 4 additions & 4 deletions bumpversion/config/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import itertools
from typing import Dict, List

from bumpversion.config.models import FileConfig, VersionPartConfig
from bumpversion.config.models import FileChange, VersionPartConfig
from bumpversion.utils import labels_for_format


def get_all_file_configs(config_dict: dict) -> List[FileConfig]:
def get_all_file_configs(config_dict: dict) -> List[FileChange]:
"""Make sure all version parts are included."""
defaults = {
"parse": config_dict["parse"],
Expand All @@ -22,7 +22,7 @@ def get_all_file_configs(config_dict: dict) -> List[FileConfig]:
files = [{k: v for k, v in filecfg.items() if v is not None} for filecfg in config_dict["files"]]
for f in files:
f.update({k: v for k, v in defaults.items() if k not in f})
return [FileConfig(**f) for f in files]
return [FileChange(**f) for f in files]


def get_all_part_configs(config_dict: dict) -> Dict[str, VersionPartConfig]:
Expand All @@ -36,7 +36,7 @@ def get_all_part_configs(config_dict: dict) -> Dict[str, VersionPartConfig]:
}


def resolve_glob_files(file_cfg: FileConfig) -> List[FileConfig]:
def resolve_glob_files(file_cfg: FileChange) -> List[FileChange]:
"""
Return a list of file configurations that match the glob pattern.
Expand Down

0 comments on commit 249a999

Please sign in to comment.