Skip to content

Commit

Permalink
Refactored context into its own module
Browse files Browse the repository at this point in the history
  • Loading branch information
coordt committed Mar 27, 2024
1 parent 7a0e639 commit 5a3e05d
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 78 deletions.
5 changes: 3 additions & 2 deletions bumpversion/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
from bumpversion.config import Config
from bumpversion.config.files import update_config_file
from bumpversion.config.files_legacy import update_ini_config_file
from bumpversion.context import get_context
from bumpversion.exceptions import ConfigurationError
from bumpversion.ui import get_indented_logger
from bumpversion.utils import get_context, key_val_string
from bumpversion.utils import key_val_string

logger = get_indented_logger(__name__)

Expand Down Expand Up @@ -96,7 +97,7 @@ def do_bump(
configured_files = resolve_file_config(config.files_to_modify, config.version_config)
modify_files(configured_files, version, next_version, ctx, dry_run)
if config_file and config_file.suffix in {".cfg", ".ini"}:
update_ini_config_file(config_file, config.current_version, next_version_str, dry_run)
update_ini_config_file(config_file, config.current_version, next_version_str, dry_run) # pragma: no-coverage
else:
update_config_file(config_file, config, version, next_version, ctx, dry_run)

Expand Down
3 changes: 2 additions & 1 deletion bumpversion/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
from bumpversion.config import get_configuration
from bumpversion.config.create import create_configuration
from bumpversion.config.files import find_config_file
from bumpversion.context import get_context
from bumpversion.files import ConfiguredFile, modify_files
from bumpversion.show import do_show
from bumpversion.ui import get_indented_logger, print_info, setup_logging
from bumpversion.utils import get_context, get_overrides
from bumpversion.utils import get_overrides
from bumpversion.visualize import visualize

logger = get_indented_logger(__name__)
Expand Down
110 changes: 110 additions & 0 deletions bumpversion/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""Context for rendering messages and tags."""

import calendar
import datetime
from collections import ChainMap
from dataclasses import asdict
from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING: # pragma: no-coverage
from bumpversion.config import Config
from bumpversion.scm import SCMInfo
from bumpversion.versioning.models import Version

MONTH_ABBREVIATIONS = [abbr for abbr in calendar.month_abbr if abbr]

CALVER_PATTERN_MAP = {
"{YYYY}": r"(?:[1-9][0-9]{3})",
"{YY}": r"(?:[1-9][0-9]?)",
"{0Y}": r"(?:[0-9]{2})",
"{MMM}": f'(?:{"|".join(MONTH_ABBREVIATIONS)})',
"{MM}": r"(?:1[0-2]|[1-9])",
"{0M}": r"(?:1[0-2]|0[1-9])",
"{DD}": r"(?:3[0-1]|[1-2][0-9]|[1-9])",
"{0D}": r"(?:3[0-1]|[1-2][0-9]|0[1-9])",
"{JJJ}": r"(?:36[0-6]|3[0-5][0-9]|[1-2][0-9][0-9]|[1-9][0-9]|[1-9])",
"{00J}": r"(?:36[0-6]|3[0-5][0-9]|[1-2][0-9][0-9]|0[1-9][0-9]|00[1-9])",
"{Q}": r"(?:[1-4])",
"{WW}": r"(?:5[0-3]|[1-4][0-9]|[0-9])",
"{0W}": r"(?:5[0-3]|[0-4][0-9])",
"{UU}": r"(?:5[0-3]|[1-4][0-9]|[0-9])",
"{0U}": r"(?:5[0-3]|[0-4][0-9])",
"{VV}": r"(?:5[0-3]|[1-4][0-9]|[1-9])",
"{0V}": r"(?:5[0-3]|[1-4][0-9]|0[1-9])",
"{GGGG}": r"(?:[1-9][0-9]{3})",
"{GG}": r"(?:[0-9][0-9]?)",
"{0G}": r"(?:[0-9]{2})",
"{INC0}": r"(?:[0-9]+)",
"{INC1}": r"[1-9][0-9]*",
}


def calver_string_to_regex(calver_format: str) -> str:
"""Convert the calver format string to a regex pattern."""
pattern = calver_format
for key, value in CALVER_PATTERN_MAP.items():
pattern = pattern.replace(key, value)
return pattern


def prefixed_environ() -> dict:
"""Return a dict of the environment with keys wrapped in `${}`."""
import os

return {f"${key}": value for key, value in os.environ.items()}


def base_context(scm_info: Optional["SCMInfo"] = None) -> ChainMap:
"""The default context for rendering messages and tags."""
from bumpversion.scm import SCMInfo # Including this here to avoid circular imports

scm = asdict(scm_info) if scm_info else asdict(SCMInfo())

return ChainMap(
{
"now": datetime.datetime.now(),
"utcnow": datetime.datetime.now(datetime.timezone.utc),
},
prefixed_environ(),
scm,
{c: c for c in ("#", ";")},
)


def get_context(
config: "Config", current_version: Optional["Version"] = None, new_version: Optional["Version"] = None
) -> ChainMap:
"""Return the context for rendering messages and tags."""
ctx = base_context(config.scm_info)
ctx = ctx.new_child({"current_version": config.current_version})
if current_version:
ctx = ctx.new_child({f"current_{part}": current_version[part].value for part in current_version})
if new_version:
ctx = ctx.new_child({f"new_{part}": new_version[part].value for part in new_version})
return ctx


def get_datetime_info(current_dt: datetime.datetime) -> dict:
"""Return the full structure of the given datetime for formatting."""
return {
"YYYY": current_dt.strftime("%Y"),
"YY": current_dt.strftime("%y").lstrip("0") or "0",
"0Y": current_dt.strftime("%y"),
"MMM": current_dt.strftime("%b"),
"MM": str(current_dt.month),
"0M": current_dt.strftime("%m"),
"DD": str(current_dt.day),
"0D": current_dt.strftime("%d"),
"JJJ": current_dt.strftime("%j").lstrip("0"),
"00J": current_dt.strftime("%j"),
"Q": str((current_dt.month - 1) // 3 + 1),
"WW": current_dt.strftime("%W").lstrip("0") or "0",
"0W": current_dt.strftime("%W"),
"UU": current_dt.strftime("%U").lstrip("0") or "0",
"0U": current_dt.strftime("%U"),
"VV": current_dt.strftime("%V").lstrip("0") or "0",
"0V": current_dt.strftime("%V"),
"GGGG": current_dt.strftime("%G"),
"GG": current_dt.strftime("%G")[2:].lstrip("0") or "0",
"0G": current_dt.strftime("%G")[2:],
}
3 changes: 2 additions & 1 deletion bumpversion/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

from bumpversion.bump import get_next_version
from bumpversion.config import Config
from bumpversion.context import get_context
from bumpversion.exceptions import BadInputError
from bumpversion.ui import print_error, print_info
from bumpversion.utils import get_context, recursive_sort_dict
from bumpversion.utils import recursive_sort_dict


def output_default(value: dict) -> None:
Expand Down
47 changes: 1 addition & 46 deletions bumpversion/utils.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
"""General utilities."""

import datetime
import string
from collections import ChainMap
from dataclasses import asdict
from typing import TYPE_CHECKING, Any, List, Optional, Tuple

if TYPE_CHECKING: # pragma: no-coverage
from bumpversion.config import Config
from bumpversion.scm import SCMInfo
from bumpversion.versioning.models import Version
from typing import Any, List, Tuple


def extract_regex_flags(regex_pattern: str) -> Tuple[str, str]:
Expand Down Expand Up @@ -42,48 +34,11 @@ def key_val_string(d: dict) -> str:
return ", ".join(f"{k}={v}" for k, v in sorted(d.items()))


def prefixed_environ() -> dict:
"""Return a dict of the environment with keys wrapped in `${}`."""
import os

return {f"${key}": value for key, value in os.environ.items()}


def labels_for_format(serialize_format: str) -> List[str]:
"""Return a list of labels for the given serialize_format."""
return [item[1] for item in string.Formatter().parse(serialize_format) if item[1]]


def base_context(scm_info: Optional["SCMInfo"] = None) -> ChainMap:
"""The default context for rendering messages and tags."""
from bumpversion.scm import SCMInfo # Including this here to avoid circular imports

scm = asdict(scm_info) if scm_info else asdict(SCMInfo())

return ChainMap(
{
"now": datetime.datetime.now(),
"utcnow": datetime.datetime.now(datetime.timezone.utc),
},
prefixed_environ(),
scm,
{c: c for c in ("#", ";")},
)


def get_context(
config: "Config", current_version: Optional["Version"] = None, new_version: Optional["Version"] = None
) -> ChainMap:
"""Return the context for rendering messages and tags."""
ctx = base_context(config.scm_info)
ctx = ctx.new_child({"current_version": config.current_version})
if current_version:
ctx = ctx.new_child({f"current_{part}": current_version[part].value for part in current_version})
if new_version:
ctx = ctx.new_child({f"new_{part}": new_version[part].value for part in new_version})
return ctx


def get_overrides(**kwargs) -> dict:
"""Return a dictionary containing only the overridden key-values."""
return {key: val for key, val in kwargs.items() if val is not None}
Expand Down
26 changes: 1 addition & 25 deletions bumpversion/versioning/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,7 @@
import re
from typing import List, Optional, Union


def get_datetime_info(current_dt: datetime.datetime) -> dict:
"""Return the full structure of the given datetime for formatting."""
return {
"YYYY": current_dt.strftime("%Y"),
"YY": current_dt.strftime("%y").lstrip("0") or "0",
"0Y": current_dt.strftime("%y"),
"MMM": current_dt.strftime("%b"),
"MM": str(current_dt.month),
"0M": current_dt.strftime("%m"),
"DD": str(current_dt.day),
"0D": current_dt.strftime("%d"),
"JJJ": current_dt.strftime("%j").lstrip("0"),
"00J": current_dt.strftime("%j"),
"Q": str((current_dt.month - 1) // 3 + 1),
"WW": current_dt.strftime("%W").lstrip("0") or "0",
"0W": current_dt.strftime("%W"),
"UU": current_dt.strftime("%U").lstrip("0") or "0",
"0U": current_dt.strftime("%U"),
"VV": current_dt.strftime("%V").lstrip("0") or "0",
"0V": current_dt.strftime("%V"),
"GGGG": current_dt.strftime("%G"),
"GG": current_dt.strftime("%G")[2:].lstrip("0") or "0",
"0G": current_dt.strftime("%G")[2:],
}
from bumpversion.context import get_datetime_info


class PartFunction:
Expand Down
2 changes: 1 addition & 1 deletion bumpversion/visualize.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

from bumpversion.bump import get_next_version
from bumpversion.config import Config
from bumpversion.context import base_context, get_context
from bumpversion.exceptions import BumpVersionError
from bumpversion.ui import print_info
from bumpversion.utils import base_context, get_context

BOX_CHARS = {
"ascii": ["+", "+", "+", "+", "+", "+", "+", "+", "-", "|", "+"],
Expand Down
2 changes: 1 addition & 1 deletion tests/test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from bumpversion import exceptions, files, config, bump
from bumpversion.config.models import FileChange
from bumpversion.utils import get_context
from bumpversion.context import get_context
from bumpversion.exceptions import VersionNotFoundError
from bumpversion.version_part import VersionConfig
from tests.conftest import get_config_data, inside_dir
Expand Down
2 changes: 1 addition & 1 deletion tests/test_version_part.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from click import UsageError

from bumpversion import exceptions
from bumpversion.utils import get_context
from bumpversion.context import get_context
from tests.conftest import get_config_data, inside_dir


Expand Down

0 comments on commit 5a3e05d

Please sign in to comment.