<s> from collections import defaultdict <EOL> from inspect import classify_class_attrs <EOL> from django . core . exceptions import ValidationError <EOL> from django . db . models . fields import NOT_PROVIDED <EOL> from django . utils . six import with_metaclass <EOL> from . fields import field <EOL> from . utils import DictObject <EOL> class MetaMapper ( type ) : <EOL> def __new__ ( mcs , name , bases , attrs ) : <EOL> new_class = super ( MetaMapper , mcs ) . __new__ ( mcs , name , bases , attrs ) <EOL> fields = { <EOL> name : prop <EOL> for name , kind , cls , prop in classify_class_attrs ( new_class ) <EOL> if isinstance ( prop , field ) <EOL> } <EOL> new_class . _fields = fields <EOL> new_class . _field_names = tuple ( fields . keys ( ) ) <EOL> return new_class <EOL> class DataMapper ( with_metaclass ( MetaMapper ) ) : <EOL> def __init__ ( self , obj = None , ** kwargs ) : <EOL> if obj is None : <EOL> obj = DictObject ( ) <EOL> self . _obj = obj <EOL> self . _context = kwargs <EOL> def __lshift__ ( self , other ) : <EOL> '''<STR_LIT>''' <EOL> self . _obj = other <EOL> return self . _reduce ( ) <EOL> def __rlshift__ ( self , other ) : <EOL> '''<STR_LIT>''' <EOL> return self . _patch ( other ) <EOL> def _reduce ( self ) : <EOL> '''<STR_LIT>''' <EOL> return { <EOL> name : getattr ( self , name ) <EOL> for name in self . _field_names <EOL> } <EOL> def _clean ( self , data , full = True ) : <EOL> '''<STR_LIT>''' <EOL> return <EOL> def _patch ( self , data ) : <EOL> '''<STR_LIT>''' <EOL> errors = defaultdict ( list ) <EOL> for name in self . _field_names : <EOL> try : <EOL> value = data [ name ] <EOL> except KeyError : <EOL> continue <EOL> try : <EOL> setattr ( self , name , value ) <EOL> except ValidationError as e : <EOL> errors [ name ] . append ( e ) <EOL> self . _errors = dict ( errors ) <EOL> self . _clean ( data , full = False ) <EOL> if self . _errors : <EOL> raise ValidationError ( self . _errors ) <EOL> return self . _obj <EOL> def _apply ( self , data ) : <EOL> '''<STR_LIT>''' <EOL> errors = defaultdict ( list ) <EOL> for name in self . _field_names : <EOL> required = getattr ( self . _fields [ name ] , '<STR_LIT>' , True ) <EOL> default = getattr ( self . _fields [ name ] , '<STR_LIT:default>' , NOT_PROVIDED ) <EOL> try : <EOL> value = data [ name ] <EOL> except KeyError : <EOL> if required : <EOL> if default is NOT_PROVIDED : <EOL> errors [ name ] . append ( <EOL> ValidationError ( '<STR_LIT>' ) <EOL> ) <EOL> continue <EOL> elif default is NOT_PROVIDED : <EOL> continue <EOL> value = default <EOL> if callable ( value ) : <EOL> value = value ( ) <EOL> try : <EOL> setattr ( self , name , value ) <EOL> except ValidationError as e : <EOL> errors [ name ] . append ( e ) <EOL> self . _errors = dict ( errors ) <EOL> self . _clean ( data , full = True ) <EOL> if self . _errors : <EOL> raise ValidationError ( self . _errors ) <EOL> return self . _obj </s>
