Coverage for /Users/coordt/Documents/code/bump-my-version/bumpversion/config/files.py: 71%
49 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-06-12 09:26 -0500
« prev ^ index » next coverage.py v7.4.4, created at 2024-06-12 09:26 -0500
1"""Contains methods for finding and reading configuration files."""
3from __future__ import annotations
5from pathlib import Path
6from typing import TYPE_CHECKING, Any, Dict, MutableMapping, Union
8from bumpversion.config.files_legacy import read_ini_file
9from bumpversion.ui import get_indented_logger, print_warning
11if TYPE_CHECKING: # pragma: no-coverage 11 ↛ 12line 11 didn't jump to line 12, because the condition on line 11 was never true
12 from bumpversion.config.models import Config
13 from bumpversion.versioning.models import Version
15logger = get_indented_logger(__name__)
17CONFIG_FILE_SEARCH_ORDER = (
18 ".bumpversion.cfg",
19 ".bumpversion.toml",
20 "setup.cfg",
21 "pyproject.toml",
22)
25def find_config_file(explicit_file: Union[str, Path, None] = None) -> Union[Path, None]:
26 """
27 Find the configuration file, if it exists.
29 If no explicit configuration file is passed, it will search in several files to
30 find its configuration.
32 Args:
33 explicit_file: The configuration file to explicitly use.
35 Returns:
36 The configuration file path
37 """
38 search_paths = (
39 [Path(explicit_file)] if explicit_file else [Path.cwd().joinpath(path) for path in CONFIG_FILE_SEARCH_ORDER]
40 )
41 return next( 41 ↛ exitline 41 didn't jump to the function exit
42 (
43 cfg_file
44 for cfg_file in search_paths
45 if cfg_file.exists() and "bumpversion]" in cfg_file.read_text(encoding="utf-8")
46 ),
47 None,
48 )
51def read_config_file(config_file: Union[str, Path, None] = None) -> Dict[str, Any]:
52 """
53 Read the configuration file, if it exists.
55 If no explicit configuration file is passed, it will search in several files to
56 find its configuration.
58 Args:
59 config_file: The configuration file to explicitly use.
61 Returns:
62 A dictionary of read key-values
63 """
64 if not config_file: 64 ↛ 65line 64 didn't jump to line 65, because the condition on line 64 was never true
65 logger.info("No configuration file found.")
66 return {}
68 config_path = Path(config_file)
69 if not config_path.exists():
70 logger.info("Configuration file not found: %s.", config_path)
71 return {}
73 logger.info("Reading config file: %s", config_file)
75 if config_path.suffix == ".cfg": 75 ↛ 76line 75 didn't jump to line 76, because the condition on line 75 was never true
76 print_warning("The .cfg file format is deprecated. Please use .toml instead.")
77 return read_ini_file(config_path)
78 elif config_path.suffix == ".toml": 78 ↛ 81line 78 didn't jump to line 81, because the condition on line 78 was never false
79 return read_toml_file(config_path)
80 else:
81 logger.info("Unknown config file suffix: %s. Using defaults.", config_path.suffix)
82 return {}
85def read_toml_file(file_path: Path) -> Dict[str, Any]:
86 """
87 Parse a TOML file and return the `bumpversion` section.
89 Args:
90 file_path: The path to the TOML file.
92 Returns:
93 dict: A dictionary of the `bumpversion` section.
94 """
95 import tomlkit
97 # Load the TOML file
98 toml_data = tomlkit.parse(file_path.read_text(encoding="utf-8")).unwrap()
100 return toml_data.get("tool", {}).get("bumpversion", {})
103def update_config_file(
104 config_file: Union[str, Path],
105 config: Config,
106 current_version: Version,
107 new_version: Version,
108 context: MutableMapping,
109 dry_run: bool = False,
110) -> None:
111 """
112 Update the current_version key in the configuration file.
114 Args:
115 config_file: The configuration file to explicitly use.
116 config: The configuration to use.
117 current_version: The current version.
118 new_version: The new version.
119 context: The context to use for serialization.
120 dry_run: True if the update should be a dry run.
121 """
122 from bumpversion.config.models import FileChange
123 from bumpversion.files import DataFileUpdater
125 if not config_file: 125 ↛ 126line 125 didn't jump to line 126, because the condition on line 125 was never true
126 logger.info("\n%sNo configuration file found to update.", logger.indent_str)
127 return
128 else:
129 logger.info("\n%sProcessing config file: %s", logger.indent_str, config_file)
130 logger.indent()
131 config_path = Path(config_file)
132 if config_path.suffix != ".toml": 132 ↛ 133line 132 didn't jump to line 133, because the condition on line 132 was never true
133 logger.info("You must have a `.toml` suffix to update the config file: %s.", config_path)
134 return
136 # TODO: Eventually this should be transformed into another default "files_to_modify" entry
137 datafile_config = FileChange(
138 filename=str(config_path),
139 key_path="tool.bumpversion.current_version",
140 search=config.search,
141 replace=config.replace,
142 regex=config.regex,
143 ignore_missing_version=True,
144 ignore_missing_file=True,
145 serialize=config.serialize,
146 parse=config.parse,
147 )
149 updater = DataFileUpdater(datafile_config, config.version_config.part_configs)
150 updater.update_file(current_version, new_version, context, dry_run)
151 logger.dedent()