Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dlt/common/configuration/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def __init__(self) -> None:
def __getitem__(self, spec: Type[TInjectableContext]) -> TInjectableContext:
# return existing config object or create it from spec
if not is_subclass(spec, ContainerInjectableContext):
raise KeyError(f"{spec.__name__} is not a context")
raise KeyError(f"`{spec.__name__}` is not a context")

context, item = self._thread_getitem(spec)
if item is None:
Expand Down
68 changes: 30 additions & 38 deletions dlt/common/configuration/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ class ConfigurationValueError(ConfigurationException, ValueError):
class ContainerException(DltException):
"""base exception for all exceptions related to injectable container"""

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

learning question: why not pass?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pass keyword is not needed since there's a docstring.

details

These are valid ways to define a "empty" class or function in Python (an "empty" function returns None):

# with a pass
class MyClass:
  pass
  
def my_fn():
  pass
  
# with a docstring
class MyClass:
  """This is my class"""

def  my_fn():
  """This is my function"""
  
# with ellipsis
class MyClass:
  ...

def my_fn():
  ...

# ellipsis is typically used inline
class MyClass: ...

def my_fn(): ...

Those are all equivalent and can be combined. Personally, I find pass to be the most ambiguous because it can be used for other purposes in loops.

"Empty" classes and functions are mostly used in typing stubs and @typing.overload to define type signatures.

# dlt.common.destination.dataset

class SupportsReadableRelation:
    # ...
    @overload
    def __getitem__(self, column: str) -> Self: ...

    @overload
    def __getitem__(self, columns: Sequence[str]) -> Self: ...

    def __getitem__(self, columns: Union[str, Sequence[str]]) -> Self:
        """Returns a new relation with the given columns selected.

        Args:
            columns (Union[str, Sequence[str]]): The columns to select.

        Returns:
            Self: The relation with the columns selected.
        """
        raise NotImplementedError("`__getitem__()` method is not supported for this relation")

pass


class ConfigProviderException(ConfigurationException):
def __init__(self, provider_name: str, *args: Any) -> None:
Expand All @@ -35,8 +33,8 @@ def __init__(self, provider_name: str, *args: Any) -> None:
class ConfigurationWrongTypeException(ConfigurationException):
def __init__(self, _typ: type) -> None:
super().__init__(
f"Invalid configuration instance type {_typ}. Configuration instances must derive from"
" BaseConfiguration and must be decorated with @configspec."
f"Invalid configuration instance type `{_typ}`. Configuration instances must derive"
" from BaseConfiguration and must be decorated with @configspec."
)


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

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

from dlt.common.configuration.container import Container
from dlt.common.configuration.specs import PluggableRunContext
Expand All @@ -68,14 +65,12 @@ def __str__(self) -> str:
for provider in providers.providers:
if provider.locations:
locations = "\n".join([f"\t- {os.path.abspath(loc)}" for loc in provider.locations])
msg += (
f"Provider {provider.name} used following locations to load"
f" values:\n{locations}\n"
)
msg += f"Provider `{provider.name}` loaded values from locations:\n{locations}\n"

if provider.is_empty:
msg += (
f"WARNING: provider {provider.name} is empty. Locations (ie. files) may not"
" exist or may be empty.\n"
f"WARNING: provider `{provider.name}` is empty. Locations (i.e., files) are"
" missing or empty.\n"
)

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

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

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

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


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


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

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


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


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


Expand All @@ -199,8 +192,8 @@ def __init__(self, provider_name: str, key: str) -> None:
self.provider_name = provider_name
self.key = key
super().__init__(
f"Provider {provider_name} cannot hold secret values but key {key} with secret value is"
" present"
f"Provider `{provider_name}` cannot hold secret values but key `{key}` with secret"
" value is present"
)


Expand All @@ -218,10 +211,9 @@ def __init__(
self.inner_exception = inner_exception
inner_msg = f" {self.inner_exception}" if inner_exception is not ValueError else ""
super().__init__(
f"{spec.__name__} cannot parse the configuration value provided. The value is of type"
f" {native_value_type.__name__} and comes from the"
" {embedded_sections} section(s). Value may be a secret and is not shown. "
f"Details: {inner_msg}"
f"`{spec.__name__}` cannot parse the configuration value provided. The value is of type"
f" `{native_value_type.__name__}` and comes from the sections `{embedded_sections}`"
f" Value may be a secret and is not shown. Details: {inner_msg}"
)


Expand All @@ -231,20 +223,20 @@ def __init__(self, spec: Type[Any], existing_config: Any, expected_config: Any)
self.existing_config = existing_config
self.expected_config = expected_config
super().__init__(
f"When restoring context {spec.__name__}, instance {expected_config} was expected,"
f" instead instance {existing_config} was found."
f"When restoring context `{spec.__name__}`, instance `{expected_config}` was expected,"
f" instead instance `{existing_config}` was found."
)


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


class DuplicateConfigProviderException(ConfigProviderException):
def __init__(self, provider_name: str) -> None:
super().__init__(
provider_name,
f"Provider with name {provider_name} already present in ConfigProvidersContext",
f"Provider with name `{provider_name}` already present in `ConfigProvidersContext`",
)
4 changes: 2 additions & 2 deletions dlt/common/configuration/inject.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ def _wrap(*args: Any, **kwargs: Any) -> Any:

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

# We're called as @with_config without parens.
Expand Down
2 changes: 1 addition & 1 deletion dlt/common/configuration/providers/google_secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def _list_vault(self) -> Set[str]:
if status_code == 403:
raise ConfigProviderException(
self.name,
f"Cannot list secrets: {self.credentials.client_email} does not have "
f"Cannot list secrets: `{self.credentials.client_email}` does not have "
"roles/secretmanager.secretViewer role. Secret listing is required when "
"list_secrets=True to optimize vault access by skipping lookups for "
f"non-existent secrets. Error: {error_message} [{error_status}]",
Expand Down
20 changes: 10 additions & 10 deletions dlt/common/configuration/specs/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class OAuth2ScopesRequired(SpecException):
def __init__(self, spec: type) -> None:
self.spec = spec
super().__init__(
"Scopes are required to retrieve refresh_token. Use 'openid' scope for a token without"
"Scopes are required to retrieve refresh_token. Use `openid` scope for a token without"
" any permissions to resources."
)

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


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


class InvalidGoogleServicesJson(NativeValueError):
def __init__(self, spec: Type[Any], native_value: Any):
msg = (
f"The expected representation for {spec.__name__} is a string with serialized service"
" account credentials, where at least 'project_id', 'private_key' and 'client_email`"
f"The expected representation for `{spec.__name__}` is a string with serialized service"
" account credentials, where at least `project_id`, `private_key` and `client_email`"
" keys are present"
)
super().__init__(spec, native_value, msg)
Expand All @@ -55,7 +55,7 @@ def __init__(self, spec: Type[Any], native_value: Any):
class InvalidGoogleOauth2Json(NativeValueError):
def __init__(self, spec: Type[Any], native_value: Any):
msg = (
f"The expected representation for {spec.__name__} is a string with serialized oauth2"
f"The expected representation for `{spec.__name__}` is a string with serialized oauth2"
" user info and may be wrapped in 'install'/'web' node - depending of oauth2 app type."
)
super().__init__(spec, native_value, msg)
Expand All @@ -64,7 +64,7 @@ def __init__(self, spec: Type[Any], native_value: Any):
class InvalidBoto3Session(NativeValueError):
def __init__(self, spec: Type[Any], native_value: Any):
msg = (
f"The expected representation for {spec.__name__} is and instance of boto3.Session"
f"The expected representation for `{spec.__name__}` is and instance of boto3.Session"
" containing credentials"
)
super().__init__(spec, native_value, msg)
Expand Down
8 changes: 6 additions & 2 deletions dlt/common/configuration/specs/pluggable_run_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ def pop_context(self, cookie: str) -> None:
"""Pops context from stack and re-initializes it if in container"""
_c, context, providers, runtime_config = self._context_stack.pop()
if cookie != _c:
raise ValueError(f"Run context stack mangled. Got cookie {_c} but expected {cookie}")
raise ValueError(
f"Run context stack mangled. Got cookie `{_c}` but expected `{cookie}`"
)
self.runtime_config = runtime_config
self.reload(context)

Expand All @@ -181,4 +183,6 @@ def drop_context(self, cookie: str) -> None:
state_ = self._context_stack.pop()
_c = state_[0]
if cookie != _c:
raise ValueError(f"Run context stack mangled. Got cookie {_c} but expected {cookie}")
raise ValueError(
f"Run context stack mangled. Got cookie `{_c}` but expected `{cookie}`"
)
2 changes: 1 addition & 1 deletion dlt/common/data_types/type_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def coerce_from_date_types(
return ensure_pendulum_date(v)
if to_type == "time":
return v.time()
raise TypeError(f"Cannot convert timestamp to {to_type}")
raise TypeError(f"Cannot convert timestamp to `{to_type}`")


def coerce_value(to_type: TDataType, from_type: TDataType, value: Any) -> Any:
Expand Down
25 changes: 13 additions & 12 deletions dlt/common/data_writers/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,33 @@ class InvalidFileNameTemplateException(DataWriterException, ValueError):
def __init__(self, file_name_template: str):
self.file_name_template = file_name_template
super().__init__(
f"Wrong file name template {file_name_template}. File name template must contain"
f"Wrong file name template `{file_name_template}`. File name template must contain"
" exactly one %s formatter"
)


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


class FileImportNotFound(DataWriterException, FileNotFoundError):
def __init__(self, import_file_path: str, local_file_path: str) -> None:
self.import_file_path = import_file_path
self.local_file_path = local_file_path
super().__init__(
f"Attempt to import non existing file {import_file_path} into extract storage file"
f" {local_file_path}"
f"Attempt to import non existing file `{import_file_path}` into extract storage file"
f" `{local_file_path}`"
)


class DestinationCapabilitiesRequired(DataWriterException, ValueError):
def __init__(self, file_format: TLoaderFileFormat):
self.file_format = file_format
super().__init__(
f"Writer for {file_format} requires destination capabilities which were not provided."
f"Writer for `{file_format=:}` requires destination capabilities which were not"
" provided."
)


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


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


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


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