Skip to content

Commit 6f48238

Browse files
Improve error string formatting for consistency (#818)
* Improve error string formatting for consistency End in full stops, use quote marks for variable quantities, cosmetic changes * Tweak error message to reflect new behaviour
1 parent e059276 commit 6f48238

File tree

23 files changed

+55
-56
lines changed

23 files changed

+55
-56
lines changed

src/usethis/_integrations/ci/bitbucket/dump.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def bitbucket_fancy_dump(
3131
if not isinstance(dump, dict):
3232
msg = (
3333
f"Invalid '{type(config)}' representation when dumping; expected dict, got "
34-
f"{type(dump)}"
34+
f"{type(dump)}."
3535
)
3636
raise TypeError(msg)
3737

src/usethis/_integrations/ci/bitbucket/steps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def _add_step_in_default_via_doc(
126126
try:
127127
script_item = _SCRIPT_ITEM_LOOKUP[script_item.name]
128128
except KeyError:
129-
msg = f"Unrecognized script item anchor: {script_item.name}"
129+
msg = f"Unrecognized script item anchor: '{script_item.name}'."
130130
raise NotImplementedError(msg) from None
131131

132132
if config.definitions is None:

src/usethis/_integrations/ci/github/tags.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ def get_github_latest_tag(owner: str, repo: str) -> str:
3030
response = requests.get(api_url, timeout=1)
3131
response.raise_for_status() # Raise an error for HTTP issues
3232
except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as err:
33-
msg = f"Failed to fetch tags from GitHub API: {err}"
33+
msg = f"Failed to fetch tags from GitHub API:\n{err}"
3434
raise GitHubTagError(msg) from None
3535

3636
tags = response.json()
3737

3838
if not tags:
39-
msg = f"No tags found for repository '{owner}/{repo}'"
39+
msg = f"No tags found for repository '{owner}/{repo}'."
4040
raise NoGitHubTagsFoundError(msg)
4141

4242
# Most recent tag's name

src/usethis/_integrations/file/ini/io_.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def read_file(self) -> None:
5656
except UnexpectedFileIOError as err:
5757
raise UnexpectedINIIOError(err) from None
5858
except configparser.ParsingError as err:
59-
msg = f"Failed to decode '{self.name}': {err}"
59+
msg = f"Failed to decode '{self.name}':\n{err}"
6060
raise INIDecodeError(msg) from None
6161

6262
def _dump_content(self) -> str:
@@ -142,7 +142,7 @@ def __getitem__(self, item: Sequence[Key]) -> Any:
142142
else:
143143
msg = (
144144
f"INI files do not support nested config, whereas access to "
145-
f"'{self.name}' was attempted at '{print_keys(keys)}'"
145+
f"'{self.name}' was attempted at '{print_keys(keys)}'."
146146
)
147147
raise KeyError(msg)
148148

@@ -174,7 +174,7 @@ def set_value(
174174
else:
175175
msg = (
176176
f"INI files do not support nested config, whereas access to "
177-
f"'{self.name}' was attempted at '{print_keys(keys)}'"
177+
f"'{self.name}' was attempted at '{print_keys(keys)}'."
178178
)
179179
raise ININestingError(msg)
180180

@@ -187,7 +187,7 @@ def _set_value_in_root(
187187
root_dict = value
188188

189189
if any(root) and not exists_ok:
190-
msg = "The INI file already has content at the root level"
190+
msg = "The INI file already has content at the root level."
191191
raise INIValueAlreadySetError(msg)
192192

193193
# We need to remove section that are not in the new dict
@@ -237,7 +237,9 @@ def _set_value_in_section(
237237

238238
if section_key in root:
239239
if not exists_ok:
240-
msg = f"The INI file already has content at the section '{section_key}'"
240+
msg = (
241+
f"The INI file already has content at the section '{section_key}'."
242+
)
241243
raise INIValueAlreadySetError(msg)
242244

243245
if not isinstance(section_key, str):
@@ -282,7 +284,7 @@ def _set_value_in_option(
282284
if root.has_option(section=section_key, option=option_key) and not exists_ok:
283285
msg = (
284286
f"The INI file already has content at the section '{section_key}' "
285-
f"and option '{option_key}'"
287+
f"and option '{option_key}'."
286288
)
287289
raise INIValueAlreadySetError(msg)
288290

@@ -371,14 +373,12 @@ def __delitem__(self, keys: Sequence[Key]) -> None:
371373
else:
372374
msg = (
373375
f"INI files do not support nested config, whereas access to "
374-
f"'{self.name}' was attempted at '{print_keys(keys)}'"
376+
f"'{self.name}' was attempted at '{print_keys(keys)}'."
375377
)
376378
raise ININestingError(msg)
377379

378380
if not seqs:
379-
msg = (
380-
f"INI file '{self.name}' does not contain the keys '{print_keys(keys)}'"
381-
)
381+
msg = f"INI file '{self.name}' does not contain the keys '{print_keys(keys)}'."
382382
raise INIValueMissingError(msg)
383383

384384
for seq in seqs:
@@ -412,12 +412,12 @@ def _delete_strkeys(self, strkeys: Sequence[str]) -> None:
412412
else:
413413
msg = (
414414
f"INI files do not support nested config, whereas access to "
415-
f"'{self.name}' was attempted at '{print_keys(strkeys)}'"
415+
f"'{self.name}' was attempted at '{print_keys(strkeys)}'."
416416
)
417417
raise ININestingError(msg)
418418

419419
if not removed:
420-
msg = f"INI file '{self.name}' does not contain the keys '{print_keys(strkeys)}'"
420+
msg = f"INI file '{self.name}' does not contain the keys '{print_keys(strkeys)}'."
421421
raise INIValueMissingError(msg)
422422

423423
self.commit(root)
@@ -432,13 +432,13 @@ def extend_list(self, *, keys: Sequence[Key], values: list[str]) -> None:
432432
if len(keys) == 0:
433433
msg = (
434434
f"INI files do not support lists at the root level, whereas access to "
435-
f"'{self.name}' was attempted at '{print_keys(keys)}'"
435+
f"'{self.name}' was attempted at '{print_keys(keys)}'."
436436
)
437437
raise InvalidINITypeError(msg)
438438
elif len(keys) == 1:
439439
msg = (
440440
f"INI files do not support lists at the section level, whereas access "
441-
f"to '{self.name}' was attempted at '{print_keys(keys)}'"
441+
f"to '{self.name}' was attempted at '{print_keys(keys)}'."
442442
)
443443
raise InvalidINITypeError(msg)
444444
elif len(keys) == 2:
@@ -449,7 +449,7 @@ def extend_list(self, *, keys: Sequence[Key], values: list[str]) -> None:
449449
else:
450450
msg = (
451451
f"INI files do not support nested config, whereas access to "
452-
f"'{self.name}' was attempted at '{print_keys(keys)}'"
452+
f"'{self.name}' was attempted at '{print_keys(keys)}'."
453453
)
454454
raise ININestingError(msg)
455455

@@ -509,13 +509,13 @@ def remove_from_list(self, *, keys: Sequence[Key], values: list[str]) -> None:
509509
if len(keys) == 0:
510510
msg = (
511511
f"INI files do not support lists at the root level, whereas access to "
512-
f"'{self.name}' was attempted at '{print_keys(keys)}'"
512+
f"'{self.name}' was attempted at '{print_keys(keys)}'."
513513
)
514514
raise InvalidINITypeError(msg)
515515
elif len(keys) == 1:
516516
msg = (
517517
f"INI files do not support lists at the section level, whereas access "
518-
f"to '{self.name}' was attempted at '{print_keys(keys)}'"
518+
f"to '{self.name}' was attempted at '{print_keys(keys)}'."
519519
)
520520
raise InvalidINITypeError(msg)
521521
elif len(keys) == 2:
@@ -526,7 +526,7 @@ def remove_from_list(self, *, keys: Sequence[Key], values: list[str]) -> None:
526526
else:
527527
msg = (
528528
f"INI files do not support nested config, whereas access to "
529-
f"'{self.name}' was attempted at '{print_keys(keys)}'"
529+
f"'{self.name}' was attempted at '{print_keys(keys)}'."
530530
)
531531
raise ININestingError(msg)
532532

src/usethis/_integrations/file/pyproject_toml/name.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ def get_name() -> str:
1919
msg = "The 'project.name' value is missing from 'pyproject.toml'."
2020
raise PyprojectTOMLProjectNameError(msg) from None
2121
except ValidationError as err:
22-
msg = (
23-
f"The 'project.name' value in 'pyproject.toml' is not a valid string: {err}"
24-
)
22+
msg = f"The 'project.name' value in 'pyproject.toml' is not a valid string:\n{err}"
2523
raise PyprojectTOMLProjectNameError(msg) from None
2624

2725
return name
@@ -36,7 +34,7 @@ def get_description() -> str:
3634
msg = "The 'project.description' value is missing from 'pyproject.toml'."
3735
raise PyprojectTOMLProjectDescriptionError(msg) from None
3836
except ValidationError as err:
39-
msg = f"The 'project.description' value in 'pyproject.toml' is not a valid string: {err}"
37+
msg = f"The 'project.description' value in 'pyproject.toml' is not a valid string:\n{err}"
4038
raise PyprojectTOMLProjectDescriptionError(msg) from None
4139

4240
return description

src/usethis/_integrations/file/pyproject_toml/project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def get_project_dict() -> dict[str, Any]:
2222
msg = "The 'project' section is missing from 'pyproject.toml'."
2323
raise PyprojectTOMLProjectSectionError(msg) from None
2424
except ValidationError as err:
25-
msg = f"The 'project' section in 'pyproject.toml' is not a valid map: {err}"
25+
msg = f"The 'project' section in 'pyproject.toml' is not a valid map:\n{err}"
2626
raise PyprojectTOMLProjectSectionError(msg) from None
2727

2828
return project

src/usethis/_integrations/file/pyproject_toml/valid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def _ensure_project_section(toml_document: TOMLDocument) -> Table:
3737

3838
project = toml_document["project"]
3939
if not isinstance(project, Table):
40-
msg = f"Expected 'project' to be a TOML Table, got {type(project)}."
40+
msg = f"Expected 'project' to be a TOML Table, got '{type(project)}'."
4141
raise TypeError(msg)
4242

4343
return project

src/usethis/_integrations/file/toml/io_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def read_file(self) -> None:
6161
except UnexpectedFileIOError as err:
6262
raise UnexpectedTOMLIOError(err) from None
6363
except TOMLKitError as err:
64-
msg = f"Failed to decode '{self.name}': {err}"
64+
msg = f"Failed to decode '{self.name}':\n{err}"
6565
raise TOMLDecodeError(msg) from None
6666

6767
def _dump_content(self) -> str:

src/usethis/_integrations/file/yaml/update.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def update_ruamel_yaml_map(
3333
"""
3434
"""Update the values of a ruamel.yaml map in-place using a diff-like algorithm."""
3535
if not isinstance(cmap, CommentedMap):
36-
msg = f"Expected CommentedMap, but got {type(cmap)}."
36+
msg = f"Expected CommentedMap, but got '{type(cmap)}'."
3737
raise TypeError(msg)
3838

3939
if not preserve_comments:

src/usethis/_integrations/pre_commit/dump.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def pre_commit_fancy_dump(
2121
if not isinstance(dump, dict):
2222
msg = (
2323
f"Invalid '{type(config)}' representation when dumping; expected dict, got "
24-
f"{type(dump)}"
24+
f"'{type(dump)}'."
2525
)
2626
raise TypeError(msg)
2727

src/usethis/_integrations/pre_commit/hooks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def add_repo(repo: LocalRepo | UriRepo) -> None:
4949
(hook_config,) = repo.hooks
5050

5151
if hook_config.id is None:
52-
msg = "Hook ID must be specified"
52+
msg = "The hook ID must be specified."
5353
raise ValueError(msg)
5454

5555
# Ordered list of the hooks already in the file
@@ -72,7 +72,7 @@ def add_repo(repo: LocalRepo | UriRepo) -> None:
7272
try:
7373
hook_idx = _HOOK_ORDER.index(hook_config.id)
7474
except ValueError:
75-
msg = f"Hook '{hook_config.id}' not recognized"
75+
msg = f"Hook '{hook_config.id}' not recognized."
7676
raise NotImplementedError(msg) from None
7777
precedents = _HOOK_ORDER[:hook_idx]
7878
successors = _HOOK_ORDER[hook_idx + 1 :]

src/usethis/_integrations/sonarqube/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def get_sonar_project_properties() -> str:
8686
def _get_short_version(version: str) -> str:
8787
match = re.match(r"^(\d{1,2}\.\d{1,2})", version)
8888
if match is None:
89-
msg = f"Could not parse Python version from {version}"
89+
msg = f"Could not parse Python version from '{version}'."
9090
raise _NonstandardPythonVersionError(msg)
9191

9292
return match.group(1)
@@ -109,5 +109,5 @@ def _validate_project_key(project_key: str) -> None:
109109
"""
110110
_RE = r"^[a-zA-Z0-9\-_:.]+$"
111111
if re.match(_RE, project_key) is None or project_key.isdigit():
112-
msg = f"Invalid SonarQube project key: {project_key}"
112+
msg = f"Invalid SonarQube project key: '{project_key}'."
113113
raise InvalidSonarQubeProjectKeyError(msg)

src/usethis/_integrations/uv/python.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def _parse_python_version_from_uv_output(version: str) -> str:
4343
if match:
4444
return match.group(1)
4545
else:
46-
msg = f"Could not parse version from {version}"
46+
msg = f"Could not parse version from '{version}'."
4747
raise UVUnparsedPythonVersionError(msg)
4848

4949

src/usethis/_io.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def read_file(self) -> None:
132132
try:
133133
self._content = self._parse_content(self.path.read_text())
134134
except FileNotFoundError:
135-
msg = f"'{self.name}' not found in the current directory at '{self.path}'"
135+
msg = f"'{self.name}' not found in the current directory at '{self.path}'."
136136
raise FileNotFoundError(msg) from None
137137

138138
@abstractmethod
@@ -157,7 +157,7 @@ def _validate_lock(self) -> None:
157157
if not self.is_locked():
158158
msg = (
159159
f"The '{self.name}' file has not been opened yet. Please enter the "
160-
f"context manager, e.g. 'with {self.__class__.__name__}():'"
160+
f"context manager, e.g. 'with {self.__class__.__name__}():'."
161161
)
162162
raise UnexpectedFileIOError(msg)
163163

src/usethis/_pipeweld/func.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ def _flatten_partition(partition: Partition) -> Series:
297297
partition.postrequisite_component,
298298
)
299299
if component is None:
300-
msg = "Flatten failed: no components"
300+
msg = "Flatten failed: no components."
301301
raise ValueError(msg)
302302
return component
303303

@@ -584,7 +584,7 @@ def get_endpoint(component: str | Series | DepGroup | Parallel) -> str:
584584
except ValueError:
585585
pass
586586

587-
msg = """No endpoints are defined for a Series with no steps"""
587+
msg = "No endpoints are defined for a Series with no steps."
588588
raise ValueError(msg)
589589
elif isinstance(component, Parallel):
590590
endpoints = []
@@ -594,7 +594,7 @@ def get_endpoint(component: str | Series | DepGroup | Parallel) -> str:
594594
# Any endpoint will do so choose the first one
595595
# alphabetically
596596
if not endpoints:
597-
msg = """No endpoints are defined for a Parallel block with no steps"""
597+
msg = "No endpoints are defined for a Parallel block with no steps."
598598
raise ValueError(msg)
599599
return sorted(endpoints)[0]
600600
elif isinstance(component, DepGroup):

src/usethis/_tool/base.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ def _get_active_config_file_managers_from_resolution(
325325
msg = (
326326
f"The preferred file manager '{preferred_file_manager}' is not "
327327
f"among the file managers '{file_managers}' for the tool "
328-
f"'{self.name}'"
328+
f"'{self.name}'."
329329
)
330330
raise NotImplementedError(msg)
331331
return {preferred_file_manager}
@@ -385,7 +385,7 @@ def add_configs(self) -> None:
385385

386386
if not file_managers:
387387
if config_item.applies_to_all:
388-
msg = f"No active config file managers found for one of the '{self.name}' config items"
388+
msg = f"No active config file managers found for one of the '{self.name}' config items."
389389
raise NotImplementedError(msg)
390390
else:
391391
# Early exist; this config item is not managed by any active files
@@ -399,9 +399,7 @@ def add_configs(self) -> None:
399399
in {file_manager.relative_path for file_manager in file_managers}
400400
]
401401
if not config_entries:
402-
msg = (
403-
f"No config entries found for one of the '{self.name}' config items"
404-
)
402+
msg = f"No config entries found for one of the '{self.name}' config items."
405403
raise NotImplementedError(msg)
406404
if len(config_entries) != 1:
407405
msg = (

src/usethis/_tool/impl/import_linter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def _is_root_package_singular(self) -> bool:
307307
elif isinstance(file_manager, SetupCFGManager | DotImportLinterManager):
308308
return ["importlinter", "root_package"] in file_manager
309309
else:
310-
msg = f"Unsupported file manager: {file_manager}"
310+
msg = f"Unsupported file manager: '{file_manager}'."
311311
raise NotImplementedError(msg)
312312

313313
def get_pre_commit_config(self) -> PreCommitConfig:

src/usethis/_tool/impl/pytest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def get_active_config_file_managers(self) -> set[KeyValueFileManager]:
203203
msg = (
204204
f"The preferred file manager '{preferred_file_manager}' is not "
205205
f"among the file managers '{file_managers}' for the tool "
206-
f"'{self.name}'"
206+
f"'{self.name}'."
207207
)
208208
raise NotImplementedError(msg)
209209
return {preferred_file_manager}

0 commit comments

Comments
 (0)