Skip to content

Commit d2e29fa

Browse files
ziltorudolfix
andauthored
qol: exception formatting (#2715)
* first pass formatting raise statements * added custom exception * updated Exception classes * linting & formatting * fixed tests * fix imports * capitalize argument to please mypy * add raise keyword * applied review comments * passing tests * fixed test * fixed broken check logic * format * fixes bigquery test --------- Co-authored-by: Marcin Rudolf <rudolfix@rudolfix.org>
1 parent 7245d85 commit d2e29fa

File tree

143 files changed

+806
-762
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+806
-762
lines changed

dlt/common/configuration/container.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self) -> None:
5959
def __getitem__(self, spec: Type[TInjectableContext]) -> TInjectableContext:
6060
# return existing config object or create it from spec
6161
if not is_subclass(spec, ContainerInjectableContext):
62-
raise KeyError(f"{spec.__name__} is not a context")
62+
raise KeyError(f"`{spec.__name__}` is not a context")
6363

6464
context, item = self._thread_getitem(spec)
6565
if item is None:

dlt/common/configuration/exceptions.py

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ class ConfigurationValueError(ConfigurationException, ValueError):
2323
class ContainerException(DltException):
2424
"""base exception for all exceptions related to injectable container"""
2525

26-
pass
27-
2826

2927
class ConfigProviderException(ConfigurationException):
3028
def __init__(self, provider_name: str, *args: Any) -> None:
@@ -35,8 +33,8 @@ def __init__(self, provider_name: str, *args: Any) -> None:
3533
class ConfigurationWrongTypeException(ConfigurationException):
3634
def __init__(self, _typ: type) -> None:
3735
super().__init__(
38-
f"Invalid configuration instance type {_typ}. Configuration instances must derive from"
39-
" BaseConfiguration and must be decorated with @configspec."
36+
f"Invalid configuration instance type `{_typ}`. Configuration instances must derive"
37+
" from BaseConfiguration and must be decorated with @configspec."
4038
)
4139

4240

@@ -50,14 +48,13 @@ def __init__(self, spec_name: str, traces: Mapping[str, Sequence[LookupTrace]])
5048
super().__init__(spec_name)
5149

5250
def __str__(self) -> str:
53-
msg = (
54-
f"Following fields are missing: {str(self.fields)} in configuration with spec"
55-
f" {self.spec_name}\n"
56-
)
51+
msg = f"Missing fields in configuration: {str(self.fields)} {self.spec_name}\n"
5752
for f, field_traces in self.traces.items():
58-
msg += f'\tfor field "{f}" config providers and keys were tried in following order:\n'
53+
msg += (
54+
f"\tfor field `{f}` the following (config providers, keys) were tried in order:\n"
55+
)
5956
for tr in field_traces:
60-
msg += f"\t\tIn {tr.provider} key {tr.key} was not found.\n"
57+
msg += f"\t\t({tr.provider}, {tr.key})\n"
6158

6259
from dlt.common.configuration.container import Container
6360
from dlt.common.configuration.specs import PluggableRunContext
@@ -68,14 +65,12 @@ def __str__(self) -> str:
6865
for provider in providers.providers:
6966
if provider.locations:
7067
locations = "\n".join([f"\t- {os.path.abspath(loc)}" for loc in provider.locations])
71-
msg += (
72-
f"Provider {provider.name} used following locations to load"
73-
f" values:\n{locations}\n"
74-
)
68+
msg += f"Provider `{provider.name}` loaded values from locations:\n{locations}\n"
69+
7570
if provider.is_empty:
7671
msg += (
77-
f"WARNING: provider {provider.name} is empty. Locations (ie. files) may not"
78-
" exist or may be empty.\n"
72+
f"WARNING: provider `{provider.name}` is empty. Locations (i.e., files) are"
73+
" missing or empty.\n"
7974
)
8075

8176
# check if entry point is run with path. this is common problem so warn the user
@@ -101,10 +96,7 @@ def __str__(self) -> str:
10196
" but run your script from some other folder, secrets/configs will not be"
10297
" found\n"
10398
)
104-
msg += (
105-
"Please refer to https://dlthub.com/docs/general-usage/credentials/ for more"
106-
" information\n"
107-
)
99+
msg += "Learn more: https://dlthub.com/docs/general-usage/credentials/\n"
108100
return msg
109101

110102
def attrs(self) -> Dict[str, Any]:
@@ -127,9 +119,9 @@ def __init__(self, spec_name: str, field_names: Sequence[str]) -> None:
127119
f">>> {name}: Any" for name in field_names
128120
)
129121
msg = (
130-
f"The config spec {spec_name} has dynamic type resolvers for fields: {field_names} but"
131-
" these fields are not defined in the spec.\nWhen using @resolve_type() decorator, Add"
132-
f" the fields with 'Any' or another common type hint, example:\n\n{example}"
122+
f"The config spec `{spec_name}` has dynamic type resolvers for fields: `{field_names}`"
123+
" but these fields are not defined in the spec.\nWhen using @resolve_type() decorator,"
124+
f" Add the fields with 'Any' or another common type hint, example:\n\n{example}"
133125
)
134126
super().__init__(msg)
135127

@@ -139,7 +131,8 @@ class FinalConfigFieldException(ConfigurationException):
139131

140132
def __init__(self, spec_name: str, field: str) -> None:
141133
super().__init__(
142-
f"Field {field} in spec {spec_name} is final but is being changed by a config provider"
134+
f"Field `{field}` in spec `{spec_name}` is final but is being changed by a config"
135+
" provider"
143136
)
144137

145138

@@ -151,7 +144,7 @@ def __init__(self, field_name: str, field_value: Any, hint: type) -> None:
151144
self.field_value = field_value
152145
self.hint = hint
153146
super().__init__(
154-
"Configured value for field %s cannot be coerced into type %s" % (field_name, str(hint))
147+
f"Configured value for field `{field_name}` cannot be coerced into type `{str(hint)}`"
155148
)
156149

157150

@@ -169,7 +162,7 @@ class ConfigFileNotFoundException(ConfigurationException):
169162
"""thrown when configuration file cannot be found in config folder"""
170163

171164
def __init__(self, path: str) -> None:
172-
super().__init__(f"Missing config file in {path}")
165+
super().__init__(f"Missing config file in `{path}`")
173166

174167

175168
class ConfigFieldMissingTypeHintException(ConfigurationException):
@@ -179,7 +172,7 @@ def __init__(self, field_name: str, spec: Type[Any]) -> None:
179172
self.field_name = field_name
180173
self.typ_ = spec
181174
super().__init__(
182-
f"Field {field_name} on configspec {spec} does not provide required type hint"
175+
f"Field `{field_name}` on configspec `{spec}` does not provide required type hint"
183176
)
184177

185178

@@ -190,7 +183,7 @@ def __init__(self, field_name: str, spec: Type[Any], typ_: Type[Any]) -> None:
190183
self.field_name = field_name
191184
self.typ_ = spec
192185
super().__init__(
193-
f"Field {field_name} on configspec {spec} has hint with unsupported type {typ_}"
186+
f"Field `{field_name}` on configspec `{spec}` has hint with unsupported type `{typ_}`"
194187
)
195188

196189

@@ -199,8 +192,8 @@ def __init__(self, provider_name: str, key: str) -> None:
199192
self.provider_name = provider_name
200193
self.key = key
201194
super().__init__(
202-
f"Provider {provider_name} cannot hold secret values but key {key} with secret value is"
203-
" present"
195+
f"Provider `{provider_name}` cannot hold secret values but key `{key}` with secret"
196+
" value is present"
204197
)
205198

206199

@@ -218,10 +211,9 @@ def __init__(
218211
self.inner_exception = inner_exception
219212
inner_msg = f" {self.inner_exception}" if inner_exception is not ValueError else ""
220213
super().__init__(
221-
f"{spec.__name__} cannot parse the configuration value provided. The value is of type"
222-
f" {native_value_type.__name__} and comes from the"
223-
" {embedded_sections} section(s). Value may be a secret and is not shown. "
224-
f"Details: {inner_msg}"
214+
f"`{spec.__name__}` cannot parse the configuration value provided. The value is of type"
215+
f" `{native_value_type.__name__}` and comes from the sections `{embedded_sections}`"
216+
f" Value may be a secret and is not shown. Details: {inner_msg}"
225217
)
226218

227219

@@ -231,20 +223,20 @@ def __init__(self, spec: Type[Any], existing_config: Any, expected_config: Any)
231223
self.existing_config = existing_config
232224
self.expected_config = expected_config
233225
super().__init__(
234-
f"When restoring context {spec.__name__}, instance {expected_config} was expected,"
235-
f" instead instance {existing_config} was found."
226+
f"When restoring context `{spec.__name__}`, instance `{expected_config}` was expected,"
227+
f" instead instance `{existing_config}` was found."
236228
)
237229

238230

239231
class ContextDefaultCannotBeCreated(ContainerException, KeyError):
240232
def __init__(self, spec: Type[Any]) -> None:
241233
self.spec = spec
242-
super().__init__(f"Container cannot create the default value of context {spec.__name__}.")
234+
super().__init__(f"Container cannot create the default value of context `{spec.__name__}`.")
243235

244236

245237
class DuplicateConfigProviderException(ConfigProviderException):
246238
def __init__(self, provider_name: str) -> None:
247239
super().__init__(
248240
provider_name,
249-
f"Provider with name {provider_name} already present in ConfigProvidersContext",
241+
f"Provider with name `{provider_name}` already present in `ConfigProvidersContext`",
250242
)

dlt/common/configuration/inject.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ def _wrap(*args: Any, **kwargs: Any) -> Any:
287287

288288
if not callable(func):
289289
raise ValueError(
290-
"First parameter to the with_config must be callable ie. by using it as function"
291-
" decorator"
290+
"First parameter of `with_config` must be callable i.e., by using it as a decorator"
291+
" `@with_config`"
292292
)
293293

294294
# We're called as @with_config without parens.

dlt/common/configuration/providers/google_secrets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def _list_vault(self) -> Set[str]:
173173
if status_code == 403:
174174
raise ConfigProviderException(
175175
self.name,
176-
f"Cannot list secrets: {self.credentials.client_email} does not have "
176+
f"Cannot list secrets: `{self.credentials.client_email}` does not have "
177177
"roles/secretmanager.secretViewer role. Secret listing is required when "
178178
"list_secrets=True to optimize vault access by skipping lookups for "
179179
f"non-existent secrets. Error: {error_message} [{error_status}]",

dlt/common/configuration/specs/exceptions.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class OAuth2ScopesRequired(SpecException):
1010
def __init__(self, spec: type) -> None:
1111
self.spec = spec
1212
super().__init__(
13-
"Scopes are required to retrieve refresh_token. Use 'openid' scope for a token without"
13+
"Scopes are required to retrieve refresh_token. Use `openid` scope for a token without"
1414
" any permissions to resources."
1515
)
1616

@@ -26,27 +26,27 @@ class InvalidConnectionString(NativeValueError):
2626
def __init__(self, spec: Type[Any], native_value: str, driver: str):
2727
driver = driver or "driver"
2828
msg = (
29-
f"The expected representation for {spec.__name__} is a standard database connection"
30-
f" string with the following format: {driver}://username:password@host:port/database."
29+
f"The expected representation for `{spec.__name__}` is a standard database connection"
30+
f" string with the following format: `{driver}://username:password@host:port/database`"
3131
)
3232
super().__init__(spec, native_value, msg)
3333

3434

3535
class InvalidGoogleNativeCredentialsType(NativeValueError):
3636
def __init__(self, spec: Type[Any], native_value: Any):
3737
msg = (
38-
f"Credentials {spec.__name__} accept a string with serialized credentials json file or"
39-
" an instance of Credentials object from google.* namespace. The value passed is of"
40-
f" type {type(native_value)}"
38+
f"Credentials `{spec.__name__}` accept a string with serialized credentials json file"
39+
" or an instance of `Credentials` object from Google.* namespace. The value passed is"
40+
f" of type `{type(native_value)}`"
4141
)
4242
super().__init__(spec, native_value, msg)
4343

4444

4545
class InvalidGoogleServicesJson(NativeValueError):
4646
def __init__(self, spec: Type[Any], native_value: Any):
4747
msg = (
48-
f"The expected representation for {spec.__name__} is a string with serialized service"
49-
" account credentials, where at least 'project_id', 'private_key' and 'client_email`"
48+
f"The expected representation for `{spec.__name__}` is a string with serialized service"
49+
" account credentials, where at least `project_id`, `private_key` and `client_email`"
5050
" keys are present"
5151
)
5252
super().__init__(spec, native_value, msg)
@@ -55,7 +55,7 @@ def __init__(self, spec: Type[Any], native_value: Any):
5555
class InvalidGoogleOauth2Json(NativeValueError):
5656
def __init__(self, spec: Type[Any], native_value: Any):
5757
msg = (
58-
f"The expected representation for {spec.__name__} is a string with serialized oauth2"
58+
f"The expected representation for `{spec.__name__}` is a string with serialized oauth2"
5959
" user info and may be wrapped in 'install'/'web' node - depending of oauth2 app type."
6060
)
6161
super().__init__(spec, native_value, msg)
@@ -64,7 +64,7 @@ def __init__(self, spec: Type[Any], native_value: Any):
6464
class InvalidBoto3Session(NativeValueError):
6565
def __init__(self, spec: Type[Any], native_value: Any):
6666
msg = (
67-
f"The expected representation for {spec.__name__} is and instance of boto3.Session"
67+
f"The expected representation for `{spec.__name__}` is and instance of boto3.Session"
6868
" containing credentials"
6969
)
7070
super().__init__(spec, native_value, msg)

dlt/common/configuration/specs/pluggable_run_context.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ def pop_context(self, cookie: str) -> None:
172172
"""Pops context from stack and re-initializes it if in container"""
173173
_c, context, providers, runtime_config = self._context_stack.pop()
174174
if cookie != _c:
175-
raise ValueError(f"Run context stack mangled. Got cookie {_c} but expected {cookie}")
175+
raise ValueError(
176+
f"Run context stack mangled. Got cookie `{_c}` but expected `{cookie}`"
177+
)
176178
self.runtime_config = runtime_config
177179
self.reload(context)
178180

@@ -181,4 +183,6 @@ def drop_context(self, cookie: str) -> None:
181183
state_ = self._context_stack.pop()
182184
_c = state_[0]
183185
if cookie != _c:
184-
raise ValueError(f"Run context stack mangled. Got cookie {_c} but expected {cookie}")
186+
raise ValueError(
187+
f"Run context stack mangled. Got cookie `{_c}` but expected `{cookie}`"
188+
)

dlt/common/data_types/type_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def coerce_from_date_types(
8888
return ensure_pendulum_date(v)
8989
if to_type == "time":
9090
return v.time()
91-
raise TypeError(f"Cannot convert timestamp to {to_type}")
91+
raise TypeError(f"Cannot convert timestamp to `{to_type}`")
9292

9393

9494
def coerce_value(to_type: TDataType, from_type: TDataType, value: Any) -> Any:

dlt/common/data_writers/exceptions.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,33 @@ class InvalidFileNameTemplateException(DataWriterException, ValueError):
1212
def __init__(self, file_name_template: str):
1313
self.file_name_template = file_name_template
1414
super().__init__(
15-
f"Wrong file name template {file_name_template}. File name template must contain"
15+
f"Wrong file name template `{file_name_template}`. File name template must contain"
1616
" exactly one %s formatter"
1717
)
1818

1919

2020
class BufferedDataWriterClosed(DataWriterException):
2121
def __init__(self, file_name: str):
2222
self.file_name = file_name
23-
super().__init__(f"Writer with recent file name {file_name} is already closed")
23+
super().__init__(f"Writer with recent file name `{file_name}` is already closed")
2424

2525

2626
class FileImportNotFound(DataWriterException, FileNotFoundError):
2727
def __init__(self, import_file_path: str, local_file_path: str) -> None:
2828
self.import_file_path = import_file_path
2929
self.local_file_path = local_file_path
3030
super().__init__(
31-
f"Attempt to import non existing file {import_file_path} into extract storage file"
32-
f" {local_file_path}"
31+
f"Attempt to import non existing file `{import_file_path}` into extract storage file"
32+
f" `{local_file_path}`"
3333
)
3434

3535

3636
class DestinationCapabilitiesRequired(DataWriterException, ValueError):
3737
def __init__(self, file_format: TLoaderFileFormat):
3838
self.file_format = file_format
3939
super().__init__(
40-
f"Writer for {file_format} requires destination capabilities which were not provided."
40+
f"Writer for `{file_format=:}` requires destination capabilities which were not"
41+
" provided."
4142
)
4243

4344

@@ -50,8 +51,7 @@ def __init__(self, file_format: TLoaderFileFormat, data_item_format: str):
5051
self.file_format = file_format
5152
self.data_item_format = data_item_format
5253
super().__init__(
53-
f"Can't find a file writer for file format {file_format} and item format"
54-
f" {data_item_format}"
54+
f"Can't find a file writer for `{file_format=:}` and item format `{data_item_format=:}`"
5555
)
5656

5757

@@ -60,8 +60,8 @@ def __init__(self, file_format: TLoaderFileFormat, data_item_format: str, spec:
6060
self.file_format = file_format
6161
self.data_item_format = data_item_format
6262
super().__init__(
63-
f"Can't find a file writer for spec with file format {file_format} and item format"
64-
f" {data_item_format} where the full spec is {spec}"
63+
f"Can't find a file writer for spec with `{file_format=:}` and `{data_item_format=:}`"
64+
f" where the full spec is `{spec}`"
6565
)
6666

6767

@@ -76,8 +76,8 @@ def __init__(
7676
self.possible_file_formats = possible_file_formats
7777
self.data_item_format = data_item_format
7878
super().__init__(
79-
f"Lookup for best file writer for item format {data_item_format} among file formats"
80-
f" {possible_file_formats} failed. The preferred file format was {file_format}."
79+
f"Failed to find file writer for {data_item_format=:} among file formats"
80+
f" {possible_file_formats=:}. The preferred file format was `{file_format=:}`."
8181
)
8282

8383

@@ -86,5 +86,6 @@ def __init__(self, file_format: TLoaderFileFormat, data_item_format: str, detail
8686
self.file_format = file_format
8787
self.data_item_format = data_item_format
8888
super().__init__(
89-
f"A data item of type {data_item_format} cannot be written as {file_format}: {details}"
89+
f"A data item of type {data_item_format=:} cannot be written as `{file_format}:"
90+
f" {details}`"
9091
)

0 commit comments

Comments
 (0)