Skip to content

Commit

Permalink
refactor: remove encoding from String and Text properties
Browse files Browse the repository at this point in the history
side-effect: Text also isn't compressable anymore.
  • Loading branch information
JorinTielen committed Nov 8, 2018
1 parent 0722597 commit b55ebc7
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 89 deletions.
51 changes: 3 additions & 48 deletions anom/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,42 +72,6 @@ def prepare_to_store(self, entity, value):
return super().prepare_to_store(entity, value)


class Encodable:
"""Mixin for string properties that have an encoding.
Parameters:
encoding(str): The encoding to use when persisting this Property
to Datastore. Defaults to ``utf-8``.
"""

def __init__(self, *, encoding="utf-8", **options):
super().__init__(**options)

self.encoding = encoding

def prepare_to_load(self, entity, value):
value = super().prepare_to_load(entity, value)

# BUG(gcloud): Projections seem to cause bytes to be
# loaded as strings so this instance check is required.
if value is not None and isinstance(value, (list, bytes)):
if self.repeated:
value = [v.decode(self.encoding) for v in value]
else:
value = value.decode(self.encoding)

return value

def prepare_to_store(self, entity, value):
if value is not None:
if self.repeated:
value = [v.encode(self.encoding) for v in value]
else:
value = value.encode(self.encoding)

return super().prepare_to_store(entity, value)


class Serializer(Compressable, Property):
"""Base class for properties that serialize data.
"""
Expand Down Expand Up @@ -564,7 +528,7 @@ def _loads(cls, data):
return msgpack.unpackb(data, ext_hook=cls._deserialize, encoding="utf-8")


class String(Encodable, Property):
class String(Property):
"""A Property for indexable string values.
Parameters:
Expand All @@ -582,15 +546,12 @@ class String(Encodable, Property):
repeated(bool, optional): Whether or not this property is
repeated. Defaults to ``False``. Optional repeated
properties default to an empty list.
encoding(str): The encoding to use when persisting this Property
to Datastore. Defaults to ``utf-8``.
"""

_types = (str,)

def _validate_length(self, value):
if len(value) > _max_indexed_length and \
len(value.encode(self.encoding)) > _max_indexed_length:
if len(value) > _max_indexed_length:
raise ValueError(
f"String value is longer than the maximum allowed length "
f"({_max_indexed_length}) for indexed properties. Set "
Expand All @@ -611,7 +572,7 @@ def validate(self, value):
return value


class Text(Encodable, Compressable, Property):
class Text(Property):
"""A Property for long string values that are never indexed.
Parameters:
Expand All @@ -624,12 +585,6 @@ class Text(Encodable, Compressable, Property):
repeated(bool, optional): Whether or not this property is
repeated. Defaults to ``False``. Optional repeated
properties default to an empty list.
compressed(bool, optional): Whether or not this property should
be compressed before being persisted.
compression_level(int, optional): The amount of compression to
apply when compressing values.
encoding(str): The encoding to use when persisting this Property
to Datastore. Defaults to ``utf-8``.
"""

_types = (str,)
Expand Down
42 changes: 1 addition & 41 deletions tests/test_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
inspect.isclass(x) and issubclass(x, Property) and
x not in {props.Computed, props.Embed}
))
blob_properties = (props.Bytes, props.Json, props.Text)
encodable_properties = (props.String, props.Text)
blob_properties = (props.Bytes, props.Json)


def test_blobs_cannot_be_indexed():
Expand All @@ -23,45 +22,6 @@ def test_blobs_cannot_be_indexed():
property_class(indexed=True)


def test_compressables_can_be_compressed():
string = "a" * 1000
text = props.Text(compressed=True, compression_level=9)
compressed_bytes = text.prepare_to_store(None, string)
assert len(compressed_bytes) == 17

uncompressed_string = text.prepare_to_load(None, compressed_bytes)
assert uncompressed_string == string


def test_compressables_compression_level_needs_to_be_in_a_specific_range():
with pytest.raises(ValueError):
props.Text(compressed=True, compression_level=20)


def test_encodables_respect_their_encodings():
string = "こんにちは"
encoded_string = string.encode("utf-8")
for property_class in encodable_properties:
prop = property_class()
assert prop.prepare_to_store(None, string) == encoded_string
assert prop.prepare_to_load(None, encoded_string) == string


def test_encodables_avoid_loading_nones():
for property_class in encodable_properties:
prop = property_class()
assert prop.prepare_to_load(None, None) is None


def test_encodables_respect_repeated_option():
string_list = ["a", "b"]
bytes_list = [b"a", b"b"]
for property_class in encodable_properties:
prop = property_class(repeated=True)
assert prop.prepare_to_store(None, string_list) == bytes_list
assert prop.prepare_to_load(None, bytes_list) == string_list


def test_keys_can_be_assigned_full_keys():
assert props.Key().validate(Key("Person", 12))

Expand Down

0 comments on commit b55ebc7

Please sign in to comment.