Coverage for /Users/coordt/Documents/code/bump-my-version/bumpversion/show.py: 21%
62 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"""Functions for displaying information about the version."""
3import dataclasses
4from io import StringIO
5from pprint import pprint
6from typing import Any, Optional
8from bumpversion.bump import get_next_version
9from bumpversion.config import Config
10from bumpversion.context import get_context
11from bumpversion.exceptions import BadInputError
12from bumpversion.ui import print_error, print_info
13from bumpversion.utils import recursive_sort_dict
16def output_default(value: dict) -> None:
17 """Output the value with key=value or just value if there is only one item."""
18 if len(value) == 1:
19 print_info(next(iter(value.values())))
20 else:
21 buffer = StringIO()
22 pprint(value, stream=buffer, sort_dicts=True) # noqa: T203
23 print_info(buffer.getvalue())
26def output_yaml(value: dict) -> None:
27 """Output the value as yaml."""
28 from bumpversion.yaml_dump import dump
30 print_info(dump(recursive_sort_dict(value)))
33def output_json(value: dict) -> None:
34 """Output the value as json."""
35 import json
37 def default_encoder(obj: Any) -> str:
38 if dataclasses.is_dataclass(obj):
39 return str(obj)
40 elif isinstance(obj, type):
41 return obj.__name__
42 raise TypeError(f"Object of type {type(obj), str(obj)} is not JSON serializable")
44 print_info(json.dumps(value, sort_keys=True, indent=2, default=default_encoder))
47OUTPUTTERS = {
48 "yaml": output_yaml,
49 "json": output_json,
50 "default": output_default,
51}
54def resolve_name(obj: Any, name: str, default: Any = None, err_on_missing: bool = False) -> Any:
55 """
56 Get a key or attr ``name`` from obj or default value.
58 Copied and modified from Django Template variable resolutions
60 Resolution methods:
62 - Mapping key lookup
63 - Attribute lookup
64 - Sequence index
66 Args:
67 obj: The object to access
68 name: A dotted name to the value, such as ``mykey.0.name``
69 default: If the name cannot be resolved from the object, return this value
70 err_on_missing: Raise a `BadInputError` if the name cannot be resolved
72 Returns:
73 The value at the resolved name or the default value.
75 Raises:
76 BadInputError: If we cannot resolve the name and `err_on_missing` is `True`
78 # noqa: DAR401
79 """
80 lookups = name.split(".")
81 current = obj
82 try: # catch-all for unexpected failures
83 for bit in lookups:
84 try: # dictionary lookup
85 current = current[bit]
86 # ValueError/IndexError are for numpy.array lookup on
87 # numpy < 1.9 and 1.9+ respectively
88 except (TypeError, AttributeError, KeyError, ValueError, IndexError):
89 try: # attribute lookup
90 current = getattr(current, bit)
91 except (TypeError, AttributeError):
92 # Reraise if the exception was raised by a @property
93 if bit in dir(current):
94 raise
95 try: # list-index lookup
96 current = current[int(bit)]
97 except (
98 IndexError, # list index out of range
99 ValueError, # invalid literal for int()
100 KeyError, # current is a dict without `int(bit)` key
101 TypeError,
102 ): # un-subscript-able object
103 return default
104 return current
105 except Exception as e: # pragma: no cover
106 if err_on_missing:
107 raise BadInputError(f"Could not resolve '{name}'") from e
108 else:
109 return default
112def do_show(*args, config: Config, format_: str = "default", increment: Optional[str] = None) -> None:
113 """Show current version or configuration information."""
114 config_dict = config.model_dump()
115 ctx = get_context(config)
117 if increment:
118 version = config.version_config.parse(config.current_version)
119 next_version = get_next_version(version, config, increment, None)
120 next_version_str = config.version_config.serialize(next_version, ctx)
121 config_dict["new_version"] = next_version_str
123 try:
124 if "all" in args or not args:
125 show_items = config_dict
126 else:
127 show_items = {key: resolve_name(config_dict, key) for key in args}
129 OUTPUTTERS.get(format_, OUTPUTTERS["default"])(show_items)
130 except BadInputError as e:
131 print_error(e.message)