Apply black to move Python style to standard form.

This commit is contained in:
Eric S. Raymond 2023-09-17 16:17:30 -04:00
parent ab4653b89c
commit 7d4dd78679
3 changed files with 265 additions and 151 deletions

View file

@ -24,6 +24,7 @@ DONOTEDIT_COMMENT = "/* Generated from adventure.yaml - do not hand-hack! */\n\n
statedefines = "" statedefines = ""
def make_c_string(string): def make_c_string(string):
"""Render a Python string into C string literal format.""" """Render a Python string into C string literal format."""
if string is None: if string is None:
@ -35,6 +36,7 @@ def make_c_string(string):
string = '"' + string + '"' string = '"' + string + '"'
return string return string
def get_refs(l): def get_refs(l):
reflist = [x[0] for x in l] reflist = [x[0] for x in l]
ref_str = "" ref_str = ""
@ -43,6 +45,7 @@ def get_refs(l):
ref_str = ref_str[:-1] # trim trailing newline ref_str = ref_str[:-1] # trim trailing newline
return ref_str return ref_str
def get_string_group(strings): def get_string_group(strings):
template = """{{ template = """{{
.strs = {}, .strs = {},
@ -51,11 +54,14 @@ def get_string_group(strings):
if strings == []: if strings == []:
strs = "NULL" strs = "NULL"
else: else:
strs = "(const char* []) {" + ", ".join([make_c_string(s) for s in strings]) + "}" strs = (
"(const char* []) {" + ", ".join([make_c_string(s) for s in strings]) + "}"
)
n = len(strings) n = len(strings)
sg_str = template.format(strs, n) sg_str = template.format(strs, n)
return sg_str return sg_str
def get_arbitrary_messages(arb): def get_arbitrary_messages(arb):
template = """ {}, template = """ {},
""" """
@ -65,6 +71,7 @@ def get_arbitrary_messages(arb):
arb_str = arb_str[:-1] # trim trailing newline arb_str = arb_str[:-1] # trim trailing newline
return arb_str return arb_str
def get_class_messages(cls): def get_class_messages(cls):
template = """ {{ template = """ {{
.threshold = {}, .threshold = {},
@ -79,6 +86,7 @@ def get_class_messages(cls):
cls_str = cls_str[:-1] # trim trailing newline cls_str = cls_str[:-1] # trim trailing newline
return cls_str return cls_str
def get_turn_thresholds(trn): def get_turn_thresholds(trn):
template = """ {{ template = """ {{
.threshold = {}, .threshold = {},
@ -95,6 +103,7 @@ def get_turn_thresholds(trn):
trn_str = trn_str[:-1] # trim trailing newline trn_str = trn_str[:-1] # trim trailing newline
return trn_str return trn_str
def get_locations(loc): def get_locations(loc):
template = """ {{ // {}: {} template = """ {{ // {}: {}
.description = {{ .description = {{
@ -115,6 +124,7 @@ def get_locations(loc):
loc_str = loc_str[:-1] # trim trailing newline loc_str = loc_str[:-1] # trim trailing newline
return loc_str return loc_str
def get_objects(obj): def get_objects(obj):
template = """ {{ // {}: {} template = """ {{ // {}: {}
.words = {}, .words = {},
@ -192,11 +202,24 @@ def get_objects(obj):
sys.stderr.write("dungeon: unknown object location in %s\n" % locs) sys.stderr.write("dungeon: unknown object location in %s\n" % locs)
sys.exit(1) sys.exit(1)
treasure = "true" if attr.get("treasure") else "false" treasure = "true" if attr.get("treasure") else "false"
obj_str += template.format(i, item[0], words_str, i_msg, locs[0], locs[1], treasure, descriptions_str, sounds_str, texts_str, changes_str) obj_str += template.format(
i,
item[0],
words_str,
i_msg,
locs[0],
locs[1],
treasure,
descriptions_str,
sounds_str,
texts_str,
changes_str,
)
obj_str = obj_str[:-1] # trim trailing newline obj_str = obj_str[:-1] # trim trailing newline
statedefines += "/* Maximum state value */\n#define MAX_STATE %d\n" % max_state statedefines += "/* Maximum state value */\n#define MAX_STATE %d\n" % max_state
return obj_str return obj_str
def get_obituaries(obit): def get_obituaries(obit):
template = """ {{ template = """ {{
.query = {}, .query = {},
@ -211,6 +234,7 @@ def get_obituaries(obit):
obit_str = obit_str[:-1] # trim trailing newline obit_str = obit_str[:-1] # trim trailing newline
return obit_str return obit_str
def get_hints(hnt): def get_hints(hnt):
template = """ {{ template = """ {{
.number = {}, .number = {},
@ -232,6 +256,7 @@ def get_hints(hnt):
hnt_str = hnt_str[:-1] # trim trailing newline hnt_str = hnt_str[:-1] # trim trailing newline
return hnt_str return hnt_str
def get_condbits(locations): def get_condbits(locations):
cnd_str = "" cnd_str = ""
for (name, loc) in locations: for (name, loc) in locations:
@ -242,7 +267,7 @@ def get_condbits(locations):
if conditions[flag]: if conditions[flag]:
flaglist.append(flag) flaglist.append(flag)
line = "|".join([("(1<<COND_%s)" % f) for f in flaglist]) line = "|".join([("(1<<COND_%s)" % f) for f in flaglist])
trail = "|".join([("(1<<COND_H%s)" % f['name']) for f in hints]) trail = "|".join([("(1<<COND_H%s)" % f["name"]) for f in hints])
if trail: if trail:
line += "|" + trail line += "|" + trail
if line.startswith("|"): if line.startswith("|"):
@ -252,6 +277,7 @@ def get_condbits(locations):
cnd_str += " " + line + ",\t// " + name + "\n" cnd_str += " " + line + ",\t// " + name + "\n"
return cnd_str return cnd_str
def get_motions(motions): def get_motions(motions):
template = """ {{ template = """ {{
.words = {}, .words = {},
@ -272,6 +298,7 @@ def get_motions(motions):
ignore += word.upper() ignore += word.upper()
return mot_str return mot_str
def get_actions(actions): def get_actions(actions):
template = """ {{ template = """ {{
.words = {}, .words = {},
@ -307,17 +334,19 @@ def get_actions(actions):
act_str = act_str[:-1] # trim trailing newline act_str = act_str[:-1] # trim trailing newline
return act_str return act_str
def bigdump(arr): def bigdump(arr):
out = "" out = ""
for (i, _) in enumerate(arr): for (i, _) in enumerate(arr):
if i % 10 == 0: if i % 10 == 0:
if out and out[-1] == ' ': if out and out[-1] == " ":
out = out[:-1] out = out[:-1]
out += "\n " out += "\n "
out += str(arr[i]).lower() + ", " out += str(arr[i]).lower() + ", "
out = out[:-2] + "\n" out = out[:-2] + "\n"
return out return out
def buildtravel(locs, objs): def buildtravel(locs, objs):
assert len(locs) <= 300 assert len(locs) <= 300
assert len(objs) <= 100 assert len(objs) <= 100
@ -372,13 +401,17 @@ def buildtravel(locs, objs):
verbmap[word.upper()] = i verbmap[word.upper()] = i
except TypeError: except TypeError:
pass pass
def dencode(action, name): def dencode(action, name):
"Decode a destination number" "Decode a destination number"
if action[0] == "goto": if action[0] == "goto":
try: try:
return locnames.index(action[1]) return locnames.index(action[1])
except ValueError: except ValueError:
sys.stderr.write("dungeon: unknown location %s in goto clause of %s\n" % (action[1], name)) sys.stderr.write(
"dungeon: unknown location %s in goto clause of %s\n"
% (action[1], name)
)
raise ValueError raise ValueError
elif action[0] == "special": elif action[0] == "special":
return 300 + action[1] return 300 + action[1]
@ -386,11 +419,15 @@ def buildtravel(locs, objs):
try: try:
return 500 + msgnames.index(action[1]) return 500 + msgnames.index(action[1])
except ValueError: except ValueError:
sys.stderr.write("dungeon: unknown location %s in carry clause of %s\n" % (cond[1], name)) sys.stderr.write(
"dungeon: unknown location %s in carry clause of %s\n"
% (cond[1], name)
)
else: else:
print(cond) print(cond)
raise ValueError raise ValueError
return '' # Pacify pylint return "" # Pacify pylint
def cencode(cond, name): def cencode(cond, name):
if cond is None: if cond is None:
return 0 return 0
@ -402,13 +439,19 @@ def buildtravel(locs, objs):
try: try:
return 100 + objnames.index(cond[1]) return 100 + objnames.index(cond[1])
except ValueError: except ValueError:
sys.stderr.write("dungeon: unknown object name %s in carry clause of %s\n" % (cond[1], name)) sys.stderr.write(
"dungeon: unknown object name %s in carry clause of %s\n"
% (cond[1], name)
)
sys.exit(1) sys.exit(1)
elif cond[0] == "with": elif cond[0] == "with":
try: try:
return 200 + objnames.index(cond[1]) return 200 + objnames.index(cond[1])
except IndexError: except IndexError:
sys.stderr.write("dungeon: unknown object name %s in with clause of %s\n" % (cond[1], name)) sys.stderr.write(
"dungeon: unknown object name %s in with clause of %s\n"
% (cond[1], name)
)
sys.exit(1) sys.exit(1)
elif cond[0] == "not": elif cond[0] == "not":
try: try:
@ -424,11 +467,17 @@ def buildtravel(locs, objs):
state = i state = i
break break
else: else:
sys.stderr.write("dungeon: unmatched state symbol %s in not clause of %s\n" % (cond[2], name)) sys.stderr.write(
"dungeon: unmatched state symbol %s in not clause of %s\n"
% (cond[2], name)
)
sys.exit(0) sys.exit(0)
return 300 + obj + 100 * state return 300 + obj + 100 * state
except ValueError: except ValueError:
sys.stderr.write("dungeon: unknown object name %s in not clause of %s\n" % (cond[1], name)) sys.stderr.write(
"dungeon: unknown object name %s in not clause of %s\n"
% (cond[1], name)
)
sys.exit(1) sys.exit(1)
else: else:
print(cond) print(cond)
@ -438,7 +487,9 @@ def buildtravel(locs, objs):
if "travel" in loc: if "travel" in loc:
for rule in loc["travel"]: for rule in loc["travel"]:
tt = [i] tt = [i]
dest = dencode(rule["action"], name) + 1000 * cencode(rule.get("cond"), name) dest = dencode(rule["action"], name) + 1000 * cencode(
rule.get("cond"), name
)
tt.append(dest) tt.append(dest)
tt += [motionnames[verbmap[e]].upper() for e in rule["verbs"]] tt += [motionnames[verbmap[e]].upper() for e in rule["verbs"]]
if not rule["verbs"]: if not rule["verbs"]:
@ -463,7 +514,7 @@ def buildtravel(locs, objs):
travel[-1][-1] = "false" if travel[-1][-1] == "true" else "true" travel[-1][-1] = "false" if travel[-1][-1] == "true" else "true"
while rule: while rule:
cond = newloc // 1000 cond = newloc // 1000
nodwarves = (cond == 100) nodwarves = cond == 100
if cond == 0: if cond == 0:
condtype = "cond_goto" condtype = "cond_goto"
condarg1 = condarg2 = 0 condarg1 = condarg2 = 0
@ -486,7 +537,7 @@ def buildtravel(locs, objs):
else: else:
condtype = "cond_not" condtype = "cond_not"
condarg1 = cond % 100 condarg1 = cond % 100
condarg2 = (cond - 300) // 100. condarg2 = (cond - 300) // 100.0
dest = newloc % 1000 dest = newloc % 1000
if dest <= 300: if dest <= 300:
desttype = "dest_goto" desttype = "dest_goto"
@ -497,7 +548,9 @@ def buildtravel(locs, objs):
else: else:
desttype = "dest_special" desttype = "dest_special"
destval = locnames[dest - 300] destval = locnames[dest - 300]
travel.append([len(tkey)-1, travel.append(
[
len(tkey) - 1,
locnames[len(tkey) - 1], locnames[len(tkey) - 1],
rule.pop(0), rule.pop(0),
condtype, condtype,
@ -506,10 +559,13 @@ def buildtravel(locs, objs):
desttype, desttype,
destval, destval,
"true" if nodwarves else "false", "true" if nodwarves else "false",
"false"]) "false",
]
)
travel[-1][-1] = "true" travel[-1][-1] = "true"
return (travel, tkey) return (travel, tkey)
def get_travel(travel): def get_travel(travel):
template = """ {{ // from {}: {} template = """ {{ // from {}: {}
.motion = {}, .motion = {},
@ -528,8 +584,9 @@ def get_travel(travel):
out = out[:-1] # trim trailing newline out = out[:-1] # trim trailing newline
return out return out
if __name__ == "__main__": if __name__ == "__main__":
with open(YAML_NAME, "r", encoding='ascii', errors='surrogateescape') as f: with open(YAML_NAME, "r", encoding="ascii", errors="surrogateescape") as f:
db = yaml.safe_load(f) db = yaml.safe_load(f)
locnames = [x[0] for x in db["locations"]] locnames = [x[0] for x in db["locations"]]
@ -537,18 +594,21 @@ if __name__ == "__main__":
objnames = [el[0] for el in db["objects"]] objnames = [el[0] for el in db["objects"]]
motionnames = [el[0] for el in db["motions"]] motionnames = [el[0] for el in db["motions"]]
(travel, tkey) = buildtravel(db["locations"], (travel, tkey) = buildtravel(db["locations"], db["objects"])
db["objects"])
ignore = "" ignore = ""
try: try:
with open(H_TEMPLATE_PATH, "r", encoding='ascii', errors='surrogateescape') as htf: with open(
H_TEMPLATE_PATH, "r", encoding="ascii", errors="surrogateescape"
) as htf:
# read in dungeon.h template # read in dungeon.h template
h_template = DONOTEDIT_COMMENT + htf.read() h_template = DONOTEDIT_COMMENT + htf.read()
with open(C_TEMPLATE_PATH, "r", encoding='ascii', errors='surrogateescape') as ctf: with open(
C_TEMPLATE_PATH, "r", encoding="ascii", errors="surrogateescape"
) as ctf:
# read in dungeon.c template # read in dungeon.c template
c_template = DONOTEDIT_COMMENT + ctf.read() c_template = DONOTEDIT_COMMENT + ctf.read()
except IOError as e: except IOError as e:
print('ERROR: reading template failed ({})'.format(e.strerror)) print("ERROR: reading template failed ({})".format(e.strerror))
sys.exit(-1) sys.exit(-1)
c = c_template.format( c = c_template.format(
@ -565,7 +625,7 @@ if __name__ == "__main__":
actions=get_actions(db["actions"]), actions=get_actions(db["actions"]),
tkeys=bigdump(tkey), tkeys=bigdump(tkey),
travel=get_travel(travel), travel=get_travel(travel),
ignore = ignore ignore=ignore,
) )
# 0-origin index of birds's last song. Bird should # 0-origin index of birds's last song. Bird should
@ -589,13 +649,13 @@ if __name__ == "__main__":
objects=get_refs(db["objects"]), objects=get_refs(db["objects"]),
motions=get_refs(db["motions"]), motions=get_refs(db["motions"]),
actions=get_refs(db["actions"]), actions=get_refs(db["actions"]),
state_definitions = statedefines state_definitions=statedefines,
) )
with open(H_NAME, "w", encoding='ascii', errors='surrogateescape') as hf: with open(H_NAME, "w", encoding="ascii", errors="surrogateescape") as hf:
hf.write(h) hf.write(h)
with open(C_NAME, "w", encoding='ascii', errors='surrogateescape') as cf: with open(C_NAME, "w", encoding="ascii", errors="surrogateescape") as cf:
cf.write(c) cf.write(c)
# end # end

View file

@ -18,28 +18,41 @@ Make a DOT graph of Colossal Cave.
import sys, getopt, yaml import sys, getopt, yaml
def allalike(loc): def allalike(loc):
"Select out loci related to the Maze All Alike" "Select out loci related to the Maze All Alike"
return location_lookup[loc]["conditions"].get("ALLALIKE") return location_lookup[loc]["conditions"].get("ALLALIKE")
def alldifferent(loc): def alldifferent(loc):
"Select out loci related to the Maze All Alike" "Select out loci related to the Maze All Alike"
return location_lookup[loc]["conditions"].get("ALLDIFFERENT") return location_lookup[loc]["conditions"].get("ALLDIFFERENT")
def surface(loc): def surface(loc):
"Select out surface locations" "Select out surface locations"
return location_lookup[loc]["conditions"].get("ABOVE") return location_lookup[loc]["conditions"].get("ABOVE")
def forest(loc): def forest(loc):
return location_lookup[loc]["conditions"].get("FOREST") return location_lookup[loc]["conditions"].get("FOREST")
def abbreviate(d): def abbreviate(d):
m = {"NORTH":"N", "EAST":"E", "SOUTH":"S", "WEST":"W", "UPWAR":"U", "DOWN":"D"} m = {
"NORTH": "N",
"EAST": "E",
"SOUTH": "S",
"WEST": "W",
"UPWAR": "U",
"DOWN": "D",
}
return m.get(d, d) return m.get(d, d)
def roomlabel(loc): def roomlabel(loc):
"Generate a room label from the description, if possible" "Generate a room label from the description, if possible"
loc_descriptions = location_lookup[loc]['description'] loc_descriptions = location_lookup[loc]["description"]
description = "" description = ""
if debug: if debug:
description = loc[4:] description = loc[4:]
@ -52,7 +65,11 @@ def roomlabel(loc):
short = short[7:] short = short[7:]
if short.startswith("You are "): if short.startswith("You are "):
short = short[8:] short = short[8:]
if short.startswith("in ") or short.startswith("at ") or short.startswith("on "): if (
short.startswith("in ")
or short.startswith("at ")
or short.startswith("on ")
):
short = short[3:] short = short[3:]
if short.startswith("the "): if short.startswith("the "):
short = short[4:] short = short[4:]
@ -69,6 +86,7 @@ def roomlabel(loc):
description += "\\n(" + ",".join(startlocs[loc]).lower() + ")" description += "\\n(" + ",".join(startlocs[loc]).lower() + ")"
return description return description
# A forwarder is a location that you can't actually stop in - when you go there # A forwarder is a location that you can't actually stop in - when you go there
# it ships some message (which is the point) then shifts you to a next location. # it ships some message (which is the point) then shifts you to a next location.
# A forwarder has a zero-length array of notion verbs in its travel section. # A forwarder has a zero-length array of notion verbs in its travel section.
@ -85,10 +103,12 @@ def roomlabel(loc):
# {verbs: [], action: [goto, LOC_NOWHERE]}, # {verbs: [], action: [goto, LOC_NOWHERE]},
# ] # ]
def is_forwarder(loc): def is_forwarder(loc):
"Is a location a forwarder?" "Is a location a forwarder?"
travel = location_lookup[loc]['travel'] travel = location_lookup[loc]["travel"]
return len(travel) == 1 and len(travel[0]['verbs']) == 0 return len(travel) == 1 and len(travel[0]["verbs"]) == 0
def forward(loc): def forward(loc):
"Chase a location through forwarding links." "Chase a location through forwarding links."
@ -96,6 +116,7 @@ def forward(loc):
loc = location_lookup[loc]["travel"][0]["action"][1] loc = location_lookup[loc]["travel"][0]["action"][1]
return loc return loc
def reveal(objname): def reveal(objname):
"Should this object be revealed when mapping?" "Should this object be revealed when mapping?"
if "OBJ_" in objname: if "OBJ_" in objname:
@ -105,8 +126,9 @@ def reveal(objname):
obj = object_lookup[objname] obj = object_lookup[objname]
return not obj.get("immovable") return not obj.get("immovable")
if __name__ == "__main__": if __name__ == "__main__":
with open("adventure.yaml", "r", encoding='ascii', errors='surrogateescape') as f: with open("adventure.yaml", "r", encoding="ascii", errors="surrogateescape") as f:
db = yaml.safe_load(f) db = yaml.safe_load(f)
location_lookup = dict(db["locations"]) location_lookup = dict(db["locations"])
@ -121,17 +143,17 @@ if __name__ == "__main__":
subset = allalike subset = allalike
debug = False debug = False
for (switch, val) in options: for (switch, val) in options:
if switch == '-a': if switch == "-a":
subset = lambda loc: True subset = lambda loc: True
elif switch == '-d': elif switch == "-d":
subset = alldifferent subset = alldifferent
elif switch == '-f': elif switch == "-f":
subset = forest subset = forest
elif switch == '-m': elif switch == "-m":
subset = allalike subset = allalike
elif switch == '-s': elif switch == "-s":
subset = surface subset = surface
elif switch == '-v': elif switch == "-v":
debug = True debug = True
else: else:
sys.stderr.write(__doc__) sys.stderr.write(__doc__)
@ -170,7 +192,7 @@ if __name__ == "__main__":
neighbors = set() neighbors = set()
for loc in nodes: for loc in nodes:
for (f, t) in links: for (f, t) in links:
if f == 'LOC_NOWHERE' or t == 'LOC_NOWHERE': if f == "LOC_NOWHERE" or t == "LOC_NOWHERE":
continue continue
if (f == loc and subset(t)) or (t == loc and subset(f)): if (f == loc and subset(t)) or (t == loc and subset(f)):
if loc not in neighbors: if loc not in neighbors:

View file

@ -29,42 +29,45 @@ DEFAULT_HTML_OUTPUT_PATH = "../coverage/adventure.yaml.html"
DANGLING_ACTIONS = ["ACT_VERSION"] DANGLING_ACTIONS = ["ACT_VERSION"]
DANGLING_MESSAGES = ["SAVERESUME_DISABLED"] DANGLING_MESSAGES = ["SAVERESUME_DISABLED"]
STDOUT_REPORT_CATEGORY = " {name:.<19}: {percent:5.1f}% covered ({covered} of {total})\n" STDOUT_REPORT_CATEGORY = (
" {name:.<19}: {percent:5.1f}% covered ({covered} of {total})\n"
)
HTML_SUMMARY_ROW = ''' HTML_SUMMARY_ROW = """
<tr> <tr>
<td class="headerItem"><a href="#{name}">{name}:</a></td> <td class="headerItem"><a href="#{name}">{name}:</a></td>
<td class="headerCovTableEntry">{total}</td> <td class="headerCovTableEntry">{total}</td>
<td class="headerCovTableEntry">{covered}</td> <td class="headerCovTableEntry">{covered}</td>
<td class="headerCovTableEntry">{percent:.1f}%</td> <td class="headerCovTableEntry">{percent:.1f}%</td>
</tr> </tr>
''' """
HTML_CATEGORY_SECTION = ''' HTML_CATEGORY_SECTION = """
<tr id="{id}"></tr> <tr id="{id}"></tr>
{rows} {rows}
<tr> <tr>
<td>&nbsp;</td> <td>&nbsp;</td>
</tr> </tr>
''' """
HTML_CATEGORY_HEADER = ''' HTML_CATEGORY_HEADER = """
<tr> <tr>
<td class="tableHead" width="60%" colspan="{colspan}">{label}</td> <td class="tableHead" width="60%" colspan="{colspan}">{label}</td>
{cells} {cells}
</tr> </tr>
''' """
HTML_CATEGORY_HEADER_CELL = '<td class="tableHead" width="15%">{}</td>\n' HTML_CATEGORY_HEADER_CELL = '<td class="tableHead" width="15%">{}</td>\n'
HTML_CATEGORY_COVERAGE_CELL = '<td class="{}">&nbsp;</td>\n' HTML_CATEGORY_COVERAGE_CELL = '<td class="{}">&nbsp;</td>\n'
HTML_CATEGORY_ROW = ''' HTML_CATEGORY_ROW = """
<tr> <tr>
<td class="coverFile" colspan="{colspan}">{id}</td> <td class="coverFile" colspan="{colspan}">{id}</td>
{cells} {cells}
</tr> </tr>
''' """
def search(needle, haystack): def search(needle, haystack):
# Search for needle in haystack, first escaping needle for regex, then # Search for needle in haystack, first escaping needle for regex, then
@ -75,16 +78,19 @@ def search(needle, haystack):
# if needle is empty, assume we're going to find an empty string # if needle is empty, assume we're going to find an empty string
return True return True
needle_san = re.escape(needle) \ needle_san = (
.replace("\\n", "\n") \ re.escape(needle)
.replace("\\t", "\t") \ .replace("\\n", "\n")
.replace("%S", ".*") \ .replace("\\t", "\t")
.replace("%s", ".*") \ .replace("%S", ".*")
.replace("%d", ".*") \ .replace("%s", ".*")
.replace("%d", ".*")
.replace("%V", ".*") .replace("%V", ".*")
)
return re.search(needle_san, haystack) return re.search(needle_san, haystack)
def obj_coverage(objects, text, report): def obj_coverage(objects, text, report):
# objects have multiple descriptions based on state # objects have multiple descriptions based on state
for _, objouter in enumerate(objects): for _, objouter in enumerate(objects):
@ -99,6 +105,7 @@ def obj_coverage(objects, text, report):
report["messages"][name]["covered"] = True report["messages"][name]["covered"] = True
report["covered"] += 1 report["covered"] += 1
def loc_coverage(locations, text, report): def loc_coverage(locations, text, report):
# locations have a long and a short description, that each have to # locations have a long and a short description, that each have to
# be checked separately # be checked separately
@ -114,6 +121,7 @@ def loc_coverage(locations, text, report):
report["messages"][name]["short"] = True report["messages"][name]["short"] = True
report["covered"] += 1 report["covered"] += 1
def hint_coverage(obituaries, text, report): def hint_coverage(obituaries, text, report):
# hints have a "question" where the hint is offered, followed # hints have a "question" where the hint is offered, followed
# by the actual hint if the player requests it # by the actual hint if the player requests it
@ -130,6 +138,7 @@ def hint_coverage(obituaries, text, report):
report["messages"][name]["hint"] = True report["messages"][name]["hint"] = True
report["covered"] += 1 report["covered"] += 1
def obit_coverage(obituaries, text, report): def obit_coverage(obituaries, text, report):
# obituaries have a "query" where it asks the player for a resurrection, # obituaries have a "query" where it asks the player for a resurrection,
# followed by a snarky comment if the player says yes # followed by a snarky comment if the player says yes
@ -140,10 +149,13 @@ def obit_coverage(obituaries, text, report):
if not report["messages"][name]["query"] and search(obit["query"], text): if not report["messages"][name]["query"] and search(obit["query"], text):
report["messages"][name]["query"] = True report["messages"][name]["query"] = True
report["covered"] += 1 report["covered"] += 1
if not report["messages"][name]["yes_response"] and search(obit["yes_response"], text): if not report["messages"][name]["yes_response"] and search(
obit["yes_response"], text
):
report["messages"][name]["yes_response"] = True report["messages"][name]["yes_response"] = True
report["covered"] += 1 report["covered"] += 1
def threshold_coverage(classes, text, report): def threshold_coverage(classes, text, report):
# works for class thresholds and turn threshold, which have a "message" # works for class thresholds and turn threshold, which have a "message"
# property # property
@ -155,25 +167,32 @@ def threshold_coverage(classes, text, report):
report["messages"][name]["covered"] = True report["messages"][name]["covered"] = True
report["covered"] += 1 report["covered"] += 1
def arb_coverage(arb_msgs, text, report): def arb_coverage(arb_msgs, text, report):
for name, message in arb_msgs: for name, message in arb_msgs:
if name not in report["messages"]: if name not in report["messages"]:
report["messages"][name] = {"covered": False} report["messages"][name] = {"covered": False}
report["total"] += 1 report["total"] += 1
if not report["messages"][name]["covered"] and (search(message, text) or name in DANGLING_MESSAGES): if not report["messages"][name]["covered"] and (
search(message, text) or name in DANGLING_MESSAGES
):
report["messages"][name]["covered"] = True report["messages"][name]["covered"] = True
report["covered"] += 1 report["covered"] += 1
def actions_coverage(items, text, report): def actions_coverage(items, text, report):
# works for actions # works for actions
for name, item in items: for name, item in items:
if name not in report["messages"]: if name not in report["messages"]:
report["messages"][name] = {"covered": False} report["messages"][name] = {"covered": False}
report["total"] += 1 report["total"] += 1
if not report["messages"][name]["covered"] and (search(item["message"], text) or name in DANGLING_ACTIONS): if not report["messages"][name]["covered"] and (
search(item["message"], text) or name in DANGLING_ACTIONS
):
report["messages"][name]["covered"] = True report["messages"][name]["covered"] = True
report["covered"] += 1 report["covered"] += 1
def coverage_report(db, check_file_contents): def coverage_report(db, check_file_contents):
# Create report for each category, including total items, number of items # Create report for each category, including total items, number of items
# covered, and a list of the covered messages # covered, and a list of the covered messages
@ -184,7 +203,7 @@ def coverage_report(db, check_file_contents):
"name": name, # convenience for string formatting "name": name, # convenience for string formatting
"total": 0, "total": 0,
"covered": 0, "covered": 0,
"messages" : {} "messages": {},
} }
# search for each message in every test check file # search for each message in every test check file
@ -200,20 +219,21 @@ def coverage_report(db, check_file_contents):
return report return report
if __name__ == "__main__": if __name__ == "__main__":
# load DB # load DB
try: try:
with open(YAML_PATH, "r", encoding='ascii', errors='surrogateescape') as f: with open(YAML_PATH, "r", encoding="ascii", errors="surrogateescape") as f:
db = yaml.safe_load(f) db = yaml.safe_load(f)
except IOError as e: except IOError as e:
print('ERROR: could not load %s (%s)' % (YAML_PATH, e.strerror)) print("ERROR: could not load %s (%s)" % (YAML_PATH, e.strerror))
sys.exit(-1) sys.exit(-1)
# get contents of all the check files # get contents of all the check files
check_file_contents = [] check_file_contents = []
for filename in os.listdir(TEST_DIR): for filename in os.listdir(TEST_DIR):
if filename.endswith(".chk"): if filename.endswith(".chk"):
with open(filename, "r", encoding='ascii', errors='surrogateescape') as f: with open(filename, "r", encoding="ascii", errors="surrogateescape") as f:
check_file_contents.append(f.read()) check_file_contents.append(f.read())
# run coverage analysis report on dungeon database # run coverage analysis report on dungeon database
@ -236,14 +256,20 @@ if __name__ == "__main__":
colspan = 10 - len(cat_keys) colspan = 10 - len(cat_keys)
for key in cat_keys: for key in cat_keys:
headers_html += HTML_CATEGORY_HEADER_CELL.format(key) headers_html += HTML_CATEGORY_HEADER_CELL.format(key)
category_html = HTML_CATEGORY_HEADER.format(colspan=colspan, label=category["name"], cells=headers_html) category_html = HTML_CATEGORY_HEADER.format(
colspan=colspan, label=category["name"], cells=headers_html
)
# render message coverage row # render message coverage row
for message_id, covered in cat_messages: for message_id, covered in cat_messages:
category_html_row = "" category_html_row = ""
for key, value in covered.items(): for key, value in covered.items():
category_html_row += HTML_CATEGORY_COVERAGE_CELL.format("uncovered" if not value else "covered") category_html_row += HTML_CATEGORY_COVERAGE_CELL.format(
category_html += HTML_CATEGORY_ROW.format(id=message_id,colspan=colspan, cells=category_html_row) "uncovered" if not value else "covered"
)
category_html += HTML_CATEGORY_ROW.format(
id=message_id, colspan=colspan, cells=category_html_row
)
categories_html += HTML_CATEGORY_SECTION.format(id=name, rows=category_html) categories_html += HTML_CATEGORY_SECTION.format(id=name, rows=category_html)
# render category summaries # render category summaries
@ -260,16 +286,22 @@ if __name__ == "__main__":
# render HTML report # render HTML report
try: try:
with open(HTML_TEMPLATE_PATH, "r", encoding='ascii', errors='surrogateescape') as f: with open(
HTML_TEMPLATE_PATH, "r", encoding="ascii", errors="surrogateescape"
) as f:
# read in HTML template # read in HTML template
html_template = f.read() html_template = f.read()
except IOError as e: except IOError as e:
print('ERROR: reading HTML report template failed ({})'.format(e.strerror)) print("ERROR: reading HTML report template failed ({})".format(e.strerror))
sys.exit(-1) sys.exit(-1)
# parse template with report and write it out # parse template with report and write it out
try: try:
with open(html_output_path, "w", encoding='ascii', errors='surrogateescape') as f: with open(
f.write(html_template.format(categories=categories_html, summary=summary_html)) html_output_path, "w", encoding="ascii", errors="surrogateescape"
) as f:
f.write(
html_template.format(categories=categories_html, summary=summary_html)
)
except IOError as e: except IOError as e:
print('ERROR: writing HTML report failed ({})'.format(e.strerror)) print("ERROR: writing HTML report failed ({})".format(e.strerror))