Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fastspec/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
'fastspec.oapi.OpenAPIClient.full_docs': ('oapi.html#openapiclient.full_docs', 'fastspec/oapi.py'),
'fastspec.oapi.SyncOpFunc': ('oapi.html#syncopfunc', 'fastspec/oapi.py'),
'fastspec.oapi.SyncOpFunc.__call__': ('oapi.html#syncopfunc.__call__', 'fastspec/oapi.py'),
'fastspec.oapi._examples_doc': ('oapi.html#_examples_doc', 'fastspec/oapi.py'),
'fastspec.oapi._join_url': ('oapi.html#_join_url', 'fastspec/oapi.py'),
'fastspec.oapi._path': ('oapi.html#_path', 'fastspec/oapi.py')},
'fastspec.spec': { 'fastspec.spec.OpSpec': ('spec.html#opspec', 'fastspec/spec.py'),
Expand Down
7 changes: 6 additions & 1 deletion fastspec/oapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@


# %% ../nbs/04_oapi.ipynb #6b2f1057
def _examples_doc(exs):
"Render body examples as an `Examples:` doc section, one fenced JSON block per example"
if not exs: return ''
return '\n\nExamples:' + ''.join(f"\n- {v.get('summary') or k}:\n```json\n{json.dumps(v['value'], indent=2)}\n```" for k,v in exs.items())

class OpFunc:
def __init__(self, op_spec, client, base_url, form_encoder=None, defaults=None):
store_attr()
Expand All @@ -40,7 +45,7 @@ def __init__(self, op_spec, client, base_url, form_encoder=None, defaults=None):
self.required_params = op_spec.required_params
self.param_docs = op_spec.param_docs
self.__signature__ = mk_sig(op_spec, self.sparams, self.defaults)
self.__doc__ = mk_doc(self, self.__signature__, self.sparams)
self.__doc__ = mk_doc(self, self.__signature__, self.sparams) + _examples_doc(op_spec.body_examples)

def _repr_markdown_(self): return self.__doc__
def __repr__(self): return f"{'.'.join(snake(g) for g in listify(self.group))}.{self.name}{self.__signature__}\n{self.docs_url}"
Expand Down
14 changes: 9 additions & 5 deletions fastspec/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ class OpSpec:
param_types: Dict = field(default_factory=dict)
param_defaults: Dict = field(default_factory=dict)
param_docs: Dict = field(default_factory=dict)
body_examples: Dict = field(default_factory=dict)
docs_url: str = ""

def mk_doc(self):
rows = []
for f,v in vars(self).items():
if f not in ('param_types','param_defaults','param_docs'): rows.append(f'| `{f}` | {v} |')
if f not in ('param_types','param_defaults','param_docs','body_examples'): rows.append(f'| `{f}` | {v} |')
md = f'| Field | Value |\n|---|---|\n' + '\n'.join(rows)
all_params = self.route_params + self.query_params + self.body_params
if all_params:
Expand Down Expand Up @@ -197,10 +198,13 @@ def _body_params(op, spec):
rb = _resolve_obj(op.get("requestBody", {}), spec)
content = rb.get("content", {})
ct = first((ct for ct in ctypes if ct in content), None)
schema = content.get(ct, {}).get("schema") if ct else None
mt = content.get(ct) or {}
schema = mt.get("schema")
exs = mt.get("examples") or ({"default": {"value": mt["example"]}} if "example" in mt else {})
bexs = {k: {"summary": r.get("summary",""), "value": r["value"]} for k,v in exs.items() if "value" in (r := _resolve_obj(v, spec))}
if not schema:
return AttrDict(body_params=[], file_params=[], required_params=set(), param_types={},
param_docs={}, param_defaults={}, request_content_type=ct)
param_docs={}, param_defaults={}, request_content_type=ct, body_examples=bexs)
props, req = _schema_props_required(schema, spec)
fparams = [k for k,v in props.items() if _resolve_obj(v, spec).get("format") == "binary"]
bparams = [k for k in props if k not in fparams]
Expand All @@ -210,7 +214,7 @@ def _body_params(op, spec):
# Params without a default or nullable type are required
# req |= {k for k in props if k not in defaults} # too aggressive doesn't match when spec is incomplete
return AttrDict(body_params=bparams, file_params=fparams, required_params=req, param_types=ptypes,
param_docs=pdocs, param_defaults=defaults, request_content_type=ct)
param_docs=pdocs, param_defaults=defaults, request_content_type=ct, body_examples=bexs)

# %% ../nbs/03_spec.ipynb #9ab326f7
_pat_md_url = re.compile(r"\[[^\]]+\]\((https?://[^)\s]+)\)")
Expand Down Expand Up @@ -268,7 +272,7 @@ def openapi_to_ops(spec, group_func=None):
required_params=sorted(pdict.required_params | bpdict.required_params),
param_types={k:v for k,v in merge(pdict.param_types, bpdict.param_types).items() if v},
param_defaults=_plain(merge(pdict.param_defaults, bpdict.param_defaults)), param_docs=merge(pdict.param_docs, bpdict.param_docs),
docs_url=_op_docs_url(op) or ""))
docs_url=_op_docs_url(op) or "", body_examples=_plain(bpdict.body_examples)))
return res

# %% ../nbs/03_spec.ipynb #78ea6617
Expand Down
Loading