Define TypeTable and TypeTableRow classes
Hopefully this will make it a bit easier to understand what's going on.
This commit is contained in:
parent
caf1333d12
commit
96650e2824
4 changed files with 125 additions and 91 deletions
|
@ -12,11 +12,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Parent class for writing units."""
|
||||
from . import AccessKeyStore
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
class Units(object):
|
||||
|
||||
|
@ -57,9 +54,6 @@ class Units(object):
|
|||
unit_dict[unit_key] = func(self.substitutions)
|
||||
else:
|
||||
unit_dict[unit_key] = func()
|
||||
self.log("Generated unit '%s' : %s" % (
|
||||
unit_key, json.dumps(unit_dict[unit_key])[:50].replace(
|
||||
"\n",""
|
||||
)
|
||||
))
|
||||
self.log("Generated unit '%s'" % unit_key)
|
||||
|
||||
return unit_dict
|
||||
|
|
|
@ -59,10 +59,12 @@ import importlib
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from textwrap import TextWrapper
|
||||
|
||||
from matrix_templates.units import TypeTableRow
|
||||
|
||||
|
||||
def create_from_template(template, sections):
|
||||
return template.render(sections)
|
||||
|
||||
|
@ -117,15 +119,23 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={}
|
|||
Given a list of rows, returns a list giving the maximum length of the
|
||||
values in each column.
|
||||
|
||||
:param list[dict[str, str]] input: a list of rows. Each row should be a
|
||||
dict with the keys given in ``keys``.
|
||||
:param list[TypeTableRow|dict[str,str]] input:
|
||||
a list of rows
|
||||
:param list[str] keys: the keys corresponding to the table columns
|
||||
:param list[int] defaults: for each column, the default column width.
|
||||
:param int default_width: if ``defaults`` is shorter than ``keys``, this
|
||||
will be used as a fallback
|
||||
"""
|
||||
def getrowattribute(row, k):
|
||||
# the row may be a dict (particularly the title row, which is
|
||||
# generated by the template
|
||||
if not isinstance(row, TypeTableRow):
|
||||
return row[k]
|
||||
return getattr(row, k)
|
||||
|
||||
def colwidth(key, default):
|
||||
return reduce(max, (len(row[key]) for row in input),
|
||||
rowwidths = (len(getrowattribute(row, key)) for row in input)
|
||||
return reduce(max, rowwidths,
|
||||
default if default is not None else default_width)
|
||||
|
||||
results = map(colwidth, keys, defaults)
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
{#
|
||||
# write a table for a list of parameters.
|
||||
#
|
||||
# 'rows' is the list of parameters. Each row should have the keys
|
||||
# 'key', 'type', and 'desc'.
|
||||
# 'rows' is the list of parameters. Each row should be a TypeTableRow.
|
||||
#}
|
||||
{% macro paramtable(rows, titles=["Parameter", "Type", "Description"]) -%}
|
||||
{{ split_paramtable({None: rows}, titles) }}
|
||||
|
|
|
@ -62,6 +62,50 @@ OrderedLoader.add_constructor(
|
|||
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
||||
construct_mapping)
|
||||
|
||||
|
||||
class TypeTable(object):
|
||||
"""Describes a table documenting an object type
|
||||
|
||||
Attributes:
|
||||
title(str|None): Title of the table - normally the object type
|
||||
desc(str|None): description of the object
|
||||
rows(list[TypeTableRow]): the rows in the table
|
||||
"""
|
||||
def __init__(self, title=None, desc=None, rows=[]):
|
||||
self.title=title
|
||||
self.desc=desc
|
||||
self._rows = []
|
||||
for row in rows:
|
||||
self.add_row(row)
|
||||
|
||||
def add_row(self, row):
|
||||
if not isinstance(row, TypeTableRow):
|
||||
raise ValueError("Can only add TypeTableRows to TypeTable")
|
||||
|
||||
self._rows.append(row)
|
||||
|
||||
def __getattr__(self, item):
|
||||
if item == 'rows':
|
||||
return list(self._rows)
|
||||
return super(TypeTable, self).__getattr__(item)
|
||||
|
||||
def __repr__(self):
|
||||
return "TypeTable[%s, rows=%s]" % (self.title, self._rows)
|
||||
|
||||
|
||||
class TypeTableRow(object):
|
||||
"""Describes an object field defined in the json schema
|
||||
"""
|
||||
def __init__(self, key, typ, desc, required=False):
|
||||
self.key = key
|
||||
self.type = typ
|
||||
self.desc = desc
|
||||
self.required = required
|
||||
|
||||
def __repr__(self):
|
||||
return "TypeTableRow[%s: %s]" % (self.key, self.desc)
|
||||
|
||||
|
||||
def resolve_references(path, schema):
|
||||
if isinstance(schema, dict):
|
||||
# do $ref first
|
||||
|
@ -171,12 +215,12 @@ def get_json_schema_object_fields(obj, enforce_title=False):
|
|||
required = key_name in required_keys
|
||||
res = process_data_type(props[key_name], required)
|
||||
|
||||
first_table_rows.append({
|
||||
"key": key_name,
|
||||
"type": res["type"],
|
||||
"required": required,
|
||||
"desc": res["desc"],
|
||||
})
|
||||
first_table_rows.append(TypeTableRow(
|
||||
key=key_name,
|
||||
typ=res["type"],
|
||||
required=required,
|
||||
desc=res["desc"],
|
||||
))
|
||||
tables.extend(res["tables"])
|
||||
logger.debug("Done property %s" % key_name)
|
||||
|
||||
|
@ -187,10 +231,10 @@ def get_json_schema_object_fields(obj, enforce_title=False):
|
|||
# we don't lose information about where the error occurred.
|
||||
raise e2, None, sys.exc_info()[2]
|
||||
|
||||
tables.insert(0, {
|
||||
"title": obj_title,
|
||||
"rows": first_table_rows,
|
||||
})
|
||||
tables.insert(0, TypeTable(title=obj_title, rows=first_table_rows))
|
||||
|
||||
for table in tables:
|
||||
assert isinstance(table, TypeTable)
|
||||
|
||||
return {
|
||||
"type": obj_title,
|
||||
|
@ -241,10 +285,12 @@ def process_data_type(prop, required=False, enforce_title=True):
|
|||
if isinstance(prop_type, list):
|
||||
prop_type = " or ".join(prop_type)
|
||||
|
||||
|
||||
rq = "**Required.**" if required else None
|
||||
desc = " ".join(x for x in [rq, prop.get("description"), enum_desc] if x)
|
||||
|
||||
for table in tables:
|
||||
assert isinstance(table, TypeTable)
|
||||
|
||||
return {
|
||||
"type": prop_type,
|
||||
"desc": desc,
|
||||
|
@ -263,13 +309,10 @@ def deduplicate_tables(tables):
|
|||
titles = set()
|
||||
filtered = []
|
||||
for table in reversed(tables):
|
||||
if table.get("no-table"):
|
||||
if table.title in titles:
|
||||
continue
|
||||
|
||||
if table.get("title") in titles:
|
||||
continue
|
||||
|
||||
titles.add(table.get("title"))
|
||||
titles.add(table.title)
|
||||
filtered.append(table)
|
||||
filtered.reverse()
|
||||
|
||||
|
@ -286,14 +329,10 @@ def get_tables_for_response(schema):
|
|||
# make up the first table, with just the 'body' row in, unless the response
|
||||
# is an object, in which case there's little point in having one.
|
||||
if not pv["is_object"]:
|
||||
tables = [{
|
||||
"title": None,
|
||||
"rows": [{
|
||||
"key": "<body>",
|
||||
"type": pv["type"],
|
||||
"desc": pv["desc"],
|
||||
}]
|
||||
}] + tables
|
||||
first_table_row = TypeTableRow(
|
||||
key="<body>", typ=pv["type"], desc=pv["desc"],
|
||||
)
|
||||
tables.insert(0, TypeTable(None, rows=[first_table_row]))
|
||||
|
||||
logger.debug("response: %r" % tables)
|
||||
|
||||
|
@ -440,11 +479,9 @@ class MatrixUnits(Units):
|
|||
" One of: %s" % json.dumps(param.get("enum"))
|
||||
)
|
||||
|
||||
endpoint["req_param_by_loc"].setdefault(param_loc, []).append({
|
||||
"key": param_name,
|
||||
"type": val_type,
|
||||
"desc": desc
|
||||
})
|
||||
endpoint["req_param_by_loc"].setdefault(param_loc, []).append(
|
||||
TypeTableRow(key=param_name, typ=val_type, desc=desc),
|
||||
)
|
||||
|
||||
example = get_example_for_param(param)
|
||||
if example is None:
|
||||
|
@ -487,11 +524,10 @@ class MatrixUnits(Units):
|
|||
headers = []
|
||||
for (header_name, header) in good_response[
|
||||
"headers"].iteritems():
|
||||
headers.append({
|
||||
"key": header_name,
|
||||
"type": header["type"],
|
||||
"desc": header["description"],
|
||||
})
|
||||
headers.append(
|
||||
TypeTableRow(key=header_name, typ=header["type"],
|
||||
desc=header["description"]),
|
||||
)
|
||||
endpoint["res_headers"] = headers
|
||||
query_string = "" if len(
|
||||
example_query_params) == 0 else "?" + urllib.urlencode(
|
||||
|
@ -531,7 +567,7 @@ class MatrixUnits(Units):
|
|||
# put the top-level parameters into 'req_param_by_loc', and the others
|
||||
# into 'req_body_tables'
|
||||
body_params = endpoint_data['req_param_by_loc'].setdefault("JSON body",[])
|
||||
body_params.extend(req_body_tables[0]["rows"])
|
||||
body_params.extend(req_body_tables[0].rows)
|
||||
|
||||
body_tables = req_body_tables[1:]
|
||||
endpoint_data['req_body_tables'].extend(body_tables)
|
||||
|
@ -586,19 +622,18 @@ class MatrixUnits(Units):
|
|||
if "event" not in event_type:
|
||||
continue # filter ImageInfo and co
|
||||
|
||||
table = {
|
||||
"title": event_info["title"],
|
||||
"desc": event_info["description"],
|
||||
"rows": []
|
||||
}
|
||||
table = TypeTable(
|
||||
title=event_info["title"],
|
||||
desc=event_info["description"],
|
||||
)
|
||||
|
||||
for prop in sorted(event_info["properties"]):
|
||||
row = {
|
||||
"key": prop,
|
||||
"type": event_info["properties"][prop]["type"],
|
||||
"desc": event_info["properties"][prop].get("description","")
|
||||
}
|
||||
table["rows"].append(row)
|
||||
prop_info = event_info["properties"][prop]
|
||||
table.add_row(TypeTableRow(
|
||||
key=prop,
|
||||
typ=prop_info["type"],
|
||||
desc=prop_info.get("description", ""),
|
||||
))
|
||||
|
||||
event_types[event_type] = table
|
||||
return event_types
|
||||
|
@ -606,29 +641,31 @@ class MatrixUnits(Units):
|
|||
def load_apis(self, substitutions):
|
||||
cs_ver = substitutions.get("%CLIENT_RELEASE_LABEL%", "unstable")
|
||||
fed_ver = substitutions.get("%SERVER_RELEASE_LABEL%", "unstable")
|
||||
return {
|
||||
"rows": [{
|
||||
"key": "`Client-Server API <client_server/"+cs_ver+".html>`_",
|
||||
"type": cs_ver,
|
||||
"desc": "Interaction between clients and servers",
|
||||
}, {
|
||||
"key": "`Server-Server API <server_server/"+fed_ver+".html>`_",
|
||||
"type": fed_ver,
|
||||
"desc": "Federation between servers",
|
||||
}, {
|
||||
"key": "`Application Service API <application_service/unstable.html>`_",
|
||||
"type": "unstable",
|
||||
"desc": "Privileged server plugins",
|
||||
}, {
|
||||
"key": "`Identity Service API <identity_service/unstable.html>`_",
|
||||
"type": "unstable",
|
||||
"desc": "Mapping of third party IDs to Matrix IDs",
|
||||
}, {
|
||||
"key": "`Push Gateway API <push_gateway/unstable.html>`_",
|
||||
"type": "unstable",
|
||||
"desc": "Push notifications for Matrix events",
|
||||
}]
|
||||
}
|
||||
|
||||
# we abuse the typetable to return this info to the templates
|
||||
return TypeTable(rows=[
|
||||
TypeTableRow(
|
||||
"`Client-Server API <client_server/"+cs_ver+".html>`_",
|
||||
cs_ver,
|
||||
"Interaction between clients and servers",
|
||||
), TypeTableRow(
|
||||
"`Server-Server API <server_server/"+fed_ver+".html>`_",
|
||||
fed_ver,
|
||||
"Federation between servers",
|
||||
), TypeTableRow(
|
||||
"`Application Service API <application_service/unstable.html>`_",
|
||||
"unstable",
|
||||
"Privileged server plugins",
|
||||
), TypeTableRow(
|
||||
"`Identity Service API <identity_service/unstable.html>`_",
|
||||
"unstable",
|
||||
"Mapping of third party IDs to Matrix IDs",
|
||||
), TypeTableRow(
|
||||
"`Push Gateway API <push_gateway/unstable.html>`_",
|
||||
"unstable",
|
||||
"Push notifications for Matrix events",
|
||||
),
|
||||
])
|
||||
|
||||
def load_event_examples(self):
|
||||
path = EVENT_EXAMPLES
|
||||
|
@ -680,13 +717,7 @@ class MatrixUnits(Units):
|
|||
"desc": None,
|
||||
"msgtype": None,
|
||||
"content_fields": [
|
||||
# {
|
||||
# title: "<title> key"
|
||||
# rows: [
|
||||
# { key: <key_name>, type: <string>,
|
||||
# desc: <desc>, required: <bool> }
|
||||
# ]
|
||||
# }
|
||||
# <TypeTable>
|
||||
]
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue