def propertycheck()

in src/cfnlint/rules/resources/properties/Properties.py [0:0]


    def propertycheck(self, text, proptype, parenttype, resourcename, path, root):
        """Check individual properties"""

        parameternames = self.parameternames
        matches = []
        if root:
            specs = self.resourcetypes
            resourcetype = parenttype
        else:
            specs = self.propertytypes
            resourcetype = str.format('{0}.{1}', parenttype, proptype)
            # Handle tags
            if resourcetype not in specs:
                if proptype in specs:
                    resourcetype = proptype
                else:
                    resourcetype = str.format('{0}.{1}', parenttype, proptype)
            else:
                resourcetype = str.format('{0}.{1}', parenttype, proptype)

        resourcespec = specs[resourcetype].get('Properties', {})
        if not resourcespec:
            if specs[resourcetype].get('Type') == 'List':
                if isinstance(text, list):
                    property_type = specs[resourcetype].get('ItemType')
                    for index, item in enumerate(text):
                        matches.extend(
                            self.propertycheck(
                                item, property_type, parenttype, resourcename,
                                path[:] + [index], root))

            return matches
        supports_additional_properties = specs[resourcetype].get('AdditionalProperties', False)

        if text == 'AWS::NoValue':
            return matches
        if not isinstance(text, dict):
            if not self.check_exceptions(parenttype, proptype, text):
                message = 'Expecting an object at %s' % ('/'.join(map(str, path)))
                matches.append(RuleMatch(path, message))
            return matches

        # You can put in functions directly in place of objects as long as that is
        # the only thing there (conditions, select) could all (possibly)
        # return objects.  FindInMap cannot directly return an object.
        len_of_text = len(text)

        #pylint: disable=too-many-nested-blocks
        for prop in text:
            proppath = path[:]
            proppath.append(prop)
            if prop not in resourcespec:
                if prop in cfnlint.helpers.CONDITION_FUNCTIONS and len_of_text == 1:
                    cond_values = self.cfn.get_condition_values(text[prop])
                    for cond_value in cond_values:
                        if isinstance(cond_value['Value'], dict):
                            matches.extend(self.propertycheck(
                                cond_value['Value'], proptype, parenttype, resourcename,
                                proppath + cond_value['Path'], root))
                        elif isinstance(cond_value['Value'], list):
                            for index, item in enumerate(cond_value['Value']):
                                matches.extend(
                                    self.propertycheck(
                                        item, proptype, parenttype, resourcename,
                                        proppath + cond_value['Path'] + [index], root)
                                )
                elif text.is_function_returning_object():
                    self.logger.debug('Ran into function "%s".  Skipping remaining checks', prop)
                elif len(text) == 1 and prop in 'Ref' and text.get(prop) == 'AWS::NoValue':
                    pass
                elif not supports_additional_properties:
                    message = 'Invalid Property %s' % ('/'.join(map(str, proppath)))
                    matches.append(RuleMatch(proppath, message))
            else:
                if 'Type' in resourcespec[prop]:
                    if resourcespec[prop]['Type'] == 'List':
                        if 'PrimitiveItemType' not in resourcespec[prop]:
                            if isinstance(text[prop], list):
                                for index, item in enumerate(text[prop]):
                                    arrproppath = proppath[:]
                                    arrproppath.append(index)
                                    matches.extend(self.propertycheck(
                                        item, resourcespec[prop]['ItemType'],
                                        parenttype, resourcename, arrproppath, False))
                            elif (isinstance(text[prop], dict)):
                                # A list can be be specific as a Conditional
                                matches.extend(
                                    self.check_list_for_condition(
                                        text, prop, parenttype, resourcename, resourcespec[prop], proppath)
                                )
                            else:
                                message = 'Property {0} should be of type List for resource {1}'
                                matches.append(
                                    RuleMatch(
                                        proppath,
                                        message.format(prop, resourcename)))
                        else:
                            if isinstance(text[prop], list):
                                primtype = resourcespec[prop]['PrimitiveItemType']
                                for index, item in enumerate(text[prop]):
                                    arrproppath = proppath[:]
                                    arrproppath.append(index)
                                    matches.extend(self.primitivetypecheck(
                                        item, primtype, arrproppath))
                            elif isinstance(text[prop], dict):
                                if 'Ref' in text[prop]:
                                    ref = text[prop]['Ref']
                                    if ref == 'AWS::NotificationARNs':
                                        continue
                                    if ref in parameternames:
                                        param_type = self.cfn.template['Parameters'][ref]['Type']
                                        if param_type:
                                            if 'List<' not in param_type and '<List' not in param_type and not param_type == 'CommaDelimitedList':
                                                message = 'Property {0} should be of type List or Parameter should ' \
                                                          'be a list for resource {1}'
                                                matches.append(
                                                    RuleMatch(
                                                        proppath,
                                                        message.format(prop, resourcename)))
                                    else:
                                        message = 'Property {0} should be of type List for resource {1}'
                                        matches.append(
                                            RuleMatch(
                                                proppath,
                                                message.format(prop, resourcename)))
                                else:
                                    if len(text[prop]) == 1:
                                        for k in text[prop].keys():
                                            def_intrinsic_type = self.intrinsictypes.get(k, {})
                                            if def_intrinsic_type:
                                                if len(def_intrinsic_type.get('ReturnTypes')) == 1 and def_intrinsic_type.get('ReturnTypes')[0] == 'Singular':
                                                    message = 'Property {0} is using {1} when a List is needed for resource {2}'
                                                    matches.append(
                                                        RuleMatch(
                                                            proppath,
                                                            message.format(prop, k, resourcename)))
                            else:
                                message = 'Property {0} should be of type List for resource {1}'
                                matches.append(
                                    RuleMatch(
                                        proppath,
                                        message.format(prop, resourcename)))
                    else:
                        if resourcespec[prop]['Type'] not in ['Map']:
                            matches.extend(self.propertycheck(
                                text[prop], resourcespec[prop]['Type'], parenttype,
                                resourcename, proppath, False))
                elif 'PrimitiveType' in resourcespec[prop]:
                    primtype = resourcespec[prop]['PrimitiveType']
                    matches.extend(self.primitivetypecheck(text[prop], primtype, proppath))

        return matches