@@ -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+
608632class 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