Make the various property checks use the entire class hierarchy

This commit is contained in:
Robert MacGregor 2016-04-22 02:19:49 -04:00
parent c23b0883b5
commit 84d321eabf

View file

@ -227,6 +227,7 @@ class TSScraper(object):
_datablock_rules = { _datablock_rules = {
"tracerprojectiledata": { "tracerprojectiledata": {
"references": ["splash", "explosion", "sound"], "references": ["splash", "explosion", "sound"],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { "checks": {
"fizzletimems": (lambda x: x >= 0, "Cannot use negative fizzle time!") "fizzletimems": (lambda x: x >= 0, "Cannot use negative fizzle time!")
@ -235,6 +236,7 @@ class TSScraper(object):
"shapebaseimagedata": { "shapebaseimagedata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { "checks": {
} }
@ -242,84 +244,100 @@ class TSScraper(object):
"itemdata": { "itemdata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { "pickupradius": (lambda x: x >= 1, "Items should have >= 1 pickup radius.") "checks": { "pickupradius": (lambda x: x >= 1, "Items should have >= 1 pickup radius.")
} }
}, },
"audioprofile": { "audioprofile": {
"references": [ ], "references": [ "description" ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"simdatablock": { "simdatablock": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"jeteffectdata": { "jeteffectdata": {
"references": [ ], "references": [ ],
"declared": [ ], "optional_references": [ ],
"declared": [ "texture" ],
"checks": { }, "checks": { },
}, },
"hovervehicledata": { "hovervehicledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ "catagory" ], "declared": [ "catagory" ],
"checks": { }, "checks": { "dragforce": (lambda x: x >= 0.01, "dragForce must be at least 0.01"),
"vertfactor": (lambda x: x >= 0 and x <= 1.0, "vertFactor must be >= 0 && <= 1.0"),
"floatingthrustfactor": (lambda x: x >= 0 and x <= 1.0, "floatThrustFactor must be >= 0 && <= 1.0") },
}, },
"stationfxpersonaldata": { "stationfxpersonaldata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"cameradata": { "cameradata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"triggerdata": { "triggerdata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"wheeledvehicledata": { "wheeledvehicledata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ "catagory" ], "declared": [ "catagory" ],
"checks": { }, "checks": { },
}, },
"tsshapeconstructor": { "tsshapeconstructor": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"bombprojectiledata": { "bombprojectiledata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"stationfxvehicledata": { "stationfxvehicledata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"runninglightdata": { "runninglightdata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { "radius": (lambda x: x >= 1, "Lights should have a radius of >= 1.") }, "checks": { "radius": (lambda x: x >= 1, "Lights should have a radius of >= 1.") },
}, },
"staticshapedata": { "staticshapedata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
@ -327,35 +345,41 @@ class TSScraper(object):
"decaldata": { "decaldata": {
"references": [ ], "references": [ ],
"declared": [ ], "optional_references": [ ],
"declared": [ "texturename" ],
"checks": { }, "checks": { },
}, },
"repairprojectiledata": { "repairprojectiledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"explosiondata": { "explosiondata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"linearprojectiledata": { "linearprojectiledata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"elfprojectiledata": { "elfprojectiledata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"linearflareprojectiledata": { "linearflareprojectiledata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
@ -363,11 +387,13 @@ class TSScraper(object):
"sensordata": { "sensordata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"forcefieldbaredata": { "forcefieldbaredata": {
"optional_references": [ ],
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
@ -375,42 +401,49 @@ class TSScraper(object):
"particledata": { "particledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"particleemitterdata": { "particleemitterdata": {
"references": [ ], "references": [ "particles" ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"playerdata": { "playerdata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { "shapefile": (lambda x: x is not None and x != "", "Must have a valid shapefile!") }, "checks": { "shapefile": (lambda x: x is not None and x != "", "Must have a valid shapefile!") },
}, },
"turretdata": { "turretdata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"turretimagedata": { "turretimagedata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"shockwavedata": { "shockwavedata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"seekerprojectiledata": { "seekerprojectiledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
@ -418,11 +451,13 @@ class TSScraper(object):
"debrisdata": { "debrisdata": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"grenadeprojectiledata": { "grenadeprojectiledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
@ -430,17 +465,20 @@ class TSScraper(object):
"sniperprojectiledata": { "sniperprojectiledata": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"sniperprojectiledata": { "sniperprojectiledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"flyingvehicledata": { "flyingvehicledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ "catagory" ], "declared": [ "catagory" ],
"checks": { }, "checks": { },
}, },
@ -448,17 +486,20 @@ class TSScraper(object):
"splashdata": { "splashdata": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"energyprojectiledata": { "energyprojectiledata": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"flareprojectiledata": { "flareprojectiledata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
@ -466,35 +507,41 @@ class TSScraper(object):
"targetprojectiledata": { "targetprojectiledata": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"shocklanceprojectiledata": { "shocklanceprojectiledata": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"effectprofile": { "effectprofile": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"precipitationdata": { "precipitationdata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"commandericondata": { "commandericondata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"missionmarkerdata": { "missionmarkerdata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
@ -502,17 +549,20 @@ class TSScraper(object):
"particleemissiondummydata": { "particleemissiondummydata": {
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"optional_references": [ ],
"checks": { }, "checks": { },
}, },
"fireballatmospheredata": { "fireballatmospheredata": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
"audiodescription": { "audiodescription": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
@ -521,10 +571,12 @@ class TSScraper(object):
"references": [ ], "references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
"optional_references": [ ],
}, },
"audioenvironment": { "audioenvironment": {
"references": [ ], "references": [ ],
"optional_references": [ ],
"declared": [ ], "declared": [ ],
"checks": { }, "checks": { },
}, },
@ -675,55 +727,79 @@ class TSScraper(object):
# For each datablock # For each datablock
for datablock in file.datablocks: for datablock in file.datablocks:
if (datablock.type in self._datablock_rules): if (datablock.type in self._datablock_rules):
# We have a bunch of rules to check, so we recurse parent classes where necessary.
parent_classes = [ datablock.name ]
# Recurse down the hierarchy
def process_parents(current, result):
if (current.derived is not None):
result += current.derived
for parent in current.derived:
parent_declarations = datablock_list[parent]
# Check for the property on each parent block
for parent in parent_declarations:
process_parents(parent, result)
return result
process_parents(datablock, parent_classes)
# Flip through each reference in the table # Flip through each reference in the table
for reference in self._datablock_rules[datablock.type]["references"]: for reference in self._datablock_rules[datablock.type]["references"]:
if (reference not in datablock.properties): found_reference = False
for parent in parent_classes:
# FIXME: Deal with datablock redeclarations?
parent_datablock = datablock_list[parent][0]
if (reference in datablock.properties):
if (datablock.properties[reference].lower() not in datablock_list.keys()):
print("Reference Warning: %s Datablock '%s' references '%s' in property '%s', which does not exist! (Declaration in %s, line %u)" % (datablock.type, datablock.name, datablock.properties[reference], reference, datablock.filepath, datablock.line))
break
else:
found_reference = True
break
if (found_reference is False):
print("Reference Warning: %s datablock '%s' has no '%s' declaration! (Declaration in %s, line %u)" % (datablock.type, datablock.name, reference, datablock.filepath, datablock.line)) print("Reference Warning: %s datablock '%s' has no '%s' declaration! (Declaration in %s, line %u)" % (datablock.type, datablock.name, reference, datablock.filepath, datablock.line))
else:
if (datablock.properties[reference].lower() not in datablock_list.keys()):
print("Reference Warning: %s Datablock '%s' references '%s' in property '%s', which does not exist! (Declaration in %s, line %u)" % (datablock.type, datablock.name, datablock.properties[reference], reference, datablock.filepath, datablock.line))
# Check each declaration # Check each declaration
for declaration in self._datablock_rules[datablock.type]["declared"]: for declaration in self._datablock_rules[datablock.type]["declared"]:
if (declaration not in datablock.properties): found_declaration = False
for parent in parent_classes:
# FIXME: Deal with datablock redeclarations?
parent_datablock = datablock_list[parent][0]
if (declaration in datablock.properties):
found_declaration = True
break
if (found_declaration is False):
print("Declaration Warning: %s Datablock '%s' required property '%s' not declared! (Declaration in %s, line %u)" % (datablock.type, datablock.name, declaration, datablock.filepath, datablock.line)) print("Declaration Warning: %s Datablock '%s' required property '%s' not declared! (Declaration in %s, line %u)" % (datablock.type, datablock.name, declaration, datablock.filepath, datablock.line))
# Run custom checks # Run custom checks
for check in self._datablock_rules[datablock.type]["checks"].keys(): for check in self._datablock_rules[datablock.type]["checks"].keys():
# Is it declared? found_check = False
if (check not in datablock.properties):
# If its not declared explicitly, check the inheritance tree
if (datablock.derived is None):
print("Property Warning: %s Datablock %s '%s' property not declared and there is no parent to inherit from! (Declaration in %s, line %u)" % (datablock.type, datablock.name, check, datablock.filepath, datablock.line))
else:
# Recurse down the hierarchy
def process_parents(current, property):
if (current.derived is not None):
for parent in current.derived:
parent_declarations = datablock_list[parent]
# Check for the property on each parent block for parent in parent_classes:
for parent in parent_declarations: # FIXME: Deal with datablock redeclarations?
if (property in parent.properties): parent_datablock = datablock_list[parent][0]
found_property = True
method, message = self._datablock_rules[datablock.type]["checks"][property] # Is it declared?
if (not method(parent.properties[property])): if (check not in parent_datablock.properties):
print("Inherited Property Warning (Child Datablock '%s', Parent Datablock '%s', type %s. Declaration in %s, line %u): %s" % (current.name, parent.name, current.type, current.filepath, current.line, message)) continue
return True
found_property = process_parents(parent, property) found_check = True
if (found_property is True): method, message = self._datablock_rules[parent_datablock.type]["checks"][check]
return True
return False
found_property = process_parents(datablock, check) if (not method(parent_datablock.properties[check])):
if (found_property is False):
print("Inherited Property Warning: %s Datablock %s '%s' property not declared and parent datablocks do not declare it! (Declaration in %s, line %u)" % (datablock.type, datablock.name, check, datablock.filepath, datablock.line))
else:
method, message = self._datablock_rules[datablock.type]["checks"][check]
if (not method(datablock.properties[check])):
print("Property Warning (Datablock '%s', type %s. Declaration in %s, line %u): %s" % (datablock.name, datablock.type, datablock.filepath, datablock.line, message)) print("Property Warning (Datablock '%s', type %s. Declaration in %s, line %u): %s" % (datablock.name, datablock.type, datablock.filepath, datablock.line, message))
break
if (found_check is False):
print("Inherited Property Warning: %s Datablock %s '%s' property not declared and parent datablocks do not declare it! (Declaration in %s, line %u)" % (datablock.type, datablock.name, check, datablock.filepath, datablock.line))
else: else:
print("Program Error: Unknown datablock type '%s'! This means the software does not know how to check this datablock. (Declaration in %s, line %u)" % (datablock.type, datablock.filepath, datablock.line)) print("Program Error: Unknown datablock type '%s'! This means the software does not know how to check this datablock. (Declaration in %s, line %u)" % (datablock.type, datablock.filepath, datablock.line))