<s> """<STR_LIT>""" <EOL> from __future__ import absolute_import <EOL> from abc import ABCMeta , abstractmethod <EOL> from itertools import izip <EOL> try : <EOL> from collections import OrderedDict <EOL> except ImportError : <EOL> from ordereddict import OrderedDict <EOL> import warnings <EOL> import types <EOL> try : <EOL> import simplejson as json <EOL> except ImportError : <EOL> import json <EOL> SCHEMA_FIELD_NAME = "<STR_LIT>" <EOL> class ParseError ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class InvalidSchemaSpecification ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , exception_msg ) : <EOL> self . exception_msg = exception_msg <EOL> def __getattr__ ( self , item ) : <EOL> raise ValueError ( self . exception_msg ) <EOL> class SchemaStore ( object ) : <EOL> def __init__ ( self ) : <EOL> self . _schema_map = { } <EOL> self . _enum_map = { } <EOL> def __str__ ( self ) : <EOL> return str ( self . _schema_map . keys ( ) ) <EOL> def add_record ( self , schema , _bump_stack_level = False ) : <EOL> """<STR_LIT>""" <EOL> full_name = get_full_name ( schema ) <EOL> has_namespace = '<STR_LIT:.>' in full_name <EOL> self . _force_add ( full_name , schema , _bump_stack_level , _raise_on_existing = has_namespace ) <EOL> if has_namespace and schema . __name__ not in self . _schema_map : <EOL> self . _force_add ( schema . __name__ , schema , _bump_stack_level ) <EOL> return schema <EOL> def add_enum ( self , enum_definition ) : <EOL> new_values_set = set ( enum_definition . values ) <EOL> old_values_set = self . _enum_map . get ( enum_definition . name ) <EOL> if old_values_set is not None and new_values_set != old_values_set : <EOL> warnings . warn ( <EOL> "<STR_LIT>" . format ( <EOL> enum_definition . name , <EOL> old_values_set , <EOL> new_values_set <EOL> ) <EOL> ) <EOL> if enum_definition . name is not None : <EOL> self . _enum_map [ enum_definition . name ] = enum_definition . values <EOL> return enum_definition <EOL> def _force_add ( self , used_name , schema , _bump_stack_level = False , _raise_on_existing = False ) : <EOL> existing = self . _schema_map . get ( used_name , None ) <EOL> if existing and existing != schema : <EOL> full_name = get_full_name ( schema ) <EOL> explanation = "<STR_LIT>" . format ( ) if full_name != used_name else "<STR_LIT>" <EOL> warnings . warn ( <EOL> "<STR_LIT>" <EOL> . format ( used_name = used_name , <EOL> explanation = explanation , <EOL> prev_module = existing . __module__ , <EOL> new_module = schema . __module__ ) , <EOL> stacklevel = <NUM_LIT:4> if _bump_stack_level else <NUM_LIT:3> ) <EOL> if _raise_on_existing : <EOL> if not isinstance ( existing , InvalidSchemaSpecification ) : <EOL> schema = InvalidSchemaSpecification ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> . format ( used_name = used_name , existing = existing , new = schema ) ) <EOL> else : <EOL> schema = existing <EOL> self . _schema_map [ used_name ] = schema <EOL> def get ( self , record_name ) : <EOL> """<STR_LIT>""" <EOL> if record_name in self . _schema_map : <EOL> return self . _schema_map [ record_name ] <EOL> else : <EOL> last_name = record_name . split ( '<STR_LIT:.>' ) [ - <NUM_LIT:1> ] <EOL> return self . _schema_map [ last_name ] <EOL> def get_enum ( self , name ) : <EOL> return self . _enum_map [ name ] <EOL> def clear ( self ) : <EOL> self . _schema_map . clear ( ) <EOL> self . _enum_map . clear ( ) <EOL> def clone ( self ) : <EOL> r = SchemaStore ( ) <EOL> r . _schema_map = self . _schema_map . copy ( ) <EOL> r . _enum_map = self . _enum_map . copy ( ) <EOL> return r <EOL> def has_schema ( self , name ) : <EOL> if name in self . _schema_map : <EOL> return True <EOL> if "<STR_LIT:.>" in name : <EOL> basename = name . split ( "<STR_LIT:.>" ) [ - <NUM_LIT:1> ] <EOL> return basename in self . _schema_map <EOL> return False <EOL> def has_enum ( self , name ) : <EOL> return name in self . _enum_map <EOL> def __contains__ ( self , schema ) : <EOL> return schema in self . _schema_map . values ( ) <EOL> class RecordStore ( SchemaStore ) : <EOL> def __init__ ( self ) : <EOL> warnings . warn ( "<STR_LIT>" , DeprecationWarning , stacklevel = <NUM_LIT:2> ) <EOL> super ( RecordStore , self ) . __init__ ( ) <EOL> def get_full_name ( schema ) : <EOL> full_name = schema . __name__ <EOL> if hasattr ( schema , '<STR_LIT>' ) : <EOL> full_name = '<STR_LIT:.>' . join ( [ schema . _namespace , schema . __name__ ] ) <EOL> elif hasattr ( schema , '<STR_LIT>' ) : <EOL> warnings . warn ( "<STR_LIT>" , DeprecationWarning , stacklevel = <NUM_LIT:3> ) <EOL> full_name = '<STR_LIT:.>' . join ( [ schema . _avro_namespace_ , schema . __name__ ] ) <EOL> return full_name <EOL> class _NoDefault : <EOL> def __repr__ ( self ) : <EOL> return "<STR_LIT>" <EOL> NO_DEFAULT = _NoDefault ( ) <EOL> _UNTOUCHED = object ( ) <EOL> class Field ( object ) : <EOL> __metaclass__ = ABCMeta <EOL> _next_index = <NUM_LIT:0> <EOL> def __init__ ( self , description = None , nullable = True , default = _UNTOUCHED ) : <EOL> self . description = description <EOL> self . _index = Field . _next_index <EOL> self . nullable = nullable <EOL> if default is _UNTOUCHED : <EOL> if nullable : <EOL> default = None <EOL> else : <EOL> default = NO_DEFAULT <EOL> self . default = default <EOL> Field . _next_index += <NUM_LIT:1> <EOL> def repr_vars ( self ) : <EOL> """<STR_LIT>""" <EOL> d = OrderedDict ( ) <EOL> d [ "<STR_LIT>" ] = repr ( self . nullable ) <EOL> d [ "<STR_LIT:default>" ] = repr ( self . default ) <EOL> if self . description is not None : <EOL> d [ "<STR_LIT:description>" ] = repr ( self . description ) <EOL> return d <EOL> def __repr__ ( self ) : <EOL> strings = ( '<STR_LIT>' . format ( vname , val ) for vname , val in self . repr_vars ( ) . iteritems ( ) ) <EOL> return self . __class__ . __name__ + '<STR_LIT:(>' + '<STR_LIT:U+002CU+0020>' . join ( strings ) + '<STR_LIT:)>' <EOL> def set_parent ( self , schema ) : <EOL> pass <EOL> @ abstractmethod <EOL> def dump ( self , obj ) : <EOL> pass <EOL> @ abstractmethod <EOL> def load ( self , obj ) : <EOL> pass <EOL> @ classmethod <EOL> def mixin ( cls , mixin_cls ) : <EOL> """<STR_LIT>""" <EOL> for item_name in dir ( mixin_cls ) : <EOL> if item_name . startswith ( "<STR_LIT>" ) : <EOL> continue <EOL> item = getattr ( mixin_cls , item_name ) <EOL> if isinstance ( item , types . MethodType ) : <EOL> item = item . im_func <EOL> setattr ( cls , item_name , item ) <EOL> return mixin_cls <EOL> def default_value ( self ) : <EOL> return self . default <EOL> def is_similar_to ( self , other ) : <EOL> return ( <EOL> type ( self ) == type ( other ) and <EOL> self . default == other . default and <EOL> self . nullable == other . nullable and <EOL> self . description == other . description <EOL> ) <EOL> auto_store = SchemaStore ( ) <EOL> class PySchema ( ABCMeta ) : <EOL> """<STR_LIT>""" <EOL> auto_register = True <EOL> def __new__ ( metacls , name , bases , dct ) : <EOL> schema_attrs = metacls . _get_schema_attributes ( <EOL> name = name , <EOL> bases = bases , <EOL> dct = dct <EOL> ) <EOL> dct . update ( schema_attrs ) <EOL> cls = ABCMeta . __new__ ( metacls , name , bases , dct ) <EOL> for field_name , field in cls . _fields . iteritems ( ) : <EOL> field . set_parent ( cls ) <EOL> if metacls . auto_register : <EOL> auto_store . add_record ( cls , _bump_stack_level = True ) <EOL> return cls <EOL> @ classmethod <EOL> def _field_dupe_warning ( metacls , name , fields ) : <EOL> warnings . warn ( <EOL> "<STR_LIT>" <EOL> . format ( <EOL> schema = name , <EOL> field = fields , <EOL> plural = "<STR_LIT:s>" if len ( fields ) > <NUM_LIT:1> else "<STR_LIT>" <EOL> ) , <EOL> stacklevel = <NUM_LIT:4> <EOL> ) <EOL> @ classmethod <EOL> def _get_schema_attributes ( metacls , name , bases , dct ) : <EOL> fields = OrderedDict ( ) <EOL> for b in bases : <EOL> if not isinstance ( b , metacls ) : <EOL> continue <EOL> field_intersection = set ( fields ) & set ( b . _fields ) <EOL> if field_intersection : <EOL> metacls . _field_dupe_warning ( name , field_intersection ) <EOL> fields . update ( b . _fields ) <EOL> new_fields = [ ] <EOL> for field_name , field_def in dct . iteritems ( ) : <EOL> if isinstance ( field_def , Field ) : <EOL> new_fields . append ( ( field_name , field_def ) ) <EOL> new_fields . sort ( key = lambda fd : fd [ <NUM_LIT:1> ] . _index ) <EOL> for field_name , field_def in new_fields : <EOL> if field_name in fields : <EOL> metacls . _field_dupe_warning ( name , ( field_name , ) ) <EOL> fields [ field_name ] = field_def <EOL> return { <EOL> "<STR_LIT>" : fields , <EOL> "<STR_LIT>" : name , <EOL> } <EOL> @ classmethod <EOL> def from_class ( metacls , cls , auto_store = True ) : <EOL> """<STR_LIT>""" <EOL> if auto_store : <EOL> def wrap ( cls ) : <EOL> return cls <EOL> else : <EOL> wrap = no_auto_store ( ) <EOL> return wrap ( metacls . __new__ ( <EOL> metacls , <EOL> cls . __name__ , <EOL> ( Record , ) , <EOL> dict ( cls . __dict__ ) <EOL> ) ) <EOL> def disable_auto_register ( ) : <EOL> PySchema . auto_register = False <EOL> def enable_auto_register ( ) : <EOL> PySchema . auto_register = True <EOL> def no_auto_store ( ) : <EOL> """<STR_LIT>""" <EOL> original_auto_register_value = PySchema . auto_register <EOL> disable_auto_register ( ) <EOL> def decorator ( cls ) : <EOL> PySchema . auto_register = original_auto_register_value <EOL> return cls <EOL> return decorator <EOL> @ no_auto_store ( ) <EOL> class Record ( object ) : <EOL> """<STR_LIT>""" <EOL> __metaclass__ = PySchema <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> if args : <EOL> raise TypeError ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> for k , field_type in self . _fields . items ( ) : <EOL> if k in kwargs : <EOL> value = kwargs . get ( k ) <EOL> else : <EOL> value = field_type . default_value ( ) <EOL> object . __setattr__ ( self , k , value ) <EOL> def __setattr__ ( self , name , value ) : <EOL> if name not in self . _fields : <EOL> raise AttributeError ( <EOL> "<STR_LIT>" <EOL> % ( name , self . _schema_name ) <EOL> ) <EOL> super ( Record , self ) . __setattr__ ( name , value ) <EOL> def __unicode__ ( self ) : <EOL> return str ( self ) . decode ( '<STR_LIT:ascii>' ) <EOL> def __str__ ( self ) : <EOL> return repr ( self ) <EOL> def __repr__ ( self ) : <EOL> strings = ( '<STR_LIT>' % ( fname , getattr ( self , fname ) ) <EOL> for fname , f in self . _fields . iteritems ( ) ) <EOL> return self . _schema_name + '<STR_LIT:(>' + '<STR_LIT:U+002CU+0020>' . join ( strings ) + '<STR_LIT:)>' <EOL> def __cmp__ ( self , other ) : <EOL> if not isinstance ( other , Record ) : <EOL> return cmp ( id ( self ) , other ) <EOL> if self . _schema_name != other . _schema_name : <EOL> return cmp ( self . _schema_name , other . _schema_name ) <EOL> fields = self . _fields . keys ( ) <EOL> a = ( getattr ( self , key ) for key in fields ) <EOL> b = ( getattr ( other , key ) for key in fields ) <EOL> for _a , _b in izip ( a , b ) : <EOL> r = cmp ( _a , _b ) <EOL> if r : <EOL> return r <EOL> return <NUM_LIT:0> <EOL> def __eq__ ( self , other ) : <EOL> return self . __cmp__ ( other ) == <NUM_LIT:0> <EOL> def __ne__ ( self , other ) : <EOL> return self . __cmp__ ( other ) != <NUM_LIT:0> <EOL> def to_json_compatible ( record ) : <EOL> "<STR_LIT>" <EOL> d = { } <EOL> for fname , f in record . _fields . iteritems ( ) : <EOL> val = getattr ( record , fname ) <EOL> if val is not None : <EOL> d [ fname ] = f . dump ( val ) <EOL> return d <EOL> def from_json_compatible ( schema , dct ) : <EOL> "<STR_LIT>" <EOL> kwargs = { } <EOL> for key in dct : <EOL> field_type = schema . _fields . get ( key ) <EOL> if field_type is None : <EOL> raise ParseError ( "<STR_LIT>" % ( schema . __name__ , key ) ) <EOL> kwargs [ key ] = field_type . load ( dct [ key ] ) <EOL> return schema ( ** kwargs ) <EOL> def ispyschema ( schema ) : <EOL> """<STR_LIT>""" <EOL> return isinstance ( schema , PySchema ) <EOL> def load_json_dct ( <EOL> dct , <EOL> record_store = None , <EOL> schema = None , <EOL> loader = from_json_compatible <EOL> ) : <EOL> """<STR_LIT>""" <EOL> if schema is None : <EOL> if record_store is None : <EOL> record_store = auto_store <EOL> try : <EOL> schema_name = dct . pop ( SCHEMA_FIELD_NAME ) <EOL> except KeyError : <EOL> raise ParseError ( ( <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" ) <EOL> . format ( SCHEMA_FIELD_NAME ) <EOL> ) <EOL> try : <EOL> schema = record_store . get ( schema_name ) <EOL> except KeyError : <EOL> raise ParseError ( <EOL> "<STR_LIT>" <EOL> % ( schema_name , ) , schema_name ) <EOL> elif SCHEMA_FIELD_NAME in dct : <EOL> dct . pop ( SCHEMA_FIELD_NAME ) <EOL> record = loader ( schema , dct ) <EOL> return record <EOL> def loads ( <EOL> s , <EOL> record_store = None , <EOL> schema = None , <EOL> loader = from_json_compatible , <EOL> record_class = None <EOL> ) : <EOL> """<STR_LIT>""" <EOL> if record_class is not None : <EOL> warnings . warn ( <EOL> "<STR_LIT>" , <EOL> DeprecationWarning , <EOL> stacklevel = <NUM_LIT:2> <EOL> ) <EOL> schema = record_class <EOL> if not isinstance ( s , unicode ) : <EOL> s = s . decode ( '<STR_LIT:utf8>' ) <EOL> if s . startswith ( u"<STR_LIT:{>" ) : <EOL> json_dct = json . loads ( s ) <EOL> return load_json_dct ( json_dct , record_store , schema , loader ) <EOL> else : <EOL> raise ParseError ( "<STR_LIT>" ) <EOL> def dumps ( obj , attach_schema_name = True ) : <EOL> json_dct = to_json_compatible ( obj ) <EOL> if attach_schema_name : <EOL> json_dct [ SCHEMA_FIELD_NAME ] = get_full_name ( obj . __class__ ) <EOL> json_string = json . dumps ( json_dct ) <EOL> return json_string </s>
