Coverage for /Users/coordt/Documents/code/bump-my-version/bumpversion/context.py: 73%
33 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-06-11 14:29 -0500
« prev ^ index » next coverage.py v7.4.4, created at 2024-06-11 14:29 -0500
1"""Context for rendering messages and tags."""
3import calendar
4import datetime
5from collections import ChainMap
6from dataclasses import asdict
7from typing import TYPE_CHECKING, Optional
9if TYPE_CHECKING: # pragma: no-coverage 9 ↛ 10line 9 didn't jump to line 10, because the condition on line 9 was never true
10 from bumpversion.config import Config
11 from bumpversion.scm import SCMInfo
12 from bumpversion.versioning.models import Version
14MONTH_ABBREVIATIONS = [abbr for abbr in calendar.month_abbr if abbr]
16CALVER_PATTERN_MAP = {
17 "{YYYY}": r"(?:[1-9][0-9]{3})",
18 "{YY}": r"(?:[1-9][0-9]?)",
19 "{0Y}": r"(?:[0-9]{2})",
20 "{MMM}": f'(?:{"|".join(MONTH_ABBREVIATIONS)})',
21 "{MM}": r"(?:1[0-2]|[1-9])",
22 "{0M}": r"(?:1[0-2]|0[1-9])",
23 "{DD}": r"(?:3[0-1]|[1-2][0-9]|[1-9])",
24 "{0D}": r"(?:3[0-1]|[1-2][0-9]|0[1-9])",
25 "{JJJ}": r"(?:36[0-6]|3[0-5][0-9]|[1-2][0-9][0-9]|[1-9][0-9]|[1-9])",
26 "{00J}": r"(?:36[0-6]|3[0-5][0-9]|[1-2][0-9][0-9]|0[1-9][0-9]|00[1-9])",
27 "{Q}": r"(?:[1-4])",
28 "{WW}": r"(?:5[0-3]|[1-4][0-9]|[0-9])",
29 "{0W}": r"(?:5[0-3]|[0-4][0-9])",
30 "{UU}": r"(?:5[0-3]|[1-4][0-9]|[0-9])",
31 "{0U}": r"(?:5[0-3]|[0-4][0-9])",
32 "{VV}": r"(?:5[0-3]|[1-4][0-9]|[1-9])",
33 "{0V}": r"(?:5[0-3]|[1-4][0-9]|0[1-9])",
34 "{GGGG}": r"(?:[1-9][0-9]{3})",
35 "{GG}": r"(?:[0-9][0-9]?)",
36 "{0G}": r"(?:[0-9]{2})",
37 "{INC0}": r"(?:[0-9]+)",
38 "{INC1}": r"[1-9][0-9]*",
39}
42def calver_string_to_regex(calver_format: str) -> str:
43 """Convert the calver format string to a regex pattern."""
44 pattern = calver_format
45 for key, value in CALVER_PATTERN_MAP.items():
46 pattern = pattern.replace(key, value)
47 return pattern
50def prefixed_environ() -> dict:
51 """Return a dict of the environment with keys wrapped in `${}`."""
52 import os
54 return {f"${key}": value for key, value in os.environ.items()}
57def base_context(scm_info: Optional["SCMInfo"] = None) -> ChainMap:
58 """The default context for rendering messages and tags."""
59 from bumpversion.scm import SCMInfo # Including this here to avoid circular imports
61 scm = asdict(scm_info) if scm_info else asdict(SCMInfo())
63 return ChainMap(
64 {
65 "now": datetime.datetime.now(),
66 "utcnow": datetime.datetime.now(datetime.timezone.utc),
67 },
68 prefixed_environ(),
69 scm,
70 {c: c for c in ("#", ";")},
71 )
74def get_context(
75 config: "Config", current_version: Optional["Version"] = None, new_version: Optional["Version"] = None
76) -> ChainMap:
77 """Return the context for rendering messages and tags."""
78 ctx = base_context(config.scm_info)
79 ctx = ctx.new_child({"current_version": config.current_version})
80 if current_version:
81 ctx = ctx.new_child({f"current_{part}": current_version[part].value for part in current_version})
82 if new_version:
83 ctx = ctx.new_child({f"new_{part}": new_version[part].value for part in new_version})
84 return ctx
87def get_datetime_info(current_dt: datetime.datetime) -> dict:
88 """Return the full structure of the given datetime for formatting."""
89 return {
90 "YYYY": current_dt.strftime("%Y"),
91 "YY": current_dt.strftime("%y").lstrip("0") or "0",
92 "0Y": current_dt.strftime("%y"),
93 "MMM": current_dt.strftime("%b"),
94 "MM": str(current_dt.month),
95 "0M": current_dt.strftime("%m"),
96 "DD": str(current_dt.day),
97 "0D": current_dt.strftime("%d"),
98 "JJJ": current_dt.strftime("%j").lstrip("0"),
99 "00J": current_dt.strftime("%j"),
100 "Q": str((current_dt.month - 1) // 3 + 1),
101 "WW": current_dt.strftime("%W").lstrip("0") or "0",
102 "0W": current_dt.strftime("%W"),
103 "UU": current_dt.strftime("%U").lstrip("0") or "0",
104 "0U": current_dt.strftime("%U"),
105 "VV": current_dt.strftime("%V").lstrip("0") or "0",
106 "0V": current_dt.strftime("%V"),
107 "GGGG": current_dt.strftime("%G"),
108 "GG": current_dt.strftime("%G")[2:].lstrip("0") or "0",
109 "0G": current_dt.strftime("%G")[2:],
110 }