Skip to content
This repository was archived by the owner on Jan 7, 2021. It is now read-only.

Commit b2b5892

Browse files
committed
Alrighty. I went ahead and made a custom dictionary class just for Document data attributes. So rather than transforming integers and other bits into strings when they are pushed to the API I am going to restrict them from being set. For #106.
1 parent 0bb8ee9 commit b2b5892

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

documentcloud/__init__.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,6 @@ def put(self, method, params):
116116
data = params.get("data")
117117
del params['data']
118118
params = urllib.parse.urlencode(params, doseq=True)
119-
# Convert all numeric keys and values into strings
120-
string_data = {}
121-
for key, value in data.items():
122-
if not isinstance(key, six.string_types):
123-
key = str(key)
124-
if not isinstance(value, six.string_types):
125-
value = str(value)
126-
string_data[key] = value
127119
# Format them in the style documentcloud expects
128120
# ?data['foo']=bar&data['tit']=tat
129121
params += "".join([
@@ -605,6 +597,38 @@ def get_location(self):
605597
location = property(get_location)
606598

607599

600+
class DocumentDataDict(dict):
601+
"""
602+
The key/value store DocumentCloud allows with each Document.
603+
604+
Functions the same as a standard Python dictionary, with two exception:
605+
key names protected by DocumentCloud are restricted and only strings
606+
are allowed.
607+
608+
If you try to set an integer or other type as a key or value it will
609+
throw a TypeError.
610+
"""
611+
def __init__(self, *args, **kwargs):
612+
for d in args:
613+
for key, value in d.items():
614+
self.validate_key(key)
615+
self.validate_value(value)
616+
dict.__init__(self, *args, **kwargs)
617+
618+
def __setitem__(self, key, value):
619+
self.validate_key(key)
620+
self.validate_value(value)
621+
dict.__setitem__(self, key, value)
622+
623+
def validate_key(self, key):
624+
is_valid_data_keyword(key)
625+
if not isinstance(key, six.string_types):
626+
raise TypeError("data attribute keys must be strings")
627+
628+
def validate_value(self, value):
629+
if not isinstance(value, six.string_types):
630+
raise TypeError("data attribute values must be strings")
631+
608632
class Document(BaseAPIObject):
609633
"""
610634
A document returned by the API.
@@ -709,27 +733,18 @@ def set_data(self, data):
709733
# Make sure a dict got passed it
710734
if not isinstance(data, type({})):
711735
raise TypeError("This attribute must be a dictionary.")
712-
# Validate keywords
713-
for keyword in list(data.keys()):
714-
is_valid_data_keyword(keyword)
715-
# Validate keys and values to verify they are all strings
716-
for key, value in data.items():
717-
if not isinstance(key, six.string_types):
718-
raise TypeError("data attribute keys must be strings")
719-
if not isinstance(value, six.string_types):
720-
raise TypeError("data attribute values must be strings")
721736
# Set the attribute
722-
self.__dict__['data'] = data
737+
self.__dict__['data'] = DocumentDataDict(data)
723738

724739
def get_data(self):
725740
"""
726741
Fetch the data field if it does not exist.
727742
"""
728743
try:
729-
return self.__dict__['data']
744+
return DocumentDataDict(self.__dict__['data'])
730745
except KeyError:
731746
self._lazy_load()
732-
return self.__dict__['data']
747+
return DocumentDataDict(self.__dict__['data'])
733748
data = property(get_data, set_data)
734749

735750
def get_annotations(self):

0 commit comments

Comments
 (0)