async def docStormTypes(): registry = s_stormtypes.registry libsinfo = registry.getLibDocs() libspage = s_autodoc.RstHelp() libspage.addHead('Storm Libraries', lvl=0, link='.. _stormtypes-libs-header:') lines = ( '', 'Storm Libraries represent powerful tools available inside of the Storm query language.', '') libspage.addLines(*lines) s_autodoc.docStormTypes(libspage, libsinfo, linkprefix='stormlibs', islib=True) priminfo = registry.getTypeDocs() typespage = s_autodoc.RstHelp() typespage.addHead('Storm Types', lvl=0, link='.. _stormtypes-prim-header:') lines = ( '', 'Storm Objects are used as view objects for manipulating data in the Storm Runtime and in the Cortex itself.' '') typespage.addLines(*lines) s_autodoc.docStormTypes(typespage, priminfo, linkprefix='stormprims') return libspage, typespage
async def docModel(outp, core): coreinfo = await core.getCoreInfo() _, model = coreinfo.get('modeldef')[0] ctors = model.get('ctors') types = model.get('types') forms = model.get('forms') univs = model.get('univs') props = collections.defaultdict(list) ctors = sorted(ctors, key=lambda x: x[0]) univs = sorted(univs, key=lambda x: x[0]) types = sorted(types, key=lambda x: x[0]) forms = sorted(forms, key=lambda x: x[0]) univ_names = {univ[0] for univ in univs} for fname, fnfo, fprops in forms: for prop in fprops: props[fname].append(prop) [v.sort() for k, v in props.items()] dochelp = DocHelp(ctors, types, forms, props, univs) # Validate examples for form, example in dochelp.formhelp.items(): if example is None: continue if example.startswith('('): q = f"[{form}={example}]" else: q = f"[{form}='{example}']" node = False async for (mtyp, mnfo) in core.storm(q, {'editformat': 'none'}): if mtyp in ('init', 'fini'): continue if mtyp == 'err': # pragma: no cover raise s_exc.SynErr(mesg='Invalid example', form=form, example=example, info=mnfo) if mtyp == 'node': node = True if not node: # pramga: no cover raise s_exc.SynErr(mesg='Unable to make a node from example.', form=form, example=example) rst = s_autodoc.RstHelp() rst.addHead('Synapse Data Model - Types', lvl=0) processCtors(rst, dochelp, ctors) processTypes(rst, dochelp, types) rst2 = s_autodoc.RstHelp() rst2.addHead('Synapse Data Model - Forms', lvl=0) processFormsProps(rst2, dochelp, forms, univ_names) processUnivs(rst2, dochelp, univs) return rst, rst2
async def docStormpkg(pkgpath): pkgdef = s_genpkg.loadPkgProto(pkgpath) pkgname = pkgdef.get('name') rst = s_autodoc.RstHelp() # Disable default python highlighting rst.addLines('.. highlight:: none\n') hname = pkgname if ':' in pkgname: hname = pkgname.replace(':', raw_back_slash_colon) rst.addHead(f'Storm Package\\: {hname}') lines = ['The following Commands are available from this package.', f'This documentation is generated for version ' f'{s_version.fmtVersion(*pkgdef.get("version"))} of the package.', ] rst.addLines(*lines) commands = pkgdef.get('commands') if commands: await processStormCmds(rst, pkgname, commands) # TODO: Modules are not currently documented. return rst, pkgname
async def docStormsvc(ctor): cls = s_dyndeps.tryDynLocal(ctor) if not hasattr(cls, 'cellapi'): raise Exception('ctor must have a cellapi attr') clsname = cls.__name__ cellapi = cls.cellapi if not issubclass(cellapi, s_stormsvc.StormSvc): raise Exception('cellapi must be a StormSvc implementation') # Make a dummy object class MockSess: def __init__(self): self.user = None class DummyLink: def __init__(self): self.info = {'sess': MockSess()} def get(self, key): return self.info.get(key) async with await cellapi.anit(s_common.novalu, DummyLink(), s_common.novalu) as obj: svcinfo = await obj.getStormSvcInfo() rst = s_autodoc.RstHelp() # Disable default python highlighting rst.addLines('.. highlight:: none\n') rst.addHead(f'{clsname} Storm Service') lines = ['The following Storm Packages and Commands are available from this service.', f'This documentation is generated for version ' f'{s_version.fmtVersion(*svcinfo.get("vers"))} of the service.', f'The Storm Service name is ``{svcinfo.get("name")}``.', ] rst.addLines(*lines) for pkg in svcinfo.get('pkgs'): pname = pkg.get('name') pver = pkg.get('version') commands = pkg.get('commands') hname = pname if ':' in pname: hname = pname.replace(':', raw_back_slash_colon) rst.addHead(f'Storm Package\\: {hname}', lvl=1) rst.addLines(f'This documentation for {pname} is generated for version {s_version.fmtVersion(*pver)}') if commands: await processStormCmds(rst, pname, commands) # TODO: Modules are not currently documented. return rst, clsname
async def docStormTypes(): registry = s_stormtypes.registry libsinfo = registry.getLibDocs() libspage = s_autodoc.RstHelp() libspage.addHead('Storm Libraries', lvl=0, link='.. _stormtypes-libs-header:') lines = ( '', 'Storm Libraries represent powerful tools available inside of the Storm query language.', '' ) libspage.addLines(*lines) # This value is appended to the end of the ref to the first level header of a type. # This prevents accidental cross linking between parts of the docs; which can happen # when secondary properties of a type may overlap with the main name of the type. types_suffix = 'f527' s_autodoc.docStormTypes(libspage, libsinfo, linkprefix='stormlibs', islib=True, known_types=registry.known_types, types_prefix='stormprims', types_suffix=types_suffix) priminfo = registry.getTypeDocs() typespage = s_autodoc.RstHelp() typespage.addHead('Storm Types', lvl=0, link='.. _stormtypes-prim-header:') lines = ( '', 'Storm Objects are used as view objects for manipulating data in the Storm Runtime and in the Cortex itself.' '' ) typespage.addLines(*lines) s_autodoc.docStormTypes(typespage, priminfo, linkprefix='stormprims', known_types=registry.known_types, types_prefix='stormprims', types_suffix=types_suffix) return libspage, typespage
async def docConfdefs(ctor, reflink=':ref:`devops-cell-config`', doc_title=None): cls = s_dyndeps.tryDynLocal(ctor) if not hasattr(cls, 'confdefs'): raise Exception('ctor must have a confdefs attr') rst = s_autodoc.RstHelp() clsname = cls.__name__ conf = cls.initCellConf() # type: s_config.Config if doc_title is None: doc_title = clsname rst.addHead(f'{doc_title} Configuration Options', lvl=0, link=f'.. _autodoc-{clsname.lower()}-conf:') rst.addLines(f'The following are boot-time configuration options for the cell.') rst.addLines(f'See {reflink} for details on how to set these options.') # access raw config data # Get envar and argparse mapping name2envar = conf.getEnvarMapping() name2cmdline = conf.getCmdlineMapping() schema = conf.json_schema.get('properties', {}) for name, conf in sorted(schema.items(), key=lambda x: x[0]): if conf.get('hideconf'): continue nodesc = f'No description available for ``{name}``.' hname = name if ':' in name: hname = name.replace(':', raw_back_slash_colon) rst.addHead(hname, lvl=1) desc = conf.get('description', nodesc) if not desc.endswith('.'): # pragma: no cover logger.warning(f'Description for [{name}] is missing a period.') lines = [] lines.append(desc) extended_description = conf.get('extended_description') if extended_description: lines.append('\n') lines.append(extended_description) # Type/additional information lines.append('\n') ctyp = conf.get('type') lines.append('Type') lines.append(f' ``{ctyp}``\n') if ctyp == 'object': if conf.get('properties'): lines.append('Properties') lines.append(' The object expects the following properties:') data = {k: v for k, v in conf.items() if k not in ( 'description', 'default', 'type', 'hideconf', 'hidecmdl', )} parts = json.dumps(data, sort_keys=True, indent=2).split('\n') lines.append(' ::') lines.append('\n') lines.extend([f' {p}' for p in parts]) lines.append('\n') defval = conf.get('default', s_common.novalu) if defval is not s_common.novalu: lines.append('Default Value') lines.append(f' ``{repr(defval)}``\n') envar = name2envar.get(name) if envar: lines.append('Environment Variable') lines.append(f' ``{envar}``\n') cmdline = name2cmdline.get(name) if cmdline: lines.append('Command Line Argument') lines.append(f' ``--{cmdline}``\n') rst.addLines(*lines) return rst, clsname
async def docStormsvc(ctor): cls = s_dyndeps.tryDynLocal(ctor) if not hasattr(cls, 'cellapi'): raise Exception('ctor must have a cellapi attr') clsname = cls.__name__ cellapi = cls.cellapi if not issubclass(cellapi, s_stormsvc.StormSvc): raise Exception('cellapi must be a StormSvc implementation') # Make a dummy object class MockSess: def __init__(self): self.user = None class DummyLink: def __init__(self): self.info = {'sess': MockSess()} def get(self, key): return self.info.get(key) async with await cellapi.anit(s_common.novalu, DummyLink(), s_common.novalu) as obj: svcinfo = await obj.getStormSvcInfo() rst = s_autodoc.RstHelp() # Disable default python highlighting rst.addLines('.. highlight:: none\n') rst.addHead(f'{clsname} Storm Service') lines = [ 'The following Storm Packages and Commands are available from this service.', f'This documentation is generated for version ' f'{s_version.fmtVersion(*svcinfo.get("vers"))} of the service.', f'The Storm Service name is ``{svcinfo.get("name")}``.', ] rst.addLines(*lines) for pkg in svcinfo.get('pkgs'): pname = pkg.get('name') pver = pkg.get('version') commands = pkg.get('commands') hname = pname if ':' in pname: hname = pname.replace(':', raw_back_slash_colon) rst.addHead(f'Storm Package\\: {hname}', lvl=1) rst.addLines( f'This documentation for {pname} is generated for version {s_version.fmtVersion(*pver)}' ) if commands: rst.addHead('Storm Commands', lvl=2) rst.addLines( f'This package implements the following Storm Commands.\n') for cdef in commands: cname = cdef.get('name') cdesc = cdef.get('descr') cargs = cdef.get('cmdargs') # command names cannot have colons in them thankfully cref = f'.. _stormcmd-{pname.replace(":", "-")}-{cname.replace(".", "-")}:' rst.addHead(cname, lvl=3, link=cref) # Form the description lines = ['::\n'] # Generate help from args pars = s_storm.Parser(prog=cname, descr=cdesc) if cargs: for (argname, arginfo) in cargs: pars.add_argument(argname, **arginfo) pars.help() for line in pars.mesgs: if '\n' in line: for subl in line.split('\n'): lines.append(f' {subl}') else: lines.append(f' {line}') lines.append('\n') forms = cdef.get('forms', {}) iforms = forms.get('input') oforms = forms.get('output') nodedata = forms.get('nodedata') if iforms: line = 'The command is aware of how to automatically handle the following forms as input nodes:\n' lines.append(line) for form in iforms: lines.append(f'- ``{form}``') lines.append('\n') if oforms: line = 'The command may make the following types of nodes in the graph as a result of its execution:\n' lines.append(line) for form in oforms: lines.append(f'- ``{form}``') lines.append('\n') if nodedata: line = 'The command may add nodedata with the following keys to the corresponding forms:\n' lines.append(line) for key, form in nodedata: lines.append(f'- ``{key}`` on ``{form}``') lines.append('\n') rst.addLines(*lines) # TODO: Modules are not currently documented. return rst, clsname