Coverage for /Users/OORDCOR/Documents/code/bump-my-version/bumpversion/config/files.py: 19%

49 statements  

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

1"""Contains methods for finding and reading configuration files.""" 

2 

3from __future__ import annotations 

4 

5from pathlib import Path 

6from typing import TYPE_CHECKING, Any, Dict, MutableMapping, Union 

7 

8from bumpversion.config.files_legacy import read_ini_file 

9from bumpversion.ui import get_indented_logger, print_warning 

10 

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.version_part import Version 

14 

15logger = get_indented_logger(__name__) 

16 

17CONFIG_FILE_SEARCH_ORDER = ( 

18 ".bumpversion.cfg", 

19 ".bumpversion.toml", 

20 "setup.cfg", 

21 "pyproject.toml", 

22) 

23 

24 

25def find_config_file(explicit_file: Union[str, Path, None] = None) -> Union[Path, None]: 

26 """ 

27 Find the configuration file, if it exists. 

28 

29 If no explicit configuration file is passed, it will search in several files to 

30 find its configuration. 

31 

32 Args: 

33 explicit_file: The configuration file to explicitly use. 

34 

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( 

42 (cfg_file for cfg_file in search_paths if cfg_file.exists() and "bumpversion]" in cfg_file.read_text()), 

43 None, 

44 ) 

45 

46 

47def read_config_file(config_file: Union[str, Path, None] = None) -> Dict[str, Any]: 

48 """ 

49 Read the configuration file, if it exists. 

50 

51 If no explicit configuration file is passed, it will search in several files to 

52 find its configuration. 

53 

54 Args: 

55 config_file: The configuration file to explicitly use. 

56 

57 Returns: 

58 A dictionary of read key-values 

59 """ 

60 if not config_file: 

61 logger.info("No configuration file found.") 

62 return {} 

63 

64 config_path = Path(config_file) 

65 if not config_path.exists(): 

66 logger.info("Configuration file not found: %s.", config_path) 

67 return {} 

68 

69 logger.info("Reading config file: %s", config_file) 

70 

71 if config_path.suffix == ".cfg": 

72 print_warning("The .cfg file format is deprecated. Please use .toml instead.") 

73 return read_ini_file(config_path) 

74 elif config_path.suffix == ".toml": 

75 return read_toml_file(config_path) 

76 else: 

77 logger.info("Unknown config file suffix: %s. Using defaults.", config_path.suffix) 

78 return {} 

79 

80 

81def read_toml_file(file_path: Path) -> Dict[str, Any]: 

82 """ 

83 Parse a TOML file and return the `bumpversion` section. 

84 

85 Args: 

86 file_path: The path to the TOML file. 

87 

88 Returns: 

89 dict: A dictionary of the `bumpversion` section. 

90 """ 

91 import tomlkit 

92 

93 # Load the TOML file 

94 toml_data = tomlkit.parse(file_path.read_text()).unwrap() 

95 

96 return toml_data.get("tool", {}).get("bumpversion", {}) 

97 

98 

99def update_config_file( 

100 config_file: Union[str, Path], 

101 config: Config, 

102 current_version: Version, 

103 new_version: Version, 

104 context: MutableMapping, 

105 dry_run: bool = False, 

106) -> None: 

107 """ 

108 Update the current_version key in the configuration file. 

109 

110 Args: 

111 config_file: The configuration file to explicitly use. 

112 config: The configuration to use. 

113 current_version: The current version. 

114 new_version: The new version. 

115 context: The context to use for serialization. 

116 dry_run: True if the update should be a dry run. 

117 """ 

118 from bumpversion.config.models import FileChange 

119 from bumpversion.files import DataFileUpdater 

120 

121 if not config_file: 

122 logger.info("\n%sNo configuration file found to update.", logger.indent_str) 

123 return 

124 else: 

125 logger.info("\n%sProcessing config file: %s", logger.indent_str, config_file) 

126 logger.indent() 

127 config_path = Path(config_file) 

128 if config_path.suffix != ".toml": 

129 logger.info("You must have a `.toml` suffix to update the config file: %s.", config_path) 

130 return 

131 

132 # TODO: Eventually this should be transformed into another default "files_to_modify" entry 

133 datafile_config = FileChange( 

134 filename=str(config_path), 

135 key_path="tool.bumpversion.current_version", 

136 search=config.search, 

137 replace=config.replace, 

138 regex=config.regex, 

139 ignore_missing_version=config.ignore_missing_version, 

140 serialize=config.serialize, 

141 parse=config.parse, 

142 ) 

143 

144 updater = DataFileUpdater(datafile_config, config.version_config.part_configs) 

145 updater.update_file(current_version, new_version, context, dry_run) 

146 logger.dedent()