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 2024-02-24 07:45 -0600

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

2 

3import dataclasses 

4from io import StringIO 

5from pprint import pprint 

6from typing import Any, Optional 

7 

8from bumpversion.bump import get_next_version 

9from bumpversion.config import Config 

10from bumpversion.exceptions import BadInputError 

11from bumpversion.ui import print_error, print_info 

12from bumpversion.utils import get_context, recursive_sort_dict 

13 

14 

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

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

17 if len(value) == 1: 

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

19 else: 

20 buffer = StringIO() 

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

22 print_info(buffer.getvalue()) 

23 

24 

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

26 """Output the value as yaml.""" 

27 from bumpversion.yaml_dump import dump 

28 

29 print_info(dump(recursive_sort_dict(value))) 

30 

31 

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

33 """Output the value as json.""" 

34 import json 

35 

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

37 if dataclasses.is_dataclass(obj): 

38 return str(obj) 

39 elif isinstance(obj, type): 

40 return obj.__name__ 

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

42 

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

44 

45 

46OUTPUTTERS = { 

47 "yaml": output_yaml, 

48 "json": output_json, 

49 "default": output_default, 

50} 

51 

52 

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

54 """ 

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

56 

57 Copied and modified from Django Template variable resolutions 

58 

59 Resolution methods: 

60 

61 - Mapping key lookup 

62 - Attribute lookup 

63 - Sequence index 

64 

65 Args: 

66 obj: The object to access 

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

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

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

70 

71 Returns: 

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

73 

74 Raises: 

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

76 

77 # noqa: DAR401 

78 """ 

79 lookups = name.split(".") 

80 current = obj 

81 try: # catch-all for unexpected failures 

82 for bit in lookups: 

83 try: # dictionary lookup 

84 current = current[bit] 

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

86 # numpy < 1.9 and 1.9+ respectively 

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

88 try: # attribute lookup 

89 current = getattr(current, bit) 

90 except (TypeError, AttributeError): 

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

92 if bit in dir(current): 

93 raise 

94 try: # list-index lookup 

95 current = current[int(bit)] 

96 except ( 

97 IndexError, # list index out of range 

98 ValueError, # invalid literal for int() 

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

100 TypeError, 

101 ): # un-subscript-able object 

102 return default 

103 return current 

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

105 if err_on_missing: 

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

107 else: 

108 return default 

109 

110 

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

112 """Output configuration with new version.""" 

113 ctx = get_context(config) 

114 if version_part: 

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

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

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

118 

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

120 

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

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

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

124 

125 

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

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

128 config_dict = config.model_dump() 

129 ctx = get_context(config) 

130 

131 if increment: 

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

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

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

135 config_dict["new_version"] = next_version_str 

136 

137 try: 

138 if "all" in args or not args: 

139 show_items = config_dict 

140 else: 

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

142 

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

144 except BadInputError as e: 

145 print_error(e.message)