def __init__(self, data_model, query_rules=None):

        '''
            a method for testing data model declaration & initializing the class

        :param data_model: dictionary with json model architecture
        :param query_rules: [optional] dictionary with valid field type qualifiers
        :return: object with jsonModel methods
        '''

    # validate schema input
        if not isinstance(data_model, dict):
            raise ModelValidationError('Data model must be a dictionary.')
        elif 'schema' not in data_model.keys():
            raise ModelValidationError('Data model must have a schema key.')
        elif not isinstance(data_model['schema'], dict):
            raise ModelValidationError('Value for the data model "schema" field must be a dictionary.')
        elif not data_model['schema']:
            raise ModelValidationError('Data model "schema" field must not be empty.')

    # construct base methods
        from copy import deepcopy
        data_model = deepcopy(data_model)
        self.schema = data_model['schema']
        model_map = mapModel(self.schema)
        self.keyName = model_map.keyName
        self.keyCriteria = model_map.keyCriteria

    # construct protected type classes
        self._datatype_names = mapModel._datatype_names
        self._datatype_classes = mapModel._datatype_classes

    # validate absence of item designators in keys
        item_pattern = re.compile('\[\d+\]')
        for i in range(len(self.keyName)):
            patterns_found = item_pattern.findall(self.keyName[i])
            if patterns_found:
                for designator in patterns_found:
                    if designator != '[0]':
                        message = 'Key name for schema field %s must not contain the item designator pattern %s' % (self.keyName[i], designator)
                        raise ModelValidationError(message)

    # validate existence of first item in list declarations
        key_set = set(self.keyName)
        for i in range(len(self.keyName)):
            if self.keyCriteria[i]['value_datatype'] == 'list':
                item_key = self.keyName[i] + '[0]'
                if not item_key in key_set:
                    message = 'Schema field %s must declare an initial item for the list.' % self.keyName[i]
                    raise ModelValidationError(message)

            # alter list requirement if first item is empty
                else:
                    item_index = self.keyName.index(item_key)
                    if not self.keyCriteria[item_index]['required_field']:
                        self.keyCriteria[i]['required_field'] = False

    # validate title input & construct title method
        self.title = ''
        if 'title' in data_model.keys():
            if not isinstance(data_model['title'], str):
                raise ModelValidationError('Value for model title must be a string.')
            self.title = data_model['title']

    # validate description input & construct description method
        self.description = ''
        if 'description' in data_model.keys():
            if not isinstance(data_model['description'], str):
                raise ModelValidationError('Value for model description must be a string.')
            self.description = data_model['description']

    # validate url input & construct title method
        self.url = ''
        if 'url' in data_model.keys():
            if not isinstance(data_model['url'], str):
                raise ModelValidationError('Value for model url must be a string.')
            self.title = data_model['url']

    # validate metadata input & construct metadata method
        self.metadata = {}
        if 'metadata' in data_model.keys():
            if not isinstance(data_model['metadata'], dict):
                raise ModelValidationError('Value for model metadata must be a dictionary.')
            self.metadata = data_model['metadata']

    # validate max size input & construct maxSize property
    #     self.maxSize = None
    #     if 'max_size' in data_model.keys():
    #         if not isinstance(data_model['max_size'], int):
    #             raise ModelValidationError('Value for model max_size must be a positive integer.')
    #         elif data_model['max_size'] < 0:
    #             raise ModelValidationError('Value for model max_size must be a positive integer.')
    #         elif data_model['max_size']:
    #             self.maxSize = data_model['max_size']

    # validate components input & construct component property
        self.components = {}
        if 'components' in data_model.keys():
            if not isinstance(data_model['components'], dict):
                raise ModelValidationError('Value for model components must be a dictionary.')
            self.components = self._validate_fields(data_model['components'], self.__rules__['components'])

    # construct keyMap fields from key names and key criteria
        self.keyMap = {}
        for i in range(len(self.keyName)):
            self.keyMap[self.keyName[i]] = self.keyCriteria[i]
        for key, value in self.components.items():

        # convert javascript dot_path to class dot_path
            dot_key = ''
            if not key:
                dot_key = '.'
            else:
                if key[0] != '.':
                    dot_key = '.%s' % key

        # add component declarations to keyMap
            if key in self.keyMap.keys():
                for k, v in self.components[key].items():
                    self.keyMap[key][k] = v
            elif dot_key and dot_key in self.keyMap.keys():
                for k, v in self.components[key].items():
                    self.keyMap[dot_key][k] = v

    # validate default values in lists
        self._validate_defaults(self.keyMap)

    # construct queryRules property from class model rules
        self.queryRules = {}
        for key, value in self.__rules__['components'].items():
            remove_from_query = [ 'required_field', 'default_value', 'example_values', 'field_title', 'field_position', 'field_description', 'field_metadata', 'extra_fields' ]
            field_qualifiers = {
                'value_exists': False
            }
            for k, v in value.items():
                if k not in remove_from_query:
                    field_qualifiers[k] = v
            self.queryRules[key] = field_qualifiers

    # validate query rules input and replace queryRules property
        if query_rules:
            if not isinstance(query_rules, dict):
                message = 'Value for query rules input must be a dictionary.'
                raise ModelValidationError(message)
            input_set = set(query_rules.keys())
            req_set = set(self.queryRules.keys())
            if input_set - req_set:
                message = 'Query rules input may only have %s field key names.' % req_set
                raise ModelValidationError(message)
            elif req_set - input_set:
                message = 'Query rules input must have all %s field key names.' % req_set
                raise ModelValidationError(message)
            for key in req_set:
                if not isinstance(query_rules[key], dict):
                    message = 'Value for query rules %s field must be a dictionary.' % key
                    raise ModelValidationError(message)
                input_qualifier_set = set(query_rules[key].keys())
                req_qualifier_set = set(self.queryRules[key].keys())
                if input_qualifier_set - req_qualifier_set:
                    message = 'Query rules field %s may only have qualifiers %s' % (key, req_qualifier_set)
                    raise ModelValidationError(message)
                for k, v in query_rules[key].items():
                    if v.__class__ != self.queryRules[key][k].__class__:
                        qualifier_index = self._datatype_classes.index(self.queryRules[key][k].__class__)
                        qualifier_type = self._datatype_names[qualifier_index]
                        message = 'Value for query rules field %s qualifier %s must be a "%s" datatype.' % (key, k, qualifier_type)
                        raise ModelValidationError(message)
            self.queryRules = query_rules
def __init__ ( self , data_model , query_rules = None ) : if not isinstance ( data_model , dict ) : raise ModelValidationError ( 'Data model must be a dictionary.' ) elif 'schema' not in data_model . keys ( ) : raise ModelValidationError ( 'Data model must have a schema key.' ) elif not isinstance ( data_model [ 'schema' ] , dict ) : raise ModelValidationError ( 'Value for the data model "schema" field must be a dictionary.' ) elif not data_model [ 'schema' ] : raise ModelValidationError ( 'Data model "schema" field must not be empty.' ) from copy import deepcopy data_model = deepcopy ( data_model ) self . schema = data_model [ 'schema' ] model_map = mapModel ( self . schema ) self . keyName = model_map . keyName self . keyCriteria = model_map . keyCriteria self . _datatype_names = mapModel . _datatype_names self . _datatype_classes = mapModel . _datatype_classes item_pattern = re . compile ( '\[\d+\]' ) for i in range ( len ( self . keyName ) ) : patterns_found = item_pattern . findall ( self . keyName [ i ] ) if patterns_found : for designator in patterns_found : if designator != '[0]' : message = 'Key name for schema field %s must not contain the item designator pattern %s' % ( self . keyName [ i ] , designator ) raise ModelValidationError ( message ) key_set = set ( self . keyName ) for i in range ( len ( self . keyName ) ) : if self . keyCriteria [ i ] [ 'value_datatype' ] == 'list' : item_key = self . keyName [ i ] + '[0]' if not item_key in key_set : message = 'Schema field %s must declare an initial item for the list.' % self . keyName [ i ] raise ModelValidationError ( message ) else : item_index = self . keyName . index ( item_key ) if not self . keyCriteria [ item_index ] [ 'required_field' ] : self . keyCriteria [ i ] [ 'required_field' ] = False self . title = '' if 'title' in data_model . keys ( ) : if not isinstance ( data_model [ 'title' ] , str ) : raise ModelValidationError ( 'Value for model title must be a string.' ) self . title = data_model [ 'title' ] self . description = '' if 'description' in data_model . keys ( ) : if not isinstance ( data_model [ 'description' ] , str ) : raise ModelValidationError ( 'Value for model description must be a string.' ) self . description = data_model [ 'description' ] self . url = '' if 'url' in data_model . keys ( ) : if not isinstance ( data_model [ 'url' ] , str ) : raise ModelValidationError ( 'Value for model url must be a string.' ) self . title = data_model [ 'url' ] self . metadata = { } if 'metadata' in data_model . keys ( ) : if not isinstance ( data_model [ 'metadata' ] , dict ) : raise ModelValidationError ( 'Value for model metadata must be a dictionary.' ) self . metadata = data_model [ 'metadata' ] self . components = { } if 'components' in data_model . keys ( ) : if not isinstance ( data_model [ 'components' ] , dict ) : raise ModelValidationError ( 'Value for model components must be a dictionary.' ) self . components = self . _validate_fields ( data_model [ 'components' ] , self . __rules__ [ 'components' ] ) self . keyMap = { } for i in range ( len ( self . keyName ) ) : self . keyMap [ self . keyName [ i ] ] = self . keyCriteria [ i ] for key , value in self . components . items ( ) : dot_key = '' if not key : dot_key = '.' else : if key [ 0 ] != '.' : dot_key = '.%s' % key if key in self . keyMap . keys ( ) : for k , v in self . components [ key ] . items ( ) : self . keyMap [ key ] [ k ] = v elif dot_key and dot_key in self . keyMap . keys ( ) : for k , v in self . components [ key ] . items ( ) : self . keyMap [ dot_key ] [ k ] = v self . _validate_defaults ( self . keyMap ) self . queryRules = { } for key , value in self . __rules__ [ 'components' ] . items ( ) : remove_from_query = [ 'required_field' , 'default_value' , 'example_values' , 'field_title' , 'field_position' , 'field_description' , 'field_metadata' , 'extra_fields' ] field_qualifiers = { 'value_exists' : False } for k , v in value . items ( ) : if k not in remove_from_query : field_qualifiers [ k ] = v self . queryRules [ key ] = field_qualifiers if query_rules : if not isinstance ( query_rules , dict ) : message = 'Value for query rules input must be a dictionary.' raise ModelValidationError ( message ) input_set = set ( query_rules . keys ( ) ) req_set = set ( self . queryRules . keys ( ) ) if input_set - req_set : message = 'Query rules input may only have %s field key names.' % req_set raise ModelValidationError ( message ) elif req_set - input_set : message = 'Query rules input must have all %s field key names.' % req_set raise ModelValidationError ( message ) for key in req_set : if not isinstance ( query_rules [ key ] , dict ) : message = 'Value for query rules %s field must be a dictionary.' % key raise ModelValidationError ( message ) input_qualifier_set = set ( query_rules [ key ] . keys ( ) ) req_qualifier_set = set ( self . queryRules [ key ] . keys ( ) ) if input_qualifier_set - req_qualifier_set : message = 'Query rules field %s may only have qualifiers %s' % ( key , req_qualifier_set ) raise ModelValidationError ( message ) for k , v in query_rules [ key ] . items ( ) : if v . __class__ != self . queryRules [ key ] [ k ] . __class__ : qualifier_index = self . _datatype_classes . index ( self . queryRules [ key ] [ k ] . __class__ ) qualifier_type = self . _datatype_names [ qualifier_index ] message = 'Value for query rules field %s qualifier %s must be a "%s" datatype.' % ( key , k , qualifier_type ) raise ModelValidationError ( message ) self . queryRules = query_rules
a method for testing data model declaration & initializing the class

        :param data_model: dictionary with json model architecture
        :param query_rules: [optional] dictionary with valid field type qualifiers
        :return: object with jsonModel methods