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

49 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2024-02-24 07:50 -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.versioning.models 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 ( 

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 ) 

49 

50 

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

52 """ 

53 Read the configuration file, if it exists. 

54 

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

56 find its configuration. 

57 

58 Args: 

59 config_file: The configuration file to explicitly use. 

60 

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 {} 

67 

68 config_path = Path(config_file) 

69 if not config_path.exists(): 

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

71 return {} 

72 

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

74 

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 {} 

83 

84 

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

86 """ 

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

88 

89 Args: 

90 file_path: The path to the TOML file. 

91 

92 Returns: 

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

94 """ 

95 import tomlkit 

96 

97 # Load the TOML file 

98 toml_data = tomlkit.parse(file_path.read_text(encoding="utf-8")).unwrap() 

99 

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

101 

102 

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. 

113 

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 

124 

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 

135 

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 ) 

148 

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

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

151 logger.dedent()