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

33 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-15 09:15 -0600

1"""General utilities.""" 

2import string 

3from collections import ChainMap 

4from dataclasses import asdict 

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

6 

7if 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 

12def 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 

29def 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 

37def 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 

42def 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 

49def 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 

54def 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: 

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

69 if new_version: 

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

71 return ctx 

72 

73 

74def 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}