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

71 statements  

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

1"""Functions for displaying information about the version.""" 

2import dataclasses 

3from io import StringIO 

4from pprint import pprint 

5from typing import Any, Optional 

6 

7from bumpversion.bump import get_next_version 

8from bumpversion.config import Config 

9from bumpversion.exceptions import BadInputError 

10from bumpversion.ui import print_error, print_info 

11from bumpversion.utils import get_context, recursive_sort_dict 

12 

13 

14def output_default(value: dict) -> None: 

15 """Output the value with key=value or just value if there is only one item.""" 

16 if len(value) == 1: 

17 print_info(next(iter(value.values()))) 

18 else: 

19 buffer = StringIO() 

20 pprint(value, stream=buffer, sort_dicts=True) # noqa: T203 

21 print_info(buffer.getvalue()) 

22 

23 

24def output_yaml(value: dict) -> None: 

25 """Output the value as yaml.""" 

26 from bumpversion.yaml_dump import dump 

27 

28 print_info(dump(recursive_sort_dict(value))) 

29 

30 

31def output_json(value: dict) -> None: 

32 """Output the value as json.""" 

33 import json 

34 

35 def default_encoder(obj: Any) -> str: 

36 if dataclasses.is_dataclass(obj): 

37 return str(obj) 

38 elif isinstance(obj, type): 

39 return obj.__name__ 

40 raise TypeError(f"Object of type {type(obj), str(obj)} is not JSON serializable") 

41 

42 print_info(json.dumps(value, sort_keys=True, indent=2, default=default_encoder)) 

43 

44 

45OUTPUTTERS = { 

46 "yaml": output_yaml, 

47 "json": output_json, 

48 "default": output_default, 

49} 

50 

51 

52def resolve_name(obj: Any, name: str, default: Any = None, err_on_missing: bool = False) -> Any: 

53 """ 

54 Get a key or attr ``name`` from obj or default value. 

55 

56 Copied and modified from Django Template variable resolutions 

57 

58 Resolution methods: 

59 

60 - Mapping key lookup 

61 - Attribute lookup 

62 - Sequence index 

63 

64 Args: 

65 obj: The object to access 

66 name: A dotted name to the value, such as ``mykey.0.name`` 

67 default: If the name cannot be resolved from the object, return this value 

68 err_on_missing: Raise a `BadInputError` if the name cannot be resolved 

69 

70 Returns: 

71 The value at the resolved name or the default value. 

72 

73 Raises: 

74 BadInputError: If we cannot resolve the name and `err_on_missing` is `True` 

75 

76 # noqa: DAR401 

77 """ 

78 lookups = name.split(".") 

79 current = obj 

80 try: # catch-all for unexpected failures 

81 for bit in lookups: 

82 try: # dictionary lookup 

83 current = current[bit] 

84 # ValueError/IndexError are for numpy.array lookup on 

85 # numpy < 1.9 and 1.9+ respectively 

86 except (TypeError, AttributeError, KeyError, ValueError, IndexError): 

87 try: # attribute lookup 

88 current = getattr(current, bit) 

89 except (TypeError, AttributeError): 

90 # Reraise if the exception was raised by a @property 

91 if bit in dir(current): 

92 raise 

93 try: # list-index lookup 

94 current = current[int(bit)] 

95 except ( 

96 IndexError, # list index out of range 

97 ValueError, # invalid literal for int() 

98 KeyError, # current is a dict without `int(bit)` key 

99 TypeError, 

100 ): # un-subscript-able object 

101 return default 

102 return current 

103 except Exception as e: # noqa: BLE001 # pragma: no cover 

104 if err_on_missing: 

105 raise BadInputError(f"Could not resolve '{name}'") from e 

106 else: 

107 return default 

108 

109 

110def log_list(config: Config, version_part: Optional[str], new_version: Optional[str]) -> None: 

111 """Output configuration with new version.""" 

112 ctx = get_context(config) 

113 if version_part: 

114 version = config.version_config.parse(config.current_version) 

115 next_version = get_next_version(version, config, version_part, new_version) 

116 next_version_str = config.version_config.serialize(next_version, ctx) 

117 

118 print_info(f"new_version={next_version_str}") 

119 

120 config_dict = recursive_sort_dict(config.model_dump(exclude={"scm_info", "parts"})) 

121 for key, value in config_dict.items(): 

122 print_info(f"{key}={value}") 

123 

124 

125def do_show(*args, config: Config, format_: str = "default", increment: Optional[str] = None) -> None: 

126 """Show current version or configuration information.""" 

127 config_dict = config.model_dump() 

128 ctx = get_context(config) 

129 

130 if increment: 

131 version = config.version_config.parse(config.current_version) 

132 next_version = get_next_version(version, config, increment, None) 

133 next_version_str = config.version_config.serialize(next_version, ctx) 

134 config_dict["new_version"] = next_version_str 

135 

136 try: 

137 if "all" in args or not args: 

138 show_items = config_dict 

139 else: 

140 show_items = {key: resolve_name(config_dict, key) for key in args} 

141 

142 OUTPUTTERS.get(format_, OUTPUTTERS["default"])(show_items) 

143 except BadInputError as e: 

144 print_error(e.message)