Skip to content

Commit

Permalink
Add support for bytes #61
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxim Avanov committed May 8, 2020
1 parent a73b73b commit 968a88a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
27 changes: 27 additions & 0 deletions tests/std_types/test_bytes.py
@@ -0,0 +1,27 @@
from typing import NamedTuple

import pytest

from typeit import TypeConstructor, flags, Error


def test_bytes():
class X(NamedTuple):
x: bytes

non_strict_mk_x, non_strict_dict_x = TypeConstructor & flags.NonStrictPrimitives ^ X
strict_mk_x, strict_dict_x = TypeConstructor ^ X

data = {'x': 'abc'}
x = non_strict_mk_x(data)
assert x.x == b'abc'

with pytest.raises(Error):
strict_mk_x(data)

data_strict = {'x': b'abc'}
x_non_strict = non_strict_mk_x(data_strict)
x_strict = strict_mk_x(data_strict)
assert x_non_strict == x_strict

assert non_strict_dict_x(x_strict) == strict_dict_x(x_non_strict) == {'x': b'abc'}
35 changes: 35 additions & 0 deletions typeit/schema/primitives.py
Expand Up @@ -98,6 +98,39 @@ def serialize(self, node, appstruct):
return super().serialize(node, appstruct)


class Bytes(col.SchemaType, metaclass=SubscriptableSchemaTypeM):
def __init__(
self,
supported_conversions: t.Iterable[t.Type[t.Any]] = (int, bool, str, bytes)
):
super().__init__()
self.supported_conversions = tuple(supported_conversions)

def serialize(self, node, appstruct):
""" Default colander str serializer serializes None as 'None',
whereas we want identical representation of the original data,
with strict primitive type semantics
"""
if appstruct in (Null, 'None'):
return None

if not isinstance(appstruct, self.supported_conversions):
raise Invalid(
node,
f'Cannot convert a source value of type {type(appstruct)} to bytes: '
f'supported source types are {self.supported_conversions}.',
appstruct
)
if isinstance(appstruct, str):
rv = bytes(appstruct, encoding='utf-8')
else:
rv = bytes(appstruct)
return rv

# it seems that for bytes serialisation checks are the same as for deserialisation
deserialize = serialize


class NonStrictStr(col.Str, metaclass=SubscriptableSchemaTypeM):

def serialize(self, node, appstruct):
Expand Down Expand Up @@ -168,6 +201,7 @@ def serialize(self, node, appstruct):
# to colander SchemaNodes responsible for serialization/deserialization
BUILTIN_TO_SCHEMA_TYPE: t.Mapping[t.Type, PrimitiveSchemaTypeT] = {
t.Any: AcceptEverything(),
bytes: Bytes(supported_conversions=(bytes,)),
str: Str(allow_empty=True),
int: Int(),
float: Float(),
Expand All @@ -177,6 +211,7 @@ def serialize(self, node, appstruct):

NON_STRICT_BUILTIN_TO_SCHEMA_TYPE: t.Mapping[t.Type, NonStrictPrimitiveSchemaTypeT] = {
t.Any: AcceptEverything(),
bytes: Bytes(),
str: NonStrictStr(allow_empty=True),
int: NonStrictInt(),
float: NonStrictFloat(),
Expand Down

0 comments on commit 968a88a

Please sign in to comment.