in isshub.domain.utils View Git history
entity¶
“entity” module
Package to handle isshub entities validation.
It is an adapter over the attrs external dependency.
-
instance_of_self()[source]¶ Return a validator checking that the field holds an instance of its own entity.
- Returns
The instantiated validator
- Return type
_InstanceOfSelfValidator
-
optional_field(field_type, relation_verbose_name=None)[source]¶ Define an optional field of the specified field_type.
- Parameters
field_type (Union[type, str]) – The expected type of the field. Use the string “self” to reference the current field’s entity
relation_verbose_name (Optional[str]) – A verbose name to describe the relation between the entity linked to the field, and the entity pointed by field_type
- Returns
An
attrsattribute, with a default value set toNone, and a validator checking that this field is optional and, if set, of the correct type.- Return type
Any
- Raises
AssertionError – If field_type is a string and this string is not “self”
Examples
>>> from isshub.domain.utils.entity import optional_field, validated, BaseEntity >>> >>> @validated() ... class MyEntity(BaseEntity): ... my_field: str = optional_field(str) >>> >>> from isshub.domain.utils.testing.validation import check_field_nullable >>> check_field_nullable(MyEntity, 'my_field', my_field='foo')
-
required_field(field_type, frozen=False, relation_verbose_name=None)[source]¶ Define a required field of the specified field_type.
- Parameters
field_type (Union[type, str]) – The expected type of the field. Use the string “self” to reference the current field’s entity
frozen (bool) – If set to
False(the default), the field can be updated after being set at init time. If set toTrue, the field can be set at init time but cannot be changed later, else aFrozenAttributeErrorexception will be raised.relation_verbose_name (Optional[str]) – A verbose name to describe the relation between the entity linked to the field, and the entity pointed by field_type
- Returns
An
attrsattribute, and a validator checking that this field is of the correct type.- Return type
Any
- Raises
AssertionError – If field_type is a string and this string is not “self”
Examples
>>> from isshub.domain.utils.entity import required_field, validated, BaseEntity >>> >>> @validated() ... class MyEntity(BaseEntity): ... my_field: str = required_field(str) >>> >>> from isshub.domain.utils.testing.validation import check_field_not_nullable >>> check_field_not_nullable(MyEntity, 'my_field', my_field='foo')
-
validated()[source]¶ Decorate an entity to handle validation.
This will let
attrsmanage the class, using slots for fields, and forcing attributes to be passed as named arguments (this allows to not have to defined all required fields first, then optional ones, and resolves problems with inheritance where we can’t handle the order)- Returns
The decorated class.
- Return type
type
Examples
>>> from isshub.domain.utils.entity import required_field, validated, BaseEntity >>> >>> @validated() ... class MyEntity(BaseEntity): ... my_field: str = required_field(str) >>> >>> MyEntity.__slots__ ('my_field',) >>> >>> instance = MyEntity() Traceback (most recent call last): ... TypeError: __init__() missing 1 required keyword-only argument: 'my_field' >>> instance = MyEntity(my_field='foo') >>> instance.my_field 'foo' >>> instance.validate() >>> instance.my_field = None >>> instance.validate() Traceback (most recent call last): ... TypeError: ("'my_field' must be <class 'str'> (got None that is a <class 'NoneType'>)...
-
class
field_validator(field)[source]¶ Bases:
objectDecorate an entity method to make it a validator of the given field.
Notes
It’s easier to implement as a function but we couldn’t make mypy work with it. Thanks to https://github.com/python/mypy/issues/1551#issuecomment-253978622
- Parameters
field (Any) – The field to validate.
Examples
>>> from isshub.domain.utils.entity import field_validator, required_field, BaseEntity >>> >>> @validated() ... class MyEntity(BaseEntity): ... my_field: str = required_field(str) ... ... @field_validator(my_field) ... def validate_my_field(self, field, value): ... if value != 'foo': ... raise ValueError(f'{self.__class__.__name__}.my_field must be "foo"') >>> >>> instance = MyEntity(my_field='bar') Traceback (most recent call last): ... ValueError: MyEntity.my_field must be "foo" >>> instance = MyEntity(my_field='foo') >>> instance.my_field 'foo' >>> instance.my_field = 'bar' >>> instance.validate() Traceback (most recent call last): ... ValueError: MyEntity.my_field must be "foo" >>> instance.my_field = 'foo' >>> instance.validate() >>> instance.my_field 'foo'
-
validate_instance(instance)[source]¶ Validate a whole instance.
- Parameters
instance (Any) – The instance to validate.
- Raises
TypeError, ValueError – If a field in the instance is not valid.
Examples
>>> from isshub.domain.utils.entity import required_field, validate_instance, BaseEntity >>> >>> @validated() ... class MyEntity(BaseEntity): ... my_field: str = required_field(str) >>> >>> instance = MyEntity(my_field='foo') >>> validate_instance(instance) >>> instance.my_field = None >>> validate_instance(instance) Traceback (most recent call last): ... TypeError: ("'my_field' must be <class 'str'> (got None that is a <class 'NoneType'>)...
- Return type
Any
-
validate_positive_integer(value, none_allowed, display_name)[source]¶ Validate that the given value is a positive integer (
Noneaccepted if none_allowed).- Parameters
value (Any) – The value to validate as a positive integer.
none_allowed (bool) – If
True, the value can beNone. IfFalse, the value must be a positive integer.display_name (str) – The name of the field to display in errors.
- Raises
TypeError – If value is not of type
int.ValueError – If value is not a positive integer (ie > 0), or
Noneif none_allowed isTrue.
Examples
>>> from isshub.domain.utils.entity import field_validator, required_field, BaseEntity >>> >>> @validated() ... class MyEntity(BaseEntity): ... my_field: int = required_field(int) ... ... @field_validator(my_field) ... def validate_my_field(self, field, value): ... validate_positive_integer( ... value=value, ... none_allowed=False, ... display_name=f"{self.__class__.__name__}.my_field", ... ) >>> >>> instance = MyEntity(my_field='foo') Traceback (most recent call last): ... TypeError: ("'my_field' must be <class 'int'> (got 'foo' that is a <class 'str'>)... >>> instance = MyEntity(my_field=-2) Traceback (most recent call last): ... ValueError: MyEntity.my_field must be a positive integer >>> instance = MyEntity(my_field=0) Traceback (most recent call last): ... ValueError: MyEntity.my_field must be a positive integer >>> instance = MyEntity(my_field=1.1) Traceback (most recent call last): ... TypeError: ("'my_field' must be <class 'int'> (got 1.1 that is a <class 'float'>)... >>> instance = MyEntity(my_field=1) >>> instance.my_field = -2 >>> instance.validate() Traceback (most recent call last): ... ValueError: MyEntity.my_field must be a positive integer
- Return type
None
-
validate_uuid(value, none_allowed, display_name)[source]¶ Validate that the given value is a uuid (version 4) (
Noneaccepted if none_allowed).- Parameters
value (Any) – The value to validate as a uuid.
none_allowed (bool) – If
True, the value can beNone. IfFalse, the value must be a uuid.display_name (str) – The name of the field to display in errors.
- Raises
TypeError – If value is not of type
UUIDversion 4 .
Examples
>>> from uuid import UUID >>> from isshub.domain.utils.entity import field_validator, required_field, BaseEntity >>> >>> @validated() ... class MyEntity(BaseEntity): ... my_field: UUID = required_field(UUID) ... ... @field_validator(my_field) ... def validate_my_field(self, field, value): ... validate_uuid( ... value=value, ... none_allowed=False, ... display_name=f"{self.__class__.__name__}.my_field", ... ) >>> >>> instance = MyEntity(my_field='foo') Traceback (most recent call last): ... TypeError: ("'my_field' must be <class 'uuid.UUID'> (got 'foo' that is a <class 'str'>)... >>> instance = MyEntity(my_field='7298d61a-f08f-4f83-b75e-934e786eb43d') Traceback (most recent call last): ... TypeError: ("'my_field' must be <class 'uuid.UUID'> (got '7298d61a-f08f-4f83-b75e-934e786eb43d' that is a <class 'str'>)... >>> instance = MyEntity(my_field=UUID('19f49bc8-06e5-11eb-8465-bf44725d7bd3')) Traceback (most recent call last): ... TypeError: MyEntity.my_field must be a UUID version 4 >>> instance = MyEntity(my_field=UUID('7298d61a-f08f-4f83-b75e-934e786eb43d')) >>> instance.my_field = UUID('19f49bc8-06e5-11eb-8465-bf44725d7bd3') >>> instance.validate() Traceback (most recent call last): ... TypeError: MyEntity.my_field must be a UUID version 4
- Return type
None
-
class
BaseEntity[source]¶ Bases:
objectA base entity without any field, that is able to validate itself.
-
class
BaseEntityWithIdentifier(*, identifier)[source]¶ Bases:
isshub.domain.utils.entity.BaseEntityA base entity with an
identifier, that is able to validate itself.- Variables
identifier (UUID) – The identifier of the instance. Validated to be a UUID version 4.
-
identifier: uuid.UUID¶
-
validate_id_is_uuid(field, value)[source]¶ Validate that the
BaseEntityWithIdentifier.identifierfield is a uuid.- Parameters
field (Any) – The field to validate.
value (Any) – The value to validate for the field.
- Return type
None