Coverage for /Users/OORDCOR/Documents/code/bump-my-version/bumpversion/utils.py: 67%

1"""General utilities."""

2 import string

3 from collections import ChainMap

4 from dataclasses import asdict

5 from typing import TYPE_CHECKING, Any, List, Optional, Tuple

6

7 if TYPE_CHECKING: # pragma: no-coverage 7 ↛ 8line 7 didn't jump to line 8, because the condition on line 7 was never true

8 from bumpversion.config import Config

9 from bumpversion.version_part import Version

10

11

12 def extract_regex_flags(regex_pattern: str) -> Tuple[str, str]:

13 """

14 Extract the regex flags from the regex pattern.

15

16 Args:

17 regex_pattern: The pattern that might start with regex flags

18

19 Returns:

20 A tuple of the regex pattern without the flag string and regex flag string

21 """

22 import re

23

24 flag_pattern = r"^(\(\?[aiLmsux]+\))"

25 bits = re.split(flag_pattern, regex_pattern)

26 return (regex_pattern, "") if len(bits) == 1 else (bits[2], bits[1])

27

28

29 def recursive_sort_dict(input_value: Any) -> Any:

30 """Sort a dictionary recursively."""

31 if not isinstance(input_value, dict):

32 return input_value

33

34 return {key: recursive_sort_dict(input_value[key]) for key in sorted(input_value.keys())}

35

36

37 def key_val_string(d: dict) -> str:

38 """Render the dictionary as a comma-delimited key=value string."""

39 return ", ".join(f"{k}={v}" for k, v in sorted(d.items()))

40

41

42 def prefixed_environ() -> dict:

43 """Return a dict of the environment with keys wrapped in `${}`."""

44 import os

45

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

47

48

49 def labels_for_format(serialize_format: str) -> List[str]:

50 """Return a list of labels for the given serialize_format."""

51 return [item[1] for item in string.Formatter().parse(serialize_format) if item[1]]

52

53

54 def get_context(

55 config: "Config", current_version: Optional["Version"] = None, new_version: Optional["Version"] = None

56) -> ChainMap:

57 """Return the context for rendering messages and tags."""

58 import datetime

59

60 ctx = ChainMap(

61 {"current_version": config.current_version},

62 {"now": datetime.datetime.now(), "utcnow": datetime.datetime.utcnow()},

63 prefixed_environ(),

64 asdict(config.scm_info),

65 {c: c for c in ("#", ";")},

66 )

67 if current_version: 67 ↛ 69line 67 didn't jump to line 69, because the condition on line 67 was never false

68 ctx = ctx.new_child({f"current_{part}": current_version[part].value for part in current_version})

69 if new_version: 69 ↛ 70line 69 didn't jump to line 70, because the condition on line 69 was never true

70 ctx = ctx.new_child({f"new_{part}": new_version[part].value for part in new_version})

71 return ctx

72

73

74 def get_overrides(**kwargs) -> dict:

75 """Return a dictionary containing only the overridden key-values."""

76 return {key: val for key, val in kwargs.items() if val is not None}