Blacksmith API

blacksmith.scan(*modules: str) None

Collect all resources to fillout the registry.

Basically, it import modules registered using blacksmith.register().

Raises:
  • TypeError – malformed module name

  • ModuleNotFoundError – unknown package name

  • AttributeError – argument is a module, not a package.

blacksmith.register(client_name: str, resource: str, service: str, version: str | None, path: str | None = None, contract: Mapping[Literal['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], tuple[Any, type[Response] | None]] | None = None, collection_path: str | None = None, collection_contract: Mapping[Literal['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], tuple[Any, type[Response] | None]] | None = None, collection_parser: type[AbstractCollectionParser] | None = None) None

Register a resource in a client in the default registry.

See blacksmith.domain.registry.Registry.register() for the signature.

class blacksmith.Request

Request Params Model.

Fields must use subclass PathInfoField(), HeaderField(), QueryStringField() or PostBodyField() to declare each fields.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class blacksmith.Response

Response Model.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

blacksmith.HeaderField(default: Any = PydanticUndefined, *, default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = PydanticUndefined, alias: str | None = PydanticUndefined, alias_priority: int | None = PydanticUndefined, validation_alias: str | AliasPath | AliasChoices | None = PydanticUndefined, serialization_alias: str | None = PydanticUndefined, title: str | None = PydanticUndefined, field_title_generator: Callable[[str, FieldInfo], str] | None = PydanticUndefined, description: str | None = PydanticUndefined, examples: list[Any] | None = PydanticUndefined, exclude: bool | None = PydanticUndefined, discriminator: str | types.Discriminator | None = PydanticUndefined, deprecated: Deprecated | str | bool | None = PydanticUndefined, json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = {'location': 'headers'}, frozen: bool | None = PydanticUndefined, validate_default: bool | None = PydanticUndefined, repr: bool = PydanticUndefined, init: bool | None = PydanticUndefined, init_var: bool | None = PydanticUndefined, kw_only: bool | None = PydanticUndefined, pattern: str | Pattern[str] | None = PydanticUndefined, strict: bool | None = PydanticUndefined, coerce_numbers_to_str: bool | None = PydanticUndefined, gt: annotated_types.SupportsGt | None = PydanticUndefined, ge: annotated_types.SupportsGe | None = PydanticUndefined, lt: annotated_types.SupportsLt | None = PydanticUndefined, le: annotated_types.SupportsLe | None = PydanticUndefined, multiple_of: float | None = PydanticUndefined, allow_inf_nan: bool | None = PydanticUndefined, max_digits: int | None = PydanticUndefined, decimal_places: int | None = PydanticUndefined, min_length: int | None = PydanticUndefined, max_length: int | None = PydanticUndefined, union_mode: Literal['smart', 'left_to_right'] = PydanticUndefined, fail_fast: bool | None = PydanticUndefined, **extra: Unpack[_EmptyKwargs]) Any

Usage docs: https://docs.pydantic.dev/2.10/concepts/fields

Create a field for objects that can be configured.

Used to provide extra information about a field, either for the model schema or complex validation. Some arguments apply only to number fields (int, float, Decimal) and some apply only to str.

Note:
  • Any _Unset objects will be replaced by the corresponding value defined in the _DefaultValues dictionary. If a key for the _Unset object is not found in the _DefaultValues dictionary, it will default to None

Args:

default: Default value if the field is not set. default_factory: A callable to generate the default value. The callable can either take 0 arguments

(in which case it is called as is) or a single argument containing the already validated data.

alias: The name to use for the attribute when validating or serializing by alias.

This is often used for things like converting between snake and camel case.

alias_priority: Priority of the alias. This affects whether an alias generator is used. validation_alias: Like alias, but only affects validation, not serialization. serialization_alias: Like alias, but only affects serialization, not validation. title: Human-readable title. field_title_generator: A callable that takes a field name and returns title for it. description: Human-readable description. examples: Example values for this field. exclude: Whether to exclude the field from the model serialization. discriminator: Field name or Discriminator for discriminating the type in a tagged union. deprecated: A deprecation message, an instance of warnings.deprecated or the typing_extensions.deprecated backport,

or a boolean. If True, a default deprecation message will be emitted when accessing the field.

json_schema_extra: A dict or callable to provide extra JSON schema properties. frozen: Whether the field is frozen. If true, attempts to change the value on an instance will raise an error. validate_default: If True, apply validation to the default value every time you create an instance.

Otherwise, for performance reasons, the default value of the field is trusted and not validated.

repr: A boolean indicating whether to include the field in the __repr__ output. init: Whether the field should be included in the constructor of the dataclass.

(Only applies to dataclasses.)

init_var: Whether the field should _only_ be included in the constructor of the dataclass.

(Only applies to dataclasses.)

kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass.

(Only applies to dataclasses.)

coerce_numbers_to_str: Whether to enable coercion of any Number type to str (not applicable in strict mode). strict: If True, strict validation is applied to the field.

See [Strict Mode](../concepts/strict_mode.md) for details.

gt: Greater than. If set, value must be greater than this. Only applicable to numbers. ge: Greater than or equal. If set, value must be greater than or equal to this. Only applicable to numbers. lt: Less than. If set, value must be less than this. Only applicable to numbers. le: Less than or equal. If set, value must be less than or equal to this. Only applicable to numbers. multiple_of: Value must be a multiple of this. Only applicable to numbers. min_length: Minimum length for iterables. max_length: Maximum length for iterables. pattern: Pattern for strings (a regular expression). allow_inf_nan: Allow inf, -inf, nan. Only applicable to numbers. max_digits: Maximum number of allow digits for strings. decimal_places: Maximum number of decimal places allowed for numbers. union_mode: The strategy to apply when validating a union. Can be smart (the default), or left_to_right.

See [Union Mode](../concepts/unions.md#union-modes) for details.

fail_fast: If True, validation will stop on the first error. If False, all validation errors will be collected.

This option can be applied only to iterable types (list, tuple, set, and frozenset).

extra: (Deprecated) Extra fields that will be included in the JSON schema.

!!! warning Deprecated

The extra kwargs is deprecated. Use json_schema_extra instead.

Returns:
A new [FieldInfo][pydantic.fields.FieldInfo]. The return annotation is Any so Field can be used on

type-annotated fields without causing a type error.

blacksmith.PathInfoField(default: Any = PydanticUndefined, *, default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = PydanticUndefined, alias: str | None = PydanticUndefined, alias_priority: int | None = PydanticUndefined, validation_alias: str | AliasPath | AliasChoices | None = PydanticUndefined, serialization_alias: str | None = PydanticUndefined, title: str | None = PydanticUndefined, field_title_generator: Callable[[str, FieldInfo], str] | None = PydanticUndefined, description: str | None = PydanticUndefined, examples: list[Any] | None = PydanticUndefined, exclude: bool | None = PydanticUndefined, discriminator: str | types.Discriminator | None = PydanticUndefined, deprecated: Deprecated | str | bool | None = PydanticUndefined, json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = {'location': 'path'}, frozen: bool | None = PydanticUndefined, validate_default: bool | None = PydanticUndefined, repr: bool = PydanticUndefined, init: bool | None = PydanticUndefined, init_var: bool | None = PydanticUndefined, kw_only: bool | None = PydanticUndefined, pattern: str | Pattern[str] | None = PydanticUndefined, strict: bool | None = PydanticUndefined, coerce_numbers_to_str: bool | None = PydanticUndefined, gt: annotated_types.SupportsGt | None = PydanticUndefined, ge: annotated_types.SupportsGe | None = PydanticUndefined, lt: annotated_types.SupportsLt | None = PydanticUndefined, le: annotated_types.SupportsLe | None = PydanticUndefined, multiple_of: float | None = PydanticUndefined, allow_inf_nan: bool | None = PydanticUndefined, max_digits: int | None = PydanticUndefined, decimal_places: int | None = PydanticUndefined, min_length: int | None = PydanticUndefined, max_length: int | None = PydanticUndefined, union_mode: Literal['smart', 'left_to_right'] = PydanticUndefined, fail_fast: bool | None = PydanticUndefined, **extra: Unpack[_EmptyKwargs]) Any

Usage docs: https://docs.pydantic.dev/2.10/concepts/fields

Create a field for objects that can be configured.

Used to provide extra information about a field, either for the model schema or complex validation. Some arguments apply only to number fields (int, float, Decimal) and some apply only to str.

Note:
  • Any _Unset objects will be replaced by the corresponding value defined in the _DefaultValues dictionary. If a key for the _Unset object is not found in the _DefaultValues dictionary, it will default to None

Args:

default: Default value if the field is not set. default_factory: A callable to generate the default value. The callable can either take 0 arguments

(in which case it is called as is) or a single argument containing the already validated data.

alias: The name to use for the attribute when validating or serializing by alias.

This is often used for things like converting between snake and camel case.

alias_priority: Priority of the alias. This affects whether an alias generator is used. validation_alias: Like alias, but only affects validation, not serialization. serialization_alias: Like alias, but only affects serialization, not validation. title: Human-readable title. field_title_generator: A callable that takes a field name and returns title for it. description: Human-readable description. examples: Example values for this field. exclude: Whether to exclude the field from the model serialization. discriminator: Field name or Discriminator for discriminating the type in a tagged union. deprecated: A deprecation message, an instance of warnings.deprecated or the typing_extensions.deprecated backport,

or a boolean. If True, a default deprecation message will be emitted when accessing the field.

json_schema_extra: A dict or callable to provide extra JSON schema properties. frozen: Whether the field is frozen. If true, attempts to change the value on an instance will raise an error. validate_default: If True, apply validation to the default value every time you create an instance.

Otherwise, for performance reasons, the default value of the field is trusted and not validated.

repr: A boolean indicating whether to include the field in the __repr__ output. init: Whether the field should be included in the constructor of the dataclass.

(Only applies to dataclasses.)

init_var: Whether the field should _only_ be included in the constructor of the dataclass.

(Only applies to dataclasses.)

kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass.

(Only applies to dataclasses.)

coerce_numbers_to_str: Whether to enable coercion of any Number type to str (not applicable in strict mode). strict: If True, strict validation is applied to the field.

See [Strict Mode](../concepts/strict_mode.md) for details.

gt: Greater than. If set, value must be greater than this. Only applicable to numbers. ge: Greater than or equal. If set, value must be greater than or equal to this. Only applicable to numbers. lt: Less than. If set, value must be less than this. Only applicable to numbers. le: Less than or equal. If set, value must be less than or equal to this. Only applicable to numbers. multiple_of: Value must be a multiple of this. Only applicable to numbers. min_length: Minimum length for iterables. max_length: Maximum length for iterables. pattern: Pattern for strings (a regular expression). allow_inf_nan: Allow inf, -inf, nan. Only applicable to numbers. max_digits: Maximum number of allow digits for strings. decimal_places: Maximum number of decimal places allowed for numbers. union_mode: The strategy to apply when validating a union. Can be smart (the default), or left_to_right.

See [Union Mode](../concepts/unions.md#union-modes) for details.

fail_fast: If True, validation will stop on the first error. If False, all validation errors will be collected.

This option can be applied only to iterable types (list, tuple, set, and frozenset).

extra: (Deprecated) Extra fields that will be included in the JSON schema.

!!! warning Deprecated

The extra kwargs is deprecated. Use json_schema_extra instead.

Returns:
A new [FieldInfo][pydantic.fields.FieldInfo]. The return annotation is Any so Field can be used on

type-annotated fields without causing a type error.

blacksmith.PostBodyField(default: Any = PydanticUndefined, *, default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = PydanticUndefined, alias: str | None = PydanticUndefined, alias_priority: int | None = PydanticUndefined, validation_alias: str | AliasPath | AliasChoices | None = PydanticUndefined, serialization_alias: str | None = PydanticUndefined, title: str | None = PydanticUndefined, field_title_generator: Callable[[str, FieldInfo], str] | None = PydanticUndefined, description: str | None = PydanticUndefined, examples: list[Any] | None = PydanticUndefined, exclude: bool | None = PydanticUndefined, discriminator: str | types.Discriminator | None = PydanticUndefined, deprecated: Deprecated | str | bool | None = PydanticUndefined, json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = {'location': 'body'}, frozen: bool | None = PydanticUndefined, validate_default: bool | None = PydanticUndefined, repr: bool = PydanticUndefined, init: bool | None = PydanticUndefined, init_var: bool | None = PydanticUndefined, kw_only: bool | None = PydanticUndefined, pattern: str | Pattern[str] | None = PydanticUndefined, strict: bool | None = PydanticUndefined, coerce_numbers_to_str: bool | None = PydanticUndefined, gt: annotated_types.SupportsGt | None = PydanticUndefined, ge: annotated_types.SupportsGe | None = PydanticUndefined, lt: annotated_types.SupportsLt | None = PydanticUndefined, le: annotated_types.SupportsLe | None = PydanticUndefined, multiple_of: float | None = PydanticUndefined, allow_inf_nan: bool | None = PydanticUndefined, max_digits: int | None = PydanticUndefined, decimal_places: int | None = PydanticUndefined, min_length: int | None = PydanticUndefined, max_length: int | None = PydanticUndefined, union_mode: Literal['smart', 'left_to_right'] = PydanticUndefined, fail_fast: bool | None = PydanticUndefined, **extra: Unpack[_EmptyKwargs]) Any

Usage docs: https://docs.pydantic.dev/2.10/concepts/fields

Create a field for objects that can be configured.

Used to provide extra information about a field, either for the model schema or complex validation. Some arguments apply only to number fields (int, float, Decimal) and some apply only to str.

Note:
  • Any _Unset objects will be replaced by the corresponding value defined in the _DefaultValues dictionary. If a key for the _Unset object is not found in the _DefaultValues dictionary, it will default to None

Args:

default: Default value if the field is not set. default_factory: A callable to generate the default value. The callable can either take 0 arguments

(in which case it is called as is) or a single argument containing the already validated data.

alias: The name to use for the attribute when validating or serializing by alias.

This is often used for things like converting between snake and camel case.

alias_priority: Priority of the alias. This affects whether an alias generator is used. validation_alias: Like alias, but only affects validation, not serialization. serialization_alias: Like alias, but only affects serialization, not validation. title: Human-readable title. field_title_generator: A callable that takes a field name and returns title for it. description: Human-readable description. examples: Example values for this field. exclude: Whether to exclude the field from the model serialization. discriminator: Field name or Discriminator for discriminating the type in a tagged union. deprecated: A deprecation message, an instance of warnings.deprecated or the typing_extensions.deprecated backport,

or a boolean. If True, a default deprecation message will be emitted when accessing the field.

json_schema_extra: A dict or callable to provide extra JSON schema properties. frozen: Whether the field is frozen. If true, attempts to change the value on an instance will raise an error. validate_default: If True, apply validation to the default value every time you create an instance.

Otherwise, for performance reasons, the default value of the field is trusted and not validated.

repr: A boolean indicating whether to include the field in the __repr__ output. init: Whether the field should be included in the constructor of the dataclass.

(Only applies to dataclasses.)

init_var: Whether the field should _only_ be included in the constructor of the dataclass.

(Only applies to dataclasses.)

kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass.

(Only applies to dataclasses.)

coerce_numbers_to_str: Whether to enable coercion of any Number type to str (not applicable in strict mode). strict: If True, strict validation is applied to the field.

See [Strict Mode](../concepts/strict_mode.md) for details.

gt: Greater than. If set, value must be greater than this. Only applicable to numbers. ge: Greater than or equal. If set, value must be greater than or equal to this. Only applicable to numbers. lt: Less than. If set, value must be less than this. Only applicable to numbers. le: Less than or equal. If set, value must be less than or equal to this. Only applicable to numbers. multiple_of: Value must be a multiple of this. Only applicable to numbers. min_length: Minimum length for iterables. max_length: Maximum length for iterables. pattern: Pattern for strings (a regular expression). allow_inf_nan: Allow inf, -inf, nan. Only applicable to numbers. max_digits: Maximum number of allow digits for strings. decimal_places: Maximum number of decimal places allowed for numbers. union_mode: The strategy to apply when validating a union. Can be smart (the default), or left_to_right.

See [Union Mode](../concepts/unions.md#union-modes) for details.

fail_fast: If True, validation will stop on the first error. If False, all validation errors will be collected.

This option can be applied only to iterable types (list, tuple, set, and frozenset).

extra: (Deprecated) Extra fields that will be included in the JSON schema.

!!! warning Deprecated

The extra kwargs is deprecated. Use json_schema_extra instead.

Returns:
A new [FieldInfo][pydantic.fields.FieldInfo]. The return annotation is Any so Field can be used on

type-annotated fields without causing a type error.

blacksmith.QueryStringField(default: Any = PydanticUndefined, *, default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = PydanticUndefined, alias: str | None = PydanticUndefined, alias_priority: int | None = PydanticUndefined, validation_alias: str | AliasPath | AliasChoices | None = PydanticUndefined, serialization_alias: str | None = PydanticUndefined, title: str | None = PydanticUndefined, field_title_generator: Callable[[str, FieldInfo], str] | None = PydanticUndefined, description: str | None = PydanticUndefined, examples: list[Any] | None = PydanticUndefined, exclude: bool | None = PydanticUndefined, discriminator: str | types.Discriminator | None = PydanticUndefined, deprecated: Deprecated | str | bool | None = PydanticUndefined, json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = {'location': 'querystring'}, frozen: bool | None = PydanticUndefined, validate_default: bool | None = PydanticUndefined, repr: bool = PydanticUndefined, init: bool | None = PydanticUndefined, init_var: bool | None = PydanticUndefined, kw_only: bool | None = PydanticUndefined, pattern: str | Pattern[str] | None = PydanticUndefined, strict: bool | None = PydanticUndefined, coerce_numbers_to_str: bool | None = PydanticUndefined, gt: annotated_types.SupportsGt | None = PydanticUndefined, ge: annotated_types.SupportsGe | None = PydanticUndefined, lt: annotated_types.SupportsLt | None = PydanticUndefined, le: annotated_types.SupportsLe | None = PydanticUndefined, multiple_of: float | None = PydanticUndefined, allow_inf_nan: bool | None = PydanticUndefined, max_digits: int | None = PydanticUndefined, decimal_places: int | None = PydanticUndefined, min_length: int | None = PydanticUndefined, max_length: int | None = PydanticUndefined, union_mode: Literal['smart', 'left_to_right'] = PydanticUndefined, fail_fast: bool | None = PydanticUndefined, **extra: Unpack[_EmptyKwargs]) Any

Usage docs: https://docs.pydantic.dev/2.10/concepts/fields

Create a field for objects that can be configured.

Used to provide extra information about a field, either for the model schema or complex validation. Some arguments apply only to number fields (int, float, Decimal) and some apply only to str.

Note:
  • Any _Unset objects will be replaced by the corresponding value defined in the _DefaultValues dictionary. If a key for the _Unset object is not found in the _DefaultValues dictionary, it will default to None

Args:

default: Default value if the field is not set. default_factory: A callable to generate the default value. The callable can either take 0 arguments

(in which case it is called as is) or a single argument containing the already validated data.

alias: The name to use for the attribute when validating or serializing by alias.

This is often used for things like converting between snake and camel case.

alias_priority: Priority of the alias. This affects whether an alias generator is used. validation_alias: Like alias, but only affects validation, not serialization. serialization_alias: Like alias, but only affects serialization, not validation. title: Human-readable title. field_title_generator: A callable that takes a field name and returns title for it. description: Human-readable description. examples: Example values for this field. exclude: Whether to exclude the field from the model serialization. discriminator: Field name or Discriminator for discriminating the type in a tagged union. deprecated: A deprecation message, an instance of warnings.deprecated or the typing_extensions.deprecated backport,

or a boolean. If True, a default deprecation message will be emitted when accessing the field.

json_schema_extra: A dict or callable to provide extra JSON schema properties. frozen: Whether the field is frozen. If true, attempts to change the value on an instance will raise an error. validate_default: If True, apply validation to the default value every time you create an instance.

Otherwise, for performance reasons, the default value of the field is trusted and not validated.

repr: A boolean indicating whether to include the field in the __repr__ output. init: Whether the field should be included in the constructor of the dataclass.

(Only applies to dataclasses.)

init_var: Whether the field should _only_ be included in the constructor of the dataclass.

(Only applies to dataclasses.)

kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass.

(Only applies to dataclasses.)

coerce_numbers_to_str: Whether to enable coercion of any Number type to str (not applicable in strict mode). strict: If True, strict validation is applied to the field.

See [Strict Mode](../concepts/strict_mode.md) for details.

gt: Greater than. If set, value must be greater than this. Only applicable to numbers. ge: Greater than or equal. If set, value must be greater than or equal to this. Only applicable to numbers. lt: Less than. If set, value must be less than this. Only applicable to numbers. le: Less than or equal. If set, value must be less than or equal to this. Only applicable to numbers. multiple_of: Value must be a multiple of this. Only applicable to numbers. min_length: Minimum length for iterables. max_length: Maximum length for iterables. pattern: Pattern for strings (a regular expression). allow_inf_nan: Allow inf, -inf, nan. Only applicable to numbers. max_digits: Maximum number of allow digits for strings. decimal_places: Maximum number of decimal places allowed for numbers. union_mode: The strategy to apply when validating a union. Can be smart (the default), or left_to_right.

See [Union Mode](../concepts/unions.md#union-modes) for details.

fail_fast: If True, validation will stop on the first error. If False, all validation errors will be collected.

This option can be applied only to iterable types (list, tuple, set, and frozenset).

extra: (Deprecated) Extra fields that will be included in the JSON schema.

!!! warning Deprecated

The extra kwargs is deprecated. Use json_schema_extra instead.

Returns:
A new [FieldInfo][pydantic.fields.FieldInfo]. The return annotation is Any so Field can be used on

type-annotated fields without causing a type error.

class blacksmith.ResponseBox(result: Ok[HTTPResponse] | Err[HTTPError], response_schema: type[Response] | None, method: Literal['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], path: str, name: str, client_name: str, error_parser: AbstractErrorParser[TError_co])

Wrap a HTTP response and deserialize it.

user: ResponseBox[User, HTTPError] = (
    await api.user.get({"username": username})
)
if user.is_ok():
    print(user.unwrap().username)
else:
    print(f"API Call failed: {user.unwrap_err()}")
property json: dict[str, Any] | None

Return the raw json response.

It return the raw response body without noticing if its a normal or an error response.

as_result() Ok[TResponse] | Err[TError_co]

Return the result as a result.Result.

The blacksmith.ResponseBox mimic the result.Result of the result library, but, you may want to cast the response box as a result.

as_optional() Ok[TResponse | None] | Err[TError_co]

Expose the instance as an optional result.

In case no response schema has been provided while registering the resource, then a Ok(None) is return to not raise any blacksmith.NoResponseSchemaException

is_ok() bool

Return True if the response was an http success.

is_err() bool

Return True if the response was an http error.

unwrap() TResponse

Return the parsed response.

Raises:

NoResponseSchemaException – if there are no response schema set.

unwrap_err() TError_co

Return the response error.

unwrap_or(default: TResponse) TResponse

Return the response or the default value in case of error.

Raises:

NoResponseSchemaException – if there are no response schema set.

unwrap_or_else(op: Callable[[TError_co], TResponse]) TResponse

Return the response or the callable return in case of error.

Raises:

NoResponseSchemaException – if there are no response schema set.

unwrap_or_raise(exc: type[Exception]) TResponse

Return the response or raise the exception exc.

Raises:
expect(message: str) TResponse

Return the response or raise an UnwrapError exception with the given message.

Raises:

NoResponseSchemaException – if there are no response schema set.

expect_err(message: str) TError_co

Return the error or raise an UnwrapError exception with the given message.

map(op: Callable[[TResponse], U]) Ok[U] | Err[TError_co]

Apply op on response in case of success, and return the new result.

Raises:

NoResponseSchemaException – if there are no response schema set.

map_or(default: U, op: Callable[[TResponse], U]) U

Apply and return op on response in case of success, default in case of error.

Raises:

NoResponseSchemaException – if there are no response schema set.

map_or_else(default_op: Callable[[], U], op: Callable[[TResponse], U]) U

Return the result of default_op in case of error otherwise the result of op.

Raises:

NoResponseSchemaException – if there are no response schema set.

map_err(op: Callable[[HTTPError], F]) Ok[TResponse] | Err[F]

Apply op on error in case of error, and return the new result.

Raises:

NoResponseSchemaException – if there are no response schema set.

and_then(op: Callable[[TResponse], Ok[U] | Err[HTTPError]]) Ok[U] | Err[HTTPError]

Apply the op function on the response and return it if success

Raises:

NoResponseSchemaException – if there are no response schema set.

or_else(op: Callable[[HTTPError], Ok[TResponse] | Err[F]]) Ok[TResponse] | Err[F]

Apply the op function on the error and return it if error

Raises:

NoResponseSchemaException – if there are no response schema set.

inspect(op: Callable[[TResponse], Any]) Ok[TResponse] | Err[TError_co]

Call op with the contained value if Ok and return the original result.

inspect_err(op: Callable[[TError_co], Any]) Ok[TResponse] | Err[TError_co]

Call op with the contained error if Ok and return the original result.

class blacksmith.CollectionIterator(response: HTTPResponse, response_schema: type[Response] | None, collection_parser: type[AbstractCollectionParser])

Deserialize the models in a json response list, item by item.

response: AbstractCollectionParser
property meta: Metadata

Get the response metadata such as counts in http header, links…

Those metadata are generated by the collection_parser.

class blacksmith.AbstractCollectionParser(resp: HTTPResponse)

Signature of the collection parser.

resp: HTTPResponse
abstract property meta: Metadata

Return the metatadata from the response.

Usually, metadata are in a header, but if the API wrap the list,

{
    "total_items": 0,
    "items": []
}

Then, the Metadata.total_count can be extracted from the json, instead of the header.

abstract property json: list[Any]

Return the list part of the response the response.

For instance, if an API wrap the list in a structure like

{
    "items": [
        {"objkey": "objval"}
    ]
}

then, the resp.json["items"] has to be returned.

class blacksmith.CollectionParser(resp: HTTPResponse)

Handle the rest collection metadata parser.

Deserialize how a collection is wrapped.

total_count_header: str = 'Total-Count'
property meta: Metadata

Return the metatadata from the response.

Usually, metadata are in a header, but if the API wrap the list,

{
    "total_items": 0,
    "items": []
}

Then, the Metadata.total_count can be extracted from the json, instead of the header.

property json: list[Any | None]

Return the list part of the response the response.

For instance, if an API wrap the list in a structure like

{
    "items": [
        {"objkey": "objval"}
    ]
}

then, the resp.json["items"] has to be returned.

resp: HTTPResponse
exception blacksmith.HTTPError(message: str, request: HTTPRequest, response: HTTPResponse)

Represent the http error.

property status_code: int
property json: Any | None
property is_client_error: bool
property is_server_error: bool
exception blacksmith.HTTPTimeoutError

Represent the http timeout error.

class blacksmith.AbstractErrorParser(*args, **kwargs)

A parser that parse the HTTPError class to become a pydantic model, represented by the generic TError_co here definabled in the SyncClientFactory and AsyncClientFactory.

blacksmith.default_error_parser(error: HTTPError) HTTPError
class blacksmith.HTTPTimeout(read: float = 30.0, connect: float = 15.0)

Request timeout.

read: float
connect: float
class blacksmith.AsyncClientFactory(sd: ~blacksmith.sd._async.base.AsyncAbstractServiceDiscovery, transport: ~blacksmith.service._async.base.AsyncAbstractTransport | None = None, registry: ~blacksmith.domain.registry.Registry = <blacksmith.domain.registry.Registry object>, timeout: ~blacksmith.domain.model.http.HTTPTimeout | float | tuple[float, float] = <blacksmith.domain.model.http.HTTPTimeout object>, proxies: dict[str, str] | None = None, verify_certificate: bool = False, collection_parser: type[~blacksmith.domain.model.params.AbstractCollectionParser] = <class 'blacksmith.domain.model.params.CollectionParser'>, error_parser: ~blacksmith.domain.error.AbstractErrorParser[~blacksmith.domain.error.TError_co] | None = None)

Client creator, for the given configuration.

Parameters:
  • sd – Service Discovery instance

  • transport – HTTP Client that process the call, default use blacksmith.service._async.adapters.httpx.HttpxTransport

  • timeout – configure timeout, this parameter is ignored if the transport has been passed

  • proxies – configure proxies, this parameter is ignored if the transport has been passed

  • verify_certificate – Reject request if certificate are invalid for https

  • collection_parser – use to customize the collection parser default use blacksmith.domain.model.params.CollectionParser

sd: AsyncAbstractServiceDiscovery
registry: Registry
transport: AsyncAbstractTransport
timeout: HTTPTimeout
collection_parser: type[AbstractCollectionParser]
error_parser: AbstractErrorParser[TError_co]
middlewares: list[AsyncHTTPMiddleware]
add_middleware(middleware: AsyncHTTPMiddleware) AsyncClientFactory[TError_co]

Add a middleware to the client factory and return the client for chaining.

..note:: Clients created before the call of this method will also be

altered. The middleware stack is a reference for all clients.

async initialize() None
class blacksmith.SyncClientFactory(sd: ~blacksmith.sd._sync.base.SyncAbstractServiceDiscovery, transport: ~blacksmith.service._sync.base.SyncAbstractTransport | None = None, registry: ~blacksmith.domain.registry.Registry = <blacksmith.domain.registry.Registry object>, timeout: ~blacksmith.domain.model.http.HTTPTimeout | float | tuple[float, float] = <blacksmith.domain.model.http.HTTPTimeout object>, proxies: dict[str, str] | None = None, verify_certificate: bool = False, collection_parser: type[~blacksmith.domain.model.params.AbstractCollectionParser] = <class 'blacksmith.domain.model.params.CollectionParser'>, error_parser: ~blacksmith.domain.error.AbstractErrorParser[~blacksmith.domain.error.TError_co] | None = None)

Client creator, for the given configuration.

Parameters:
  • sd – Service Discovery instance

  • transport – HTTP Client that process the call, default use blacksmith.service._async.adapters.httpx.HttpxTransport

  • timeout – configure timeout, this parameter is ignored if the transport has been passed

  • proxies – configure proxies, this parameter is ignored if the transport has been passed

  • verify_certificate – Reject request if certificate are invalid for https

  • collection_parser – use to customize the collection parser default use blacksmith.domain.model.params.CollectionParser

sd: SyncAbstractServiceDiscovery
registry: Registry
transport: SyncAbstractTransport
timeout: HTTPTimeout
collection_parser: type[AbstractCollectionParser]
error_parser: AbstractErrorParser[TError_co]
middlewares: list[SyncHTTPMiddleware]
add_middleware(middleware: SyncHTTPMiddleware) SyncClientFactory[TError_co]

Add a middleware to the client factory and return the client for chaining.

..note:: Clients created before the call of this method will also be

altered. The middleware stack is a reference for all clients.

initialize() None
class blacksmith.AsyncClient(name: str, endpoint: str, resources: Mapping[str, ApiRoutes], transport: AsyncAbstractTransport, timeout: HTTPTimeout, collection_parser: type[AbstractCollectionParser], middlewares: list[AsyncHTTPMiddleware], error_parser: AbstractErrorParser[TError_co])

Client representation for the client name.

A client will have dymanic property, based on the registered resources.

name: str
endpoint: str
resources: Mapping[str, ApiRoutes]
transport: AsyncAbstractTransport
timeout: HTTPTimeout
collection_parser: type[AbstractCollectionParser]
middlewares: list[AsyncHTTPMiddleware]
add_middleware(middleware: AsyncHTTPMiddleware) AsyncClient[TError_co]
class blacksmith.SyncClient(name: str, endpoint: str, resources: Mapping[str, ApiRoutes], transport: SyncAbstractTransport, timeout: HTTPTimeout, collection_parser: type[AbstractCollectionParser], middlewares: list[SyncHTTPMiddleware], error_parser: AbstractErrorParser[TError_co])

Client representation for the client name.

A client will have dymanic property, based on the registered resources.

name: str
endpoint: str
resources: Mapping[str, ApiRoutes]
transport: SyncAbstractTransport
timeout: HTTPTimeout
collection_parser: type[AbstractCollectionParser]
middlewares: list[SyncHTTPMiddleware]
add_middleware(middleware: SyncHTTPMiddleware) SyncClient[TError_co]
class blacksmith.AsyncRouteProxy(client_name: str, name: str, endpoint: str, routes: ApiRoutes, transport: AsyncAbstractTransport, timeout: HTTPTimeout, collection_parser: type[AbstractCollectionParser], error_parser: AbstractErrorParser[TError_co], middlewares: list[AsyncHTTPMiddleware])

Proxy from resource to its associate routes.

client_name: str
name: str
endpoint: str
routes: ApiRoutes
transport: AsyncAbstractTransport
timeout: HTTPTimeout
collection_parser: type[AbstractCollectionParser]
error_parser: AbstractErrorParser[TError_co]
middlewares: list[AsyncHTTPMiddleware]
async collection_head(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http HEAD query on the collection_path.

async collection_get(params: Request | None | dict[Any, Any] = None, timeout: HTTPTimeout | float | tuple[float, float] | None = None) Ok[CollectionIterator[TCollectionResponse]] | Err[TError_co]

Retrieve a collection of resources.

It perform an http GET query on the collection_path.

The collection is return in as an iterator, and models ares validated one by one using the TCollectionResponse schema which descrine one item of the collection.

Important

This method is the only method that behave as an iterator. You can update the way collection are deserialize for a whole client, by passing a blacksmith.AbstractCollectionParser on the blacksmith.AsyncClientFactory ( or blacksmith.SyncClientFactory for the synchronous version).

async collection_post(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http POST query on the collection_path.

async collection_put(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PUT query on the collection_path.

async collection_patch(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PATCH query on the collection_path.

async collection_delete(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http DELETE query on the collection_path.

async collection_options(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http OPTIONS query on the collection_path.

async head(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http HEAD query on the path.

async get(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http GET query on the path.

async post(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http POST query on the path.

async put(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PUT query on the path.

async patch(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PATCH query on the path.

async delete(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http DELETE query on the path.

async options(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http OPTIONS query on the path.

class blacksmith.SyncRouteProxy(client_name: str, name: str, endpoint: str, routes: ApiRoutes, transport: SyncAbstractTransport, timeout: HTTPTimeout, collection_parser: type[AbstractCollectionParser], error_parser: AbstractErrorParser[TError_co], middlewares: list[SyncHTTPMiddleware])

Proxy from resource to its associate routes.

client_name: str
name: str
endpoint: str
routes: ApiRoutes
transport: SyncAbstractTransport
timeout: HTTPTimeout
collection_parser: type[AbstractCollectionParser]
error_parser: AbstractErrorParser[TError_co]
middlewares: list[SyncHTTPMiddleware]
collection_head(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http HEAD query on the collection_path.

collection_get(params: Request | None | dict[Any, Any] = None, timeout: HTTPTimeout | float | tuple[float, float] | None = None) Ok[CollectionIterator[TCollectionResponse]] | Err[TError_co]

Retrieve a collection of resources.

It perform an http GET query on the collection_path.

The collection is return in as an iterator, and models ares validated one by one using the TCollectionResponse schema which descrine one item of the collection.

Important

This method is the only method that behave as an iterator. You can update the way collection are deserialize for a whole client, by passing a blacksmith.AbstractCollectionParser on the blacksmith.AsyncClientFactory ( or blacksmith.SyncClientFactory for the synchronous version).

collection_post(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http POST query on the collection_path.

collection_put(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PUT query on the collection_path.

collection_patch(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PATCH query on the collection_path.

collection_delete(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http DELETE query on the collection_path.

collection_options(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http OPTIONS query on the collection_path.

head(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http HEAD query on the path.

get(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http GET query on the path.

post(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http POST query on the path.

put(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PUT query on the path.

patch(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http PATCH query on the path.

delete(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http DELETE query on the path.

options(params: Request | dict[Any, Any], timeout: HTTPTimeout | float | tuple[float, float] | None = None) ResponseBox[TResponse, TError_co]

Use to perform an http OPTIONS query on the path.

class blacksmith.AsyncAbstractServiceDiscovery

Define the Service Discovery interface.

abstract async get_endpoint(service: str, version: str | None) str

Get the endpoint of a service.

class blacksmith.SyncAbstractServiceDiscovery

Define the Service Discovery interface.

abstract get_endpoint(service: str, version: str | None) str

Get the endpoint of a service.

class blacksmith.AsyncConsulDiscovery(addr: str = 'http://consul:8500/v1', service_name_fmt: str = '{service}-{version}', service_url_fmt: str = 'http://{address}:{port}/{version}', unversioned_service_name_fmt: str = '{service}', unversioned_service_url_fmt: str = 'http://{address}:{port}', consul_token: str = '', _client_factory: ~typing.Callable[[str, str], ~blacksmith.service._async.client.AsyncClientFactory[~typing.Any]] = <function blacksmith_cli>)

A discovery instance based on a Consul server.

Parameters:
  • addr – endpoint of the consul v1 http api.

  • service_name_fmt – pattern for name of versionned service.

  • service_url_fmt – pattern for url of versionned service.

  • unversioned_service_name_fmt – pattern for name of unversioned service.

  • unversioned_service_url_fmt – pattern for url of unversioned service.

  • consul_token – If set, the consul token is sent on http api call.

addr: str
consul_token: str
service_name_fmt: str
service_url_fmt: str
unversioned_service_name_fmt: str
unversioned_service_url_fmt: str
format_service_name(service: str, version: str | None) str

Build the service name to send to consul.

format_endoint(version: str | None, address: str, port: int) str

Build the rest api endpoint from consul response.

async resolve(service: str, version: str | None) Service

Get the Service from the consul registry.

If many instances host the service, the host is choosen randomly.

async get_endpoint(service: str, version: str | None) str

Get the endpoint from the consul registry

If many instances host the service, the host is choosen randomly.

class blacksmith.SyncConsulDiscovery(addr: str = 'http://consul:8500/v1', service_name_fmt: str = '{service}-{version}', service_url_fmt: str = 'http://{address}:{port}/{version}', unversioned_service_name_fmt: str = '{service}', unversioned_service_url_fmt: str = 'http://{address}:{port}', consul_token: str = '', _client_factory: ~typing.Callable[[str, str], ~blacksmith.service._sync.client.SyncClientFactory[~typing.Any]] = <function blacksmith_cli>)

A discovery instance based on a Consul server.

Parameters:
  • addr – endpoint of the consul v1 http api.

  • service_name_fmt – pattern for name of versionned service.

  • service_url_fmt – pattern for url of versionned service.

  • unversioned_service_name_fmt – pattern for name of unversioned service.

  • unversioned_service_url_fmt – pattern for url of unversioned service.

  • consul_token – If set, the consul token is sent on http api call.

addr: str
consul_token: str
service_name_fmt: str
service_url_fmt: str
unversioned_service_name_fmt: str
unversioned_service_url_fmt: str
format_service_name(service: str, version: str | None) str

Build the service name to send to consul.

format_endoint(version: str | None, address: str, port: int) str

Build the rest api endpoint from consul response.

resolve(service: str, version: str | None) Service

Get the Service from the consul registry.

If many instances host the service, the host is choosen randomly.

get_endpoint(service: str, version: str | None) str

Get the endpoint from the consul registry

If many instances host the service, the host is choosen randomly.

class blacksmith.AsyncNomadDiscovery(service_url_fmt: str = 'http://{nomad_upstream_addr}/{version}', service_env_fmt: str = 'NOMAD_UPSTREAM_ADDR_{service}_{version}', unversioned_service_url_fmt: str = 'http://{nomad_upstream_addr}', unversioned_service_env_fmt: str = 'NOMAD_UPSTREAM_ADDR_{service}')

A discovery instance based on Nomad environment variables.

async get_endpoint(service: str, version: str | None = None) str

Retrieve endpoint using the given parameters from endpoints.

class blacksmith.SyncNomadDiscovery(service_url_fmt: str = 'http://{nomad_upstream_addr}/{version}', service_env_fmt: str = 'NOMAD_UPSTREAM_ADDR_{service}_{version}', unversioned_service_url_fmt: str = 'http://{nomad_upstream_addr}', unversioned_service_env_fmt: str = 'NOMAD_UPSTREAM_ADDR_{service}')

A discovery instance based on Nomad environment variables.

get_endpoint(service: str, version: str | None = None) str

Retrieve endpoint using the given parameters from endpoints.

class blacksmith.AsyncRouterDiscovery(service_url_fmt: str = 'http://router/{service}-{version}/{version}', unversioned_service_url_fmt: str = 'http://router/{service}')

Router that implement a Server-Side Service discovery.

This implementation never raise blacksmith.domain.exceptions.UnregisteredServiceException when service are unknown, because it only passe very request to the router server that is connected to the service registry.

Note

Given pattern in parameter have to match the format of the router server.

Parameters:
  • service_url_fmt – A pattern used to create endpoint of versionned services.

  • unversioned_service_url_fmt – A pattern used to create endpoint of unversionned services.

service_url_fmt: str
unversioned_service_url_fmt: str
async get_endpoint(service: str, version: str | None) str

Create and return the endpoint using the given parameters service_url_fmt or unversioned_service_url_fmt if version is None.

class blacksmith.SyncRouterDiscovery(service_url_fmt: str = 'http://router/{service}-{version}/{version}', unversioned_service_url_fmt: str = 'http://router/{service}')

Router that implement a Server-Side Service discovery.

This implementation never raise blacksmith.domain.exceptions.UnregisteredServiceException when service are unknown, because it only passe very request to the router server that is connected to the service registry.

Note

Given pattern in parameter have to match the format of the router server.

Parameters:
  • service_url_fmt – A pattern used to create endpoint of versionned services.

  • unversioned_service_url_fmt – A pattern used to create endpoint of unversionned services.

service_url_fmt: str
unversioned_service_url_fmt: str
get_endpoint(service: str, version: str | None) str

Create and return the endpoint using the given parameters service_url_fmt or unversioned_service_url_fmt if version is None.

class blacksmith.AsyncStaticDiscovery(endpoints: Mapping[tuple[str, str | None], str])

A discovery instance based on a static dictionary.

endpoints: Mapping[tuple[str, str | None], str]
async get_endpoint(service: str, version: str | None) str

Retrieve endpoint using the given parameters from endpoints.

class blacksmith.SyncStaticDiscovery(endpoints: Mapping[tuple[str, str | None], str])

A discovery instance based on a static dictionary.

endpoints: Mapping[tuple[str, str | None], str]
get_endpoint(service: str, version: str | None) str

Retrieve endpoint using the given parameters from endpoints.

class blacksmith.AsyncMiddleware(*args, **kwargs)

Signature of the middleware for the async version.

class blacksmith.SyncMiddleware(*args, **kwargs)

Signature of the middleware for the sync version.

class blacksmith.AsyncHTTPMiddleware

Inject data in http query on every requests.

async initialize() None

Asynchronous initialization of a middleware.

For instance, used to initialize connection to storage backend.

class blacksmith.SyncHTTPMiddleware

Inject data in http query on every requests.

initialize() None

Asynchronous initialization of a middleware.

For instance, used to initialize connection to storage backend.

class blacksmith.AsyncHTTPAddHeadersMiddleware(headers: dict[str, str])

Generic middleware that inject HTTP headers.

Params:

headers to inject in HTTP requests.

headers: dict[str, str]
class blacksmith.SyncHTTPAddHeadersMiddleware(headers: dict[str, str])

Generic middleware that inject HTTP headers.

Params:

headers to inject in HTTP requests.

headers: dict[str, str]
class blacksmith.AsyncHTTPAuthorizationMiddleware(scheme: str, value: str)

Authentication Mechanism based on the header Authorization.

Parameters:
  • scheme – the scheme of the mechanism.

  • value – the value that authenticate the user using the scheme.

class blacksmith.SyncHTTPAuthorizationMiddleware(scheme: str, value: str)

Authentication Mechanism based on the header Authorization.

Parameters:
  • scheme – the scheme of the mechanism.

  • value – the value that authenticate the user using the scheme.

class blacksmith.AsyncHTTPBearerMiddleware(bearer_token: str)

Authentication Mechanism based on the header Authorization with the Bearer scheme.

Parameters:

value – value of the bearer token.

class blacksmith.SyncHTTPBearerMiddleware(bearer_token: str)

Authentication Mechanism based on the header Authorization with the Bearer scheme.

Parameters:

value – value of the bearer token.

class blacksmith.AsyncCircuitBreakerMiddleware(threshold: int = 5, ttl: float = 30, listeners: Iterable[Callable[[str, Literal['circuit_breaker_created', 'state_changed', 'failed', 'recovered'], Event], None]] | None = None, uow: AsyncAbstractUnitOfWork | None = None, metrics: PrometheusMetrics | None = None)

Prevent cascading failure.

The circuit breaker is based on purgatory, the middleware create one circuit breaker per client_name. The parameters are forwarded to all the clients. This middleware does not give the possibility to adapt a threshold or the time the circuit is opened per clients.

async initialize() None

Asynchronous initialization of a middleware.

For instance, used to initialize connection to storage backend.

class blacksmith.SyncCircuitBreakerMiddleware(threshold: int = 5, ttl: float = 30, listeners: Iterable[Callable[[str, Literal['circuit_breaker_created', 'state_changed', 'failed', 'recovered'], Event], None]] | None = None, uow: SyncAbstractUnitOfWork | None = None, metrics: PrometheusMetrics | None = None)

Prevent cascading failure.

The circuit breaker is based on purgatory, the middleware create one circuit breaker per client_name. The parameters are forwarded to all the clients. This middleware does not give the possibility to adapt a threshold or the time the circuit is opened per clients.

initialize() None

Asynchronous initialization of a middleware.

For instance, used to initialize connection to storage backend.

class blacksmith.PrometheusMetrics(buckets: list[float] | None = None, hit_cache_buckets: list[float] | None = None, registry: Any = None)
class blacksmith.AsyncPrometheusMiddleware(metrics: PrometheusMetrics | None = None)

Collect the api calls made in a prometheus registry.

It expose a blacksmith_info Gauge to get the blacksmith version, as a label, and a blacksmith_request_latency_seconds_count Counter to get the number of http requests made. The counter blacksmith_request_latency_seconds_count as client_name, method, path and status_code labels.

Note

the service_name and service version is redundant with the client_name, so they are not exposed as labels. By the way, you may have multiple client_name for 1 service name/version.

metrics: PrometheusMetrics
class blacksmith.SyncPrometheusMiddleware(metrics: PrometheusMetrics | None = None)

Collect the api calls made in a prometheus registry.

It expose a blacksmith_info Gauge to get the blacksmith version, as a label, and a blacksmith_request_latency_seconds_count Counter to get the number of http requests made. The counter blacksmith_request_latency_seconds_count as client_name, method, path and status_code labels.

Note

the service_name and service version is redundant with the client_name, so they are not exposed as labels. By the way, you may have multiple client_name for 1 service name/version.

metrics: PrometheusMetrics
class blacksmith.AbstractCachePolicy

Define the Cache Policy

abstract handle_request(req: HTTPRequest, client_name: str, path: str) bool

A function to decide if the http request is cachable.

abstract get_vary_key(client_name: str, path: str, request: HTTPRequest) str

Create a caching key for the vary part.

abstract get_response_cache_key(client_name: str, path: str, req: HTTPRequest, vary: list[str]) str

Create a caching key for the http response.

abstract get_cache_info_for_response(client_name: str, path: str, req: HTTPRequest, resp: HTTPResponse) tuple[int, str, list[str]]

Return caching info. Tuple (ttl in seconds, vary key, vary list).

class blacksmith.AbstractSerializer
abstract static loads(s: str) Any

Load a string to an object

abstract static dumps(obj: Any) str

Get a value from redis

class blacksmith.CacheControlPolicy(sep: str = '$')

Initialize the caching using Cache-Control http headers. Also consume the Vary response header to cache response per Vary response headers per request.

Parameters:

sep – Separator used in cache key MUST NOT BE USED in client name.

handle_request(req: HTTPRequest, client_name: str, path: str) bool

A function to decide if the http request is cachable.

get_vary_key(client_name: str, path: str, request: HTTPRequest) str

Create a caching key for the vary part.

get_response_cache_key(client_name: str, path: str, req: HTTPRequest, vary: list[str]) str

Create a caching key for the http response.

get_cache_info_for_response(client_name: str, path: str, req: HTTPRequest, resp: HTTPResponse) tuple[int, str, list[str]]

Return caching info. Tuple (ttl in seconds, vary key, vary list).

class blacksmith.JsonSerializer
static loads(s: str) Any

Load a string to an object

static dumps(obj: Any) str

Get a value from redis

class blacksmith.AsyncAbstractCache

Abstract Redis Client.

abstract async initialize() None

Initialize the cache

abstract async get(key: str) str | None

Get a value from redis

abstract async set(key: str, val: str, ex: timedelta) None

Get a value from redis

class blacksmith.AsyncHTTPCacheMiddleware(cache: ~blacksmith.middleware._async.http_cache.AsyncAbstractCache, metrics: ~blacksmith.domain.model.middleware.prometheus.PrometheusMetrics | None = None, policy: ~blacksmith.domain.model.middleware.http_cache.AbstractCachePolicy = <blacksmith.domain.model.middleware.http_cache.CacheControlPolicy object>, serializer: type[~blacksmith.domain.model.middleware.http_cache.AbstractSerializer] = <class 'blacksmith.domain.model.middleware.http_cache.JsonSerializer'>)

Http Cache Middleware based on Cache-Control and redis.

async initialize() None

Asynchronous initialization of a middleware.

For instance, used to initialize connection to storage backend.

async cache_response(client_name: str, path: str, req: HTTPRequest, resp: HTTPResponse) bool
async get_from_cache(client_name: str, path: str, req: HTTPRequest) HTTPResponse | None
observe_cache_hit(client_name: str, method: str, path: str, status_code: int, latency: float) None
inc_cache_miss(client_name: str, cachable_state: Literal['uncachable_request', 'uncachable_response', 'cached'], method: Literal['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], path: str, status_code: int) None
class blacksmith.SyncHTTPCacheMiddleware(cache: ~blacksmith.middleware._sync.http_cache.SyncAbstractCache, metrics: ~blacksmith.domain.model.middleware.prometheus.PrometheusMetrics | None = None, policy: ~blacksmith.domain.model.middleware.http_cache.AbstractCachePolicy = <blacksmith.domain.model.middleware.http_cache.CacheControlPolicy object>, serializer: type[~blacksmith.domain.model.middleware.http_cache.AbstractSerializer] = <class 'blacksmith.domain.model.middleware.http_cache.JsonSerializer'>)

Http Cache Middleware based on Cache-Control and redis.

initialize() None

Asynchronous initialization of a middleware.

For instance, used to initialize connection to storage backend.

cache_response(client_name: str, path: str, req: HTTPRequest, resp: HTTPResponse) bool
get_from_cache(client_name: str, path: str, req: HTTPRequest) HTTPResponse | None
observe_cache_hit(client_name: str, method: str, path: str, status_code: int, latency: float) None
inc_cache_miss(client_name: str, cachable_state: Literal['uncachable_request', 'uncachable_response', 'cached'], method: Literal['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], path: str, status_code: int) None
class blacksmith.AbstractTraceContext(name: str, kind: str = 'SERVER')

Interface of the trace context for the middleware.

See examples with starlette-zipking for an implementation.

abstract classmethod make_headers() dict[str, str]

Build headers for the sub requests.

abstract tag(key: str, value: str) AbstractTraceContext

Tag the span

abstract annotate(value: str | None, ts: float | None = None) AbstractTraceContext

Annotate the span

class blacksmith.AsyncZipkinMiddleware(trace: type[AbstractTraceContext])

Zipkin Middleware based on an abstract context manager.

Parameters:

trace – A deferred context manager that manage the trace span stack.

class blacksmith.AsyncAbstractTransport(verify_certificate: bool = True, proxies: dict[str, str] | None = None)
verify_certificate: bool
proxies: dict[str, str] | None
class blacksmith.SyncAbstractTransport(verify_certificate: bool = True, proxies: dict[str, str] | None = None)
verify_certificate: bool
proxies: dict[str, str] | None
class blacksmith.HTTPRequest(method: ~typing.Literal['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], url_pattern: str, path: dict[str, str | int | float | bool] = <factory>, querystring: dict[str, str | int | float | bool | list[str | int | float | bool]] = <factory>, headers: dict[str, str] = <factory>, body: str | bytes | ~collections.abc.Iterable[bytes] | ~collections.abc.AsyncIterable[bytes] = '')

Internal representation of an http request.

Note that the HTTP method is not present, because the method is the funcion called.

The HTTP Request is filled out using the blacksmith.domain.model.params.Request schema.

method: Literal['HEAD', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']
url_pattern: str
path: dict[str, str | int | float | bool]
querystring: dict[str, str | int | float | bool | list[str | int | float | bool]]
headers: dict[str, str]
body: str | bytes | Iterable[bytes] | AsyncIterable[bytes] = ''
property url: str
class blacksmith.HTTPResponse(status_code: int, headers: Mapping[str, str], json: Any | None)

Intermediate representation of an http response.

In this representation, the response body has been parsed to the property json, which is a python structure containing simple python types. This http response representation will be used create pydantic response object.

status_code: int

HTTP Status code.

headers: Mapping[str, str]

Header of the response.

json: Any | None

Json Body of the response.

class blacksmith.AbstractHttpBodySerializer

Request body serializer.

abstract accept(content_type: str) bool

Return true in case it can handle the request.

abstract serialize(body: dict[str, Any] | Sequence[Any]) str | bytes | Iterable[bytes] | AsyncIterable[bytes]

Serialize a python simple types to a python request body.

The body received here is the extracted object from the request model.

abstract deserialize(body: bytes, encoding: str | None) Any | None

Deserialize a raw http response body to a python simple types representation.

blacksmith.register_http_body_serializer(serializer: AbstractHttpBodySerializer) None

Register a serializer to serialize some kind of request.

blacksmith.unregister_http_body_serializer(serializer: AbstractHttpBodySerializer) None

Unregister a serializer previously added.

Usefull for testing purpose.