Skip to content

Commit

Permalink
pre and post return value notes
Browse files Browse the repository at this point in the history
  • Loading branch information
ShahanaFarooqui committed Dec 12, 2023
1 parent 55a68b8 commit f6d1614
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 83 deletions.
167 changes: 86 additions & 81 deletions tools/fromschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,94 +187,91 @@ def has_members(sub):
def output_members(sub, indent=""):
"""Generate lines for these properties"""
warnings = []
if "properties" not in sub:
if "additionalProperties" in sub:
return
elif "oneOf" in sub:
for oneOfItem in sub["oneOf"]:
if "type" in oneOfItem and oneOfItem["type"] == "object":
output_member(None, oneOfItem, False, indent, prefix="-")
elif "type" in oneOfItem and oneOfItem["type"] == "array":
output_array(oneOfItem, indent)
elif "type" in oneOfItem and oneOfItem["type"] == "string":
output(indent + "- ")
output_range(oneOfItem, False)
output("\n")
else:
# If we have multiple ifs, we have to wrap them in allOf.
if "allOf" in sub:
ifclauses = sub["allOf"]
elif "if" in sub:
ifclauses = [sub]
else:
ifclauses = []
# Remove deprecated: True and stub properties, collect warnings
# (Stubs required to keep additionalProperties: false happy)

# FIXME: It fails for schemas which have only an array type with
# no properties, ex:
# "abcd": {
# "type": "array",
# "items": {
# "type": "whatever",
# "description": "efgh"
# }
# }
# Checkout the schema of `staticbackup`.
for p in list(sub["properties"].keys()):
if len(sub["properties"][p]) == 0 or sub["properties"][p].get("deprecated") is True:
del sub["properties"][p]
elif p.startswith("warning"):
warnings.append(p)

# First list always-present properties
for p in sub["properties"]:
if p.startswith("warning"):
continue
if "required" in sub and p in sub["required"]:
output_member(p, sub["properties"][p], False, indent)

# We partially handle if, assuming it depends on particular values of prior properties.
for ifclause in ifclauses:
conditions = []
for p in sub["properties"]:
if p.startswith("warning"):
continue
if "required" not in sub or p not in sub["required"]:
output_member(p, sub["properties"][p], True, indent)

if warnings != []:
output(indent + "- the following warnings are possible:\n")
for w in warnings:
output_member(w, sub["properties"][w], False, indent + " ", print_type=False)

if "oneOf" in sub:
for oneOfItem in sub["oneOf"]:
if "type" in oneOfItem and oneOfItem["type"] == "object":
output_member(None, oneOfItem, False, indent, "-")
elif "type" in oneOfItem and oneOfItem["type"] == "array":
output_array(oneOfItem, indent)
elif "type" in oneOfItem and oneOfItem["type"] == "string":
output(indent + "- ")
output_range(oneOfItem, False)
output("\n")

# If we have multiple ifs, we have to wrap them in allOf.
if "allOf" in sub:
ifclauses = sub["allOf"]
elif "if" in sub:
ifclauses = [sub]
else:
ifclauses = []

# "required" are fields that simply must be present
for r in ifclause["if"].get("required", []):
conditions.append(fmt_propname(r) + " is present")
# We partially handle if, assuming it depends on particular values of prior properties.
for ifclause in ifclauses:
conditions = []

# "properties" are enums of field values
for tag, vals in ifclause["if"].get("properties", {}).items():
# Don"t have a description field here, it"s not used.
assert "description" not in vals
whichvalues = vals["enum"]
# "required" are fields that simply must be present
for r in ifclause["if"].get("required", []):
conditions.append(fmt_propname(r) + " is present")

cond = fmt_propname(tag) + " is"
if len(whichvalues) == 1:
cond += " {}".format(json_value(whichvalues[0]))
else:
cond += " {} or {}".format(", ".join([json_value(v) for v in whichvalues[:-1]]),
json_value(whichvalues[-1]))
conditions.append(cond)
# "properties" are enums of field values
for tag, vals in ifclause["if"].get("properties", {}).items():
# Don"t have a description field here, it"s not used.
assert "description" not in vals
whichvalues = vals["enum"]

sentence = indent + "If " + ", and ".join(conditions) + ":\n\n"
cond = fmt_propname(tag) + " is"
if len(whichvalues) == 1:
cond += " {}".format(json_value(whichvalues[0]))
else:
cond += " {} or {}".format(", ".join([json_value(v) for v in whichvalues[:-1]]),
json_value(whichvalues[-1]))
conditions.append(cond)

if has_members(ifclause["then"]):
# Prefix with blank line.
outputs(["\n", sentence])
sentence = indent + "If " + ", and ".join(conditions) + ":\n"

output_members(ifclause["then"], indent + " ")
else:
# Remove deprecated: True and stub properties, collect warnings
# (Stubs required to keep additionalProperties: false happy)

# FIXME: It fails for schemas which have only an array type with
# no properties, ex:
# "abcd": {
# "type": "array",
# "items": {
# "type": "whatever",
# "description": "efgh"
# }
# }
# Checkout the schema of `staticbackup`.
for p in list(sub["properties"].keys()):
if len(sub["properties"][p]) == 0 or sub["properties"][p].get("deprecated") is True:
del sub["properties"][p]
elif p.startswith("warning"):
warnings.append(p)

# First list always-present properties
for p in sub["properties"]:
if p.startswith("warning"):
continue
if "required" in sub and p in sub["required"]:
output_member(p, sub["properties"][p], False, indent)

for p in sub["properties"]:
if p.startswith("warning"):
continue
if "required" not in sub or p not in sub["required"]:
output_member(p, sub["properties"][p], True, indent)

if warnings != []:
output(indent + "- the following warnings are possible:\n")
for w in warnings:
output_member(w, sub["properties"][w], False, indent + " ", print_type=False)
if has_members(ifclause["then"]):
# Prefix with blank line.
outputs(["\n", sentence])
output_members(ifclause["then"], indent + " ")
output("\n")


def output_params(schema):
Expand Down Expand Up @@ -316,6 +313,11 @@ def generate_from_request(schema):
def generate_from_response(schema):
"""This is not general, but works for us"""
output_title("RETURN VALUE")

if "pre_return_value_notes" in schema["response"]:
outputs(schema["response"]["pre_return_value_notes"], "\n")
output("\n\n")

if schema["type"] != "object":
# "stop" returns a single string!
output_member(None, schema, False, "", prefix="On success, returns a single element")
Expand Down Expand Up @@ -354,6 +356,9 @@ def generate_from_response(schema):

output_members(sub)

if "post_return_value_notes" in schema["response"]:
outputs(schema["response"]["post_return_value_notes"], "\n")

if warnings:
outputs(["\n", "The following warnings may also be returned:\n\n"])
for w, desc in warnings:
Expand Down
22 changes: 20 additions & 2 deletions tools/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
if base_name not in grouped_files:
grouped_files.append(base_name)

grouped_files = ['autoclean-status']
# Merge and create new JSON files
for base_name in grouped_files:
if not os.path.exists(input_folder + "lightning-" + base_name + ".7.md"):
Expand Down Expand Up @@ -63,12 +64,29 @@
merged_json["title"] = title.strip("\n")
else:
title_line = md_file_contents[i - 1].strip("\n")
if line.startswith("----") and not (title_line.startswith("SYNOPSIS") or title_line.startswith("RETURN VALUE")):
if line.startswith("----") and not (title_line.startswith("SYNOPSIS")):
for j in range(i+2, len(md_file_contents)):
if md_file_contents[j].startswith("----"):
title_line_end = j - 2
break
if title_line.startswith("DESCRIPTION") or title_line.startswith("EXAMPLE JSON REQUEST"):
if title_line.startswith("RETURN VALUE"):
for j in range(i+2, len(md_file_contents)):
if md_file_contents[j].startswith("[comment]: # (GENERATE-FROM-SCHEMA-START)"):
pre_notes_end = j - 1
break
pre_return_value_notes = md_file_contents[i+2:pre_notes_end]
for k in range(j, len(md_file_contents)):
if md_file_contents[k].startswith("[comment]: # (GENERATE-FROM-SCHEMA-END)"):
post_notes_start = k + 2
if md_file_contents[k].startswith("----"):
post_notes_end = k - 2
break
post_return_value_notes = md_file_contents[post_notes_start:post_notes_end]
if len(pre_return_value_notes) > 0:
response_json["pre_return_value_notes"] = pre_return_value_notes
if len(post_return_value_notes) > 0:
response_json["post_return_value_notes"] = post_return_value_notes
elif title_line.startswith("DESCRIPTION") or title_line.startswith("EXAMPLE JSON REQUEST"):
request_json[title_line.lower().replace(" ", "_")] = md_file_contents[i+2:title_line_end]
merged_json["request"] = request_json
merged_json["response"] = response_json
Expand Down

0 comments on commit f6d1614

Please sign in to comment.