def make_field(self, types, domain, items, env=None): fieldname = nodes.field_name('', self.label) listnode = self.list_type() if len(items) == 1 and self.can_collapse: return Field.make_field(self, types, domain, items[0]) for fieldarg, content in items: par = nodes.paragraph() par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong) listnode += nodes.list_item('', par) fieldbody = nodes.field_body('', listnode) return nodes.field('', fieldname, fieldbody)
def make_field(self, types, domain, items): fieldname = nodes.field_name('', self.label) if len(items) == 1 and self.can_collapse: return Field.make_field(self, types, domain, items[0]) bodynode = nodes.paragraph() for i, (fieldarg, content) in enumerate(items): bodynode += nodes.Text(', ') if i else None bodynode += self.make_xref(self.bodyrolename, domain, content[0].astext(), nodes.Text) fieldbody = nodes.field_body('', bodynode) return nodes.field('', fieldname, fieldbody)
def setup(app): from sphinx.domains.python import PyField from sphinx.util.docfields import Field app.add_object_type('confval', 'confval', objname='configuration value', indextemplate='pair: %s; configuration value', doc_field_types=[ PyField('type', label=_('Type'), has_arg=False, names=('type', ), bodyrolename='class'), Field( 'default', label=_('Default'), has_arg=False, names=('default', ), ), ])
def setup(app): from sphinx.domains.python import PyField from sphinx.util.docfields import Field app.add_object_type("confval", "confval", objname="configuration value", indextemplate="pair: %s; configuration value", doc_field_types=[ PyField("type", label=_("Type"), has_arg=False, names=("type", ), bodyrolename="class"), Field( "default", label=_("Default"), has_arg=False, names=("default", ), ), ])
def setup(app: Sphinx) -> None: """Register the :dir: role. This is just a shortcut to curb the cognitive dissonance when saying :file:`directory/`. """ app.add_role("dir", DirRole()) app.add_object_type( "confval", "confval", objname="configuration parameter", doc_field_types=[ Field( "default", label="default", has_arg=True, names=("default", ), bodyrolename="class", ) ], )
def setup(app) -> Dict[str, Any]: app.add_config_value('ceph_confval_imports', default=[], rebuild='html', types=[str]) app.add_config_value('ceph_confval_mgr_module_path', default=[], rebuild='html', types=[str]) app.add_config_value('ceph_confval_mgr_python_path', default=[], rebuild='', types=[str]) app.add_object_type( 'confsec', 'confsec', objname='configuration section', indextemplate='pair: %s; configuration section', doc_field_types=[ Field( 'example', label=_('Example'), has_arg=False, )] ) app.add_object_type( 'confval', 'confval', objname='configuration option', ) app.add_directive_to_domain('std', 'mgr_module', CephModule) app.add_directive_to_domain('std', 'confval', CephOption, override=True) app.connect('env-purge-doc', _reset_ref_context) return { 'version': 'builtin', 'parallel_read_safe': True, 'parallel_write_safe': True, }
class ReFORMStatement(ReFORMMarkup): """ Description of a reFORM statement. """ doc_field_types = [ TypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument'), typerolename='type', typenames=('type', )), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), ] def handle_signature(self, sig, signode): name = sig.strip() nameid = name.split()[0] desc_name = name signode += addnodes.desc_name(nameid, desc_name) return nameid
def setup(app): from sphinx.util.docfields import Field, TypedField increase_python_stack() # the :ghci-cmd: directive used in ghci.rst app.add_object_type('ghci-cmd', 'ghci-cmd', parse_node=parse_ghci_cmd, objname='GHCi command', indextemplate='pair: %s; GHCi command') # Haddock references app.add_role('th-ref', haddock_role('template-haskell')) app.add_role('base-ref', haddock_role('base')) app.add_role('cabal-ref', haddock_role('Cabal')) app.add_role('ghc-compact-ref', haddock_role('ghc-compact')) app.add_role('ghc-prim-ref', haddock_role('ghc-prim')) app.add_role('parallel-ref', haddock_role('parallel')) app.add_role('array-ref', haddock_role('array')) app.add_object_type('rts-flag', 'rts-flag', objname='runtime system command-line option', parse_node=parse_flag, indextemplate='pair: %s; RTS option', doc_field_types=[ Field('since', label='Introduced in GHC version', names=['since']) ]) app.add_object_type('event-type', 'event-type', objname='event log event type', indextemplate='pair: %s; eventlog event type', doc_field_types=[ Field('since', label='Introduced in GHC version', names=['since']), Field('tag', label='Event type ID', names=['tag']), Field('length', label='Record length', names=['length']), TypedField('fields', label='Fields', names='field', typenames=('fieldtype', 'type')) ]) app.add_object_type('pragma', 'pragma', objname='Haskell pragma', parse_node=parse_pragma, indextemplate='pair: %s; pragma', doc_field_types=[ Field('since', label='Introduced in GHC version', names=['since']), Field('where', label='Allowed contexts', names=['where']) ])
class CabalField(CabalObject): ''' Base for fields in *.cabal files ''' option_spec = { 'noindex': directives.flag, 'deprecated': parse_deprecated, 'since': StrictVersion, 'synopsis': lambda x: x } doc_field_types = [ Field('default', label='Default value', names=['default'], has_arg=False) ] def handle_signature(self, sig, signode): ''' As in sphinx.directives.ObjectDescription By default make an object description from name and adding either deprecated or since as annotation. ''' env = self.state.document.settings.env sig = sig.strip() parts = sig.split(':', 1) name = parts[0] signode += addnodes.desc_name(name, name) signode += addnodes.desc_addname(': ', ': ') if len(parts) > 1: rest = parts[1].strip() signode += addnodes.desc_annotation(rest, rest) return name
def setup(app): from sphinx.domains.python import PyField from sphinx.util.docfields import Field app.add_object_type('confval', 'confval', objname='configuration value', indextemplate='pair: %s; configuration value', doc_field_types=[ PyField('type', label=_('Type'), has_arg=False, names=('type', ), bodyrolename='class'), Field( 'default', label=_('Default'), has_arg=False, names=('default', ), ), ]) app.add_stylesheet("css/theme_overrides.css") app.add_javascript("js/version_switch.js")
def make_confval(app): # Copy-pasted from https://github.com/rtfd/sphinx_rtd_theme from sphinx.locale import _ from sphinx.domains.python import PyField from sphinx.util.docfields import Field app.add_object_type('confval', 'confval', objname='configuration value', indextemplate='pair: %s; configuration value', doc_field_types=[ PyField('type', label=_('Type'), has_arg=False, names=('type', ), bodyrolename='class'), Field( 'default', label=_('Default'), has_arg=False, names=('default', ), ), ])
def setup(app): from sphinx.domains.python import PyField from sphinx.util.docfields import Field app.add_css_file('/source/_static/custom.css') app.add_stylesheet('/source/_static/theme_override.css') app.add_object_type('confval', 'confval', objname='configuration value', indextemplate='pair: %s; configuration value', doc_field_types=[ PyField('type', label=_('Type'), has_arg=False, names=('type', ), bodyrolename='class'), Field( 'default', label=_('Default'), has_arg=False, names=('default', ), ), ]) # Patch the MATLAB lexer to correct wrong highlighting from sphinx.highlighting import lexers from pygments.lexers import MatlabLexer from pygments.token import Name from pygments.filters import NameHighlightFilter matlab_lexer = MatlabLexer() matlab_lexer.add_filter( NameHighlightFilter( names=[ 'function', 'end', 'if', 'else', 'elseif', 'switch', 'case', 'return', 'otherwise' ], tokentype=Name.Function, )) app.add_lexer('matlab', matlab_lexer)
class DotNetProperty(DotNetObject): option_spec = { 'name': directives.unchanged, 'prefix': directives.unchanged, 'type': directives.unchanged, } doc_field_types = [ Field('value', label=l_('Value'), has_arg=False, names=('value', 'value')), ] def handle_signature(self, sig, signode): name = self.options['name'] prefix = self.options['prefix'] type_v = json.loads(self.options['type']) if prefix != 'readwrite': signode += nodes.Text(prefix, prefix) signode += nodes.Text(' ', u'\xa0') xref = addnodes.pending_xref(':ref:`' + type_v[1] + '`', refdomain='std', reftype='ref', reftarget=ws_re.sub( ' ', type_v[1].lower()), refexplicit=False) xref += nodes.Text(type_v[0], type_v[0]) signode += xref signode += nodes.Text(' ', u'\xa0') signode += addnodes.desc_name(name, name) return name, ""
class JSONDefinition(JSONObject): doc_field_types = [ Field("type", label=l_("Type"), names=("type")), TypedField( "props", label=l_("Properties"), names=("property", "prop"), typenames=("array", "boolean", "integer", "null", "number", "object", "string"), ) ] def handle_signature(self, sig, signode): import ipdb ipdb.set_trace() signode += addnodes.desc_name(sig, sig) fullname = self.objtype.capitalize() + " " + sig signode["fullname"] = fullname return (fullname, sig) def add_target_and_index(self, name_cls, sig, signode): signode["ids"].append("{0}-{1}".format(self.objtype, sig)) self.env.domaindata["jsschema"]["objects"][sig] = (self.env.docname, self.objtype, "")
class BBDomain(Domain): name = 'bb' label = 'Buildbot' object_types = { 'cfg': ObjType('cfg', 'cfg'), 'sched': ObjType('sched', 'sched'), 'chsrc': ObjType('chsrc', 'chsrc'), 'step': ObjType('step', 'step'), 'reporter': ObjType('reporter', 'reporter'), 'configurator': ObjType('configurator', 'configurator'), 'worker': ObjType('worker', 'worker'), 'cmdline': ObjType('cmdline', 'cmdline'), 'msg': ObjType('msg', 'msg'), 'event': ObjType('event', 'event'), 'rtype': ObjType('rtype', 'rtype'), 'rpath': ObjType('rpath', 'rpath'), } directives = { 'cfg': make_ref_target_directive('cfg', indextemplates=[ 'single: Buildmaster Config; %s', 'single: %s (Buildmaster Config)', ]), 'sched': make_ref_target_directive('sched', indextemplates=[ 'single: Schedulers; %s', 'single: %s Scheduler', ]), 'chsrc': make_ref_target_directive('chsrc', indextemplates=[ 'single: Change Sources; %s', 'single: %s Change Source', ]), 'step': make_ref_target_directive('step', indextemplates=[ 'single: Build Steps; %s', 'single: %s Build Step', ]), 'reporter': make_ref_target_directive('reporter', indextemplates=[ 'single: Reporter Targets; %s', 'single: %s Reporter Target', ]), 'configurator': make_ref_target_directive('configurator', indextemplates=[ 'single: Configurators; %s', 'single: %s Configurators', ]), 'worker': make_ref_target_directive('worker', indextemplates=[ 'single: Build Workers; %s', 'single: %s Build Worker', ]), 'cmdline': make_ref_target_directive('cmdline', indextemplates=[ 'single: Command Line Subcommands; %s', 'single: %s Command Line Subcommand', ]), 'msg': make_ref_target_directive('msg', indextemplates=[ 'single: Message Schema; %s', ], has_content=True, name_annotation='routing key:', doc_field_types=[ TypedField('key', label='Keys', names=('key', ), typenames=('type', ), can_collapse=True), Field('var', label='Variable', names=('var', )), ]), 'event': make_ref_target_directive('event', indextemplates=[ 'single: event; %s', ], has_content=True, name_annotation='event:', doc_field_types=[]), 'rtype': make_ref_target_directive('rtype', indextemplates=[ 'single: Resource Type; %s', ], has_content=True, name_annotation='resource type:', doc_field_types=[ TypedField('attr', label='Attributes', names=('attr', ), typenames=('type', ), can_collapse=True), ]), 'rpath': make_ref_target_directive('rpath', indextemplates=[ 'single: Resource Path; %s', ], name_annotation='path:', has_content=True, doc_field_types=[ TypedField('pathkey', label='Path Keys', names=('pathkey', ), typenames=('type', ), can_collapse=True), ]), 'raction': make_ref_target_directive('raction', indextemplates=[ 'single: Resource Action; %s', ], name_annotation='POST with method:', has_content=True, doc_field_types=[ TypedField('body', label='Body keys', names=('body', ), typenames=('type', ), can_collapse=True), ]), } roles = { 'cfg': XRefRole(), 'sched': XRefRole(), 'chsrc': XRefRole(), 'step': XRefRole(), 'reporter': XRefRole(), 'configurator': XRefRole(), 'worker': XRefRole(), 'cmdline': XRefRole(), 'msg': XRefRole(), 'event': XRefRole(), 'rtype': XRefRole(), 'rpath': XRefRole(), 'index': XRefRole() } initial_data = { 'targets': {}, # type -> target -> (docname, targetname) } indices = [ make_index("cfg", "Buildmaster Configuration Index"), make_index("sched", "Scheduler Index"), make_index("chsrc", "Change Source Index"), make_index("step", "Build Step Index"), make_index("reporter", "Reporter Target Index"), make_index("configurator", "Configurator Target Index"), make_index("worker", "Build Worker Index"), make_index("cmdline", "Command Line Index"), make_index("msg", "MQ Routing Key Index"), make_index("event", "Data API Event Index"), make_index("rtype", "REST/Data API Resource Type Index"), make_index("rpath", "REST/Data API Path Index"), make_index("raction", "REST/Data API Actions Index"), ] def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): if typ == 'index': for idx in self.indices: if idx.name == target: break else: raise KeyError("no index named '%s'" % target) return idx.resolve_ref(self, env, fromdocname, builder, typ, target, node, contnode) elif typ in self.directives: dir = self.directives[typ] return dir.resolve_ref(self, env, fromdocname, builder, typ, target, node, contnode)
class CObject(ObjectDescription): """ Description of a C language object. """ doc_field_types = [ TypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument'), typerolename='type', typenames=('type', )), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), Field('returntype', label=l_('Return type'), has_arg=False, names=('rtype', )), ] # These C types aren't described anywhere, so don't try to create # a cross-reference to them stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct')) def _parse_type(self, node, ctype): # add cross-ref nodes for all words for part in filter(None, wsplit_re.split(ctype)): tnode = nodes.Text(part, part) if part[0] in string.ascii_letters+'_' and \ part not in self.stopwords: pnode = addnodes.pending_xref('', refdomain='c', reftype='type', reftarget=part, modname=None, classname=None) pnode += tnode node += pnode else: node += tnode def handle_signature(self, sig, signode): """Transform a C signature into RST nodes.""" # first try the function pointer signature regex, it's more specific m = c_funcptr_sig_re.match(sig) if m is None: m = c_sig_re.match(sig) if m is None: raise ValueError('no match') rettype, name, arglist, const = m.groups() signode += addnodes.desc_type('', '') self._parse_type(signode[-1], rettype) try: classname, funcname = name.split('::', 1) classname += '::' signode += addnodes.desc_addname(classname, classname) signode += addnodes.desc_name(funcname, funcname) # name (the full name) is still both parts except ValueError: signode += addnodes.desc_name(name, name) # clean up parentheses from canonical name m = c_funcptr_name_re.match(name) if m: name = m.group(1) typename = self.env.temp_data.get('c:type') if self.name == 'c:member' and typename: fullname = typename + '.' + name else: fullname = name if not arglist: if self.objtype == 'function': # for functions, add an empty parameter list signode += addnodes.desc_parameterlist() if const: signode += addnodes.desc_addname(const, const) return fullname paramlist = addnodes.desc_parameterlist() arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup # this messes up function pointer types, but not too badly ;) args = arglist.split(',') for arg in args: arg = arg.strip() param = addnodes.desc_parameter('', '', noemph=True) try: ctype, argname = arg.rsplit(' ', 1) except ValueError: # no argument name given, only the type self._parse_type(param, arg) else: self._parse_type(param, ctype) # separate by non-breaking space in the output param += nodes.emphasis(' ' + argname, u'\xa0' + argname) paramlist += param signode += paramlist if const: signode += addnodes.desc_addname(const, const) return fullname def get_index_text(self, name): if self.objtype == 'function': return _('%s (C function)') % name elif self.objtype == 'member': return _('%s (C member)') % name elif self.objtype == 'macro': return _('%s (C macro)') % name elif self.objtype == 'type': return _('%s (C type)') % name elif self.objtype == 'var': return _('%s (C variable)') % name else: return '' def add_target_and_index(self, name, sig, signode): # note target if name not in self.state.document.ids: signode['names'].append(name) signode['ids'].append(name) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) inv = self.env.domaindata['c']['objects'] if name in inv: self.state_machine.reporter.warning( 'duplicate C object description of %s, ' % name + 'other instance in ' + self.env.doc2path(inv[name][0]), line=self.lineno) inv[name] = (self.env.docname, self.objtype) indextext = self.get_index_text(name) if indextext: self.indexnode['entries'].append(('single', indextext, name, '')) def before_content(self): self.typename_set = False if self.name == 'c:type': if self.names: self.env.temp_data['c:type'] = self.names[0] self.typename_set = True def after_content(self): if self.typename_set: self.env.temp_data['c:type'] = None
class RoseConfigDirective(RoseDirective): """Directive for documenting config sections. Optional Attributes: * ``envvar`` - Associate an environment variable with this configuration option. * ``compulsory`` - Set to ``True`` for compulsory settings, omit this field for optional settings. Additional ref_context: * ``rose:conf-section`` - Set for parent configurations, is available to any child nodes. Example: Click :guilabel:`source` to view source code. .. code-block:: rst .. rose:conf:: foo :default: foo :opt argtype foo: Description of option ``foo``. :opt bar: Description of bar A setting called ``foo``. .. rose:conf:: bar A section called ``bar``. .. rose:conf:: baz :compulsory: True :env: AN_ASSOCIATED_ENVIRONMENT_VARIABLE A config called ``[bar]baz``. """ NAME = 'conf' LABEL = 'Config' SECTION_REF_CONTEXT = 'conf-section' ARGUMENT_REGEX = OPT_ARG_REGEX ARGUMENT_SEPARATOR = '=' # Add custom fields. doc_field_types = [ # NOTE: The field label must be sort to avoid causing a line break. Field('envvar', label='Env Var', has_arg=False, names=('env', ), bodyrolename='obj'), Field('compulsory', label='Compulsory', has_arg=True, names=('compulsory', )), Field('default', label='Default', has_arg=False, names=('default', )), TypedField('option', label='Options', names=('opt', ), typerolename='obj', typenames=('paramtype', 'type'), can_collapse=True) ] def run(self): """Overridden to add the :rose:conf-section: ``ref_context`` variable for nested sections.""" if self.registered_children or any('.. rose:conf::' in line for line in self.content): # This configuration contains other configurations i.e. it is a # configuration section. Apply a custom_name_template so that it is # written inside square brackets. self.custom_name_template = '[%s]' # Sections cannot be written with argument examples. self.ARGUMENT_SEPARATOR = None self.ARGUMENT_REGEX = None # Add a ref_context variable to mark this node as a config section. self.add_ref_context(self.SECTION_REF_CONTEXT) return RoseDirective.run(self)
class BBDomain(Domain): name = 'bb' label = 'Buildbot' object_types = { 'cfg': ObjType('cfg', 'cfg'), 'sched': ObjType('sched', 'sched'), 'chsrc': ObjType('chsrc', 'chsrc'), 'step': ObjType('step', 'step'), 'reporter': ObjType('reporter', 'reporter'), 'configurator': ObjType('configurator', 'configurator'), 'worker': ObjType('worker', 'worker'), 'cmdline': ObjType('cmdline', 'cmdline'), 'msg': ObjType('msg', 'msg'), 'event': ObjType('event', 'event'), 'rtype': ObjType('rtype', 'rtype'), 'rpath': ObjType('rpath', 'rpath'), 'raction': ObjType('raction', 'raction'), } directives = { 'cfg': make_ref_target_directive('cfg', indextemplates=[ 'single: Buildmaster Config; %s', 'single: %s (Buildmaster Config)', ]), 'sched': make_ref_target_directive('sched', indextemplates=[ 'single: Schedulers; %s', 'single: %s Scheduler', ]), 'chsrc': make_ref_target_directive('chsrc', indextemplates=[ 'single: Change Sources; %s', 'single: %s Change Source', ]), 'step': make_ref_target_directive('step', indextemplates=[ 'single: Build Steps; %s', 'single: %s Build Step', ]), 'reporter': make_ref_target_directive('reporter', indextemplates=[ 'single: Reporter Targets; %s', 'single: %s Reporter Target', ]), 'configurator': make_ref_target_directive('configurator', indextemplates=[ 'single: Configurators; %s', 'single: %s Configurators', ]), 'worker': make_ref_target_directive('worker', indextemplates=[ 'single: Build Workers; %s', 'single: %s Build Worker', ]), 'cmdline': make_ref_target_directive('cmdline', indextemplates=[ 'single: Command Line Subcommands; %s', 'single: %s Command Line Subcommand', ]), 'msg': make_ref_target_directive('msg', indextemplates=[ 'single: Message Schema; %s', ], has_content=True, name_annotation='routing key:', doc_field_types=[ TypedField('key', label='Keys', names=('key', ), typenames=('type', ), can_collapse=True), Field('var', label='Variable', names=('var', )), ]), 'event': make_ref_target_directive('event', indextemplates=[ 'single: event; %s', ], has_content=True, name_annotation='event:', doc_field_types=[]), 'rtype': make_ref_target_directive('rtype', indextemplates=[ 'single: Resource Type; %s', ], has_content=True, name_annotation='resource type:', doc_field_types=[ TypedField('attr', label='Attributes', names=('attr', ), typenames=('type', ), can_collapse=True), ]), 'rpath': make_ref_target_directive('rpath', indextemplates=[ 'single: Resource Path; %s', ], name_annotation='path:', has_content=True, doc_field_types=[ TypedField('pathkey', label='Path Keys', names=('pathkey', ), typenames=('type', ), can_collapse=True), ]), 'raction': make_ref_target_directive('raction', indextemplates=[ 'single: Resource Action; %s', ], name_annotation='POST with method:', has_content=True, doc_field_types=[ TypedField('body', label='Body keys', names=('body', ), typenames=('type', ), can_collapse=True), ]), } roles = { 'cfg': XRefRole(), 'sched': XRefRole(), 'chsrc': XRefRole(), 'step': XRefRole(), 'reporter': XRefRole(), 'configurator': XRefRole(), 'worker': XRefRole(), 'cmdline': XRefRole(), 'msg': XRefRole(), 'event': XRefRole(), 'rtype': XRefRole(), 'rpath': XRefRole(), 'index': XRefRole() } initial_data = { 'targets': {}, # type -> target -> (docname, targetname) } indices = [ make_index("cfg", "Buildmaster Configuration Index"), make_index("sched", "Scheduler Index"), make_index("chsrc", "Change Source Index"), make_index("step", "Build Step Index"), make_index("reporter", "Reporter Target Index"), make_index("configurator", "Configurator Target Index"), make_index("worker", "Build Worker Index"), make_index("cmdline", "Command Line Index"), make_index("msg", "MQ Routing Key Index"), make_index("event", "Data API Event Index"), make_index("rtype", "REST/Data API Resource Type Index"), make_index("rpath", "REST/Data API Path Index"), make_index("raction", "REST/Data API Actions Index"), ] def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): if typ == 'index': for idx in self.indices: if idx.name == target: break else: raise KeyError("no index named '%s'" % target) return idx.resolve_ref(self, env, fromdocname, builder, typ, target, node, contnode) elif typ in self.directives: dir = self.directives[typ] return dir.resolve_ref(self, env, fromdocname, builder, typ, target, node, contnode) def merge_domaindata(self, docnames, otherdata): for typ in self.object_types: if typ not in otherdata['targets']: continue if typ not in self.data['targets']: self.data['targets'][typ] = otherdata['targets'][typ] continue self_data = self.data['targets'][typ] other_data = otherdata['targets'][typ] for target_name, target_data in other_data.items(): if target_name in self_data: # for some reason we end up with multiple references to the same things in # multiple domains. If both instances point to the same location, ignore it, # otherwise issue a warning. if other_data[target_name] == self_data[target_name]: continue self_path = '{0}#{1}'.format( self.env.doc2path(self_data[target_name][0]), self_data[target_name][1]) other_path = '{0}#{1}'.format( self.env.doc2path(other_path[target_name][0]), other_path[target_name][1]) logger.warning(('Duplicate index {} reference {} in {}, ' 'other instance in {}').format( typ, target_name, self_path, other_path)) else: self_data[target_name] = target_data
class MongoDBObject(ObjectDescription): """ Description of a MongoDB object. """ #: If set to ``True`` this object is callable and a `desc_parameterlist` is #: added has_arguments = False #: what is displayed right before the documentation entry display_prefix = None def handle_signature(self, sig, signode): sig = sig.strip() if '(' in sig and sig[-1:] == ')': prefix, arglist = sig.split('(', 1) prefix = prefix.strip() arglist = arglist[:-1].strip() else: prefix = sig arglist = None if '.' in prefix: nameprefix, name = prefix.rsplit('.', 1) else: nameprefix = None name = prefix objectname = self.env.temp_data.get('mongodb:object') if nameprefix: if objectname: # someone documenting the method of an attribute of the current # object? shouldn't happen but who knows... nameprefix = objectname + '.' + nameprefix fullname = nameprefix + '.' + name elif objectname: fullname = objectname + '.' + name else: # just a function or constructor objectname = '' fullname = name signode['object'] = objectname signode['fullname'] = fullname if self.display_prefix: signode += addnodes.desc_annotation(self.display_prefix, self.display_prefix) if nameprefix: signode += addnodes.desc_addname(nameprefix + '.', nameprefix + '.') signode += addnodes.desc_name(name, name) if self.has_arguments: if not arglist: signode += addnodes.desc_parameterlist() else: _pseudo_parse_arglist(signode, arglist) return fullname, nameprefix def add_target_and_index(self, name_obj, sig, signode): objectname = self.options.get( 'object', self.env.temp_data.get('mongodb:object')) fullname = name_obj[0] if fullname not in self.state.document.ids: signode['names'].append(fullname) signode['ids'].append(fullname.replace('$', '_S_')) signode['first'] = not self.names self.state.document.note_explicit_target(signode) objects = self.env.domaindata['mongodb']['objects'] # if fullname in objects: # self.state_machine.reporter.warning( # 'duplicate object description of %s, ' % fullname + # 'other instance in ' + # self.env.doc2path(objects[fullname][0]), # line=self.lineno) objects[fullname] = self.env.docname, self.objtype # elif self.objtype == "binary": # signode['names'].append(fullname) # signode['ids'].append(fullname.replace('$', '_S_')) # signode['first'] = not self.names # self.state.document.note_explicit_target(signode) indextext = self.get_index_text(objectname, name_obj) if indextext: self.indexnode['entries'].append(('single', indextext, fullname.replace('$', '_S_'), '')) def get_index_text(self, objectname, name_obj): name, obj = name_obj if self.objtype == 'dbcommand': return _('%s (database command)') % name elif self.objtype == 'operator': return _('%s (operator)') % name elif self.objtype == 'projection': return _('%s (projection operator)') % name elif self.objtype == 'program': return _('%s (program)') % name elif self.objtype == 'setting': return _('%s (setting)') % (name) elif self.objtype == 'status': return _('%s (status)') % (name) elif self.objtype == 'stats': return _('%s (statistic)') % (name) elif self.objtype == 'data': return _('%s (shell output)') % (name) elif self.objtype == 'method': return _('%s (shell method)') % (name) elif self.objtype == 'collflag': return _('%s (collection flag)') % (name) elif self.objtype == 'readmode': return _('%s (read preference mode)') % (name) elif self.objtype == 'error': return _('%s (error code)') % (name) elif self.objtype == 'macro': return _('%s (JavaScript shell macro)') % (name) elif self.objtype == 'limit': return _('%s (MongoDB system limit)') % (name) return '' def run(self): return super(MongoDBObject, self).run() doc_field_types = [ TypedField('arguments', label=l_('Arguments'), names=('argument', 'arg', 'parameter', 'param'), typerolename='method', typenames=('paramtype', 'type')), TypedField('options', label=l_('Options'), names=('options', 'opts', 'option', 'opt'), typerolename=('dbcommand', 'setting', 'status', 'stats', 'aggregator'), typenames=('optstype', 'type')), TypedField('fields', label=l_('Fields'), names=('fields', 'fields', 'field', 'field'), typerolename=('dbcommand', 'setting', 'status', 'stats', 'aggregator'), typenames=('fieldtype', 'type')), TypedField('flags', label=l_('Flags'), names=('flags', 'flags', 'flag', 'flag'), typerolename=('dbcommand', 'setting', 'status', 'stats', 'aggregator'), typenames=('flagtype', 'type')), GroupedField('errors', label=l_('Throws'), rolename='err', names=('throws', ), can_collapse=True), GroupedField('exception', label=l_('Exception'), rolename='err', names=('exception', ), can_collapse=True), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), Field('returntype', label=l_('Return type'), has_arg=False, names=('rtype',)), ]
class ChapelObject(ObjectDescription): """Base class for Chapel directives. It has methods for parsing signatures of any form, and generating target and index text. """ option_spec = { 'noindex': directives.flag, 'module': directives.unchanged, 'annotation': directives.unchanged, } doc_field_types = [ ChapelTypedField('parameter', label=_('Arguments'), names=('param', 'parameter', 'arg', 'argument'), typerolename='chplref', typenames=('paramtype', 'type'), can_collapse=True), Field('returnvalue', label=_('Returns'), has_arg=False, names=('returns', 'return')), Field('yieldvalue', label=_('Yields'), has_arg=False, names=('yields', 'yield')), Field('returntype', label=_('Return type'), has_arg=False, names=('rtype',)), Field('yieldtype', label=_('Yield type'), has_arg=False, names=('ytype',)), GroupedField('errorhandling', label=_('Throws'), names=('throw', 'throws'), can_collapse=True), ] @staticmethod def _pseudo_parse_arglist(signode, arglist): """Parse list of comma separated arguments. Arguments can have optional types. """ paramlist = addnodes.desc_parameterlist() stack = [paramlist] try: for argument in arglist.split(','): argument = argument.strip() ends_open = 0 ends_close = 0 while argument.startswith('['): stack.append(addnodes.desc_optional()) stack[-2] += stack[-1] argument = argument[1:].strip() while argument.startswith(']'): stack.pop() argument = argument[1:].strip() while argument.endswith(']') and not argument.endswith('[]'): ends_close += 1 argument = argument[:-1].strip() while argument.endswith('['): ends_open += 1 argument = argument[:-1].strip() if argument: stack[-1] += addnodes.desc_parameter(argument, argument) while ends_open: stack.append(addnodes.desc_optional()) stack[-2] += stack[-1] ends_open -= 1 while ends_close: stack.pop() ends_close -= 1 if len(stack) != 1: raise IndexError except IndexError: # If there are too few or too many elements on the stack, just give # up and treat the whole argument list as one argument, discarding # the already partially populated paramlist node. signode += addnodes.desc_parameterlist() signode[-1] += addnodes.desc_parameter(arglist, arglist) else: signode += paramlist def _get_attr_like_prefix(self, sig): """Return prefix text for attribute or data directive.""" sig_match = chpl_attr_sig_pattern.match(sig) if sig_match is None: return ChapelObject.get_signature_prefix(self, sig) prefixes, _, _, _ = sig_match.groups() if prefixes: return prefixes.strip() + ' ' elif self.objtype == 'type': return 'type' + ' ' else: return ChapelObject.get_signature_prefix(self, sig) def _get_proc_like_prefix(self, sig): """Return prefix text for function or method directive (and similar). """ sig_match = chpl_sig_pattern.match(sig) if sig_match is None: return ChapelObject.get_signature_prefix(self, sig) prefixes, _, _, _, _ = sig_match.groups() if prefixes: return prefixes.strip() + ' ' elif self.objtype.startswith('iter'): return 'iter' + ' ' elif self.objtype in ('method', 'function'): return 'proc' + ' ' else: return ChapelObject.get_signature_prefix(self, sig) def _is_attr_like(self): """Returns True when objtype is attribute or data.""" return self.objtype in ('attribute', 'data', 'type', 'enum') def _is_proc_like(self): """Returns True when objtype is *function or *method.""" return (self.objtype in ('function', 'iterfunction', 'method', 'itermethod')) def _get_sig_prefix(self, sig): """Return signature prefix text. For attribute, data, and proc/iter directives this might be part of the signature. E.g. `type myNewType` will return a prefix of 'type' and `inline proc foo()` will return 'inline proc'. """ if self._is_proc_like(): return self._get_proc_like_prefix(sig) elif self._is_attr_like(): return self._get_attr_like_prefix(sig) else: return ChapelObject.get_signature_prefix(self, sig) def get_signature_prefix(self, sig): """May return a prefix to put before the object name in the signature. """ return '' def needs_arglist(self): """May return True if an empty argument list is to be generated even if the document contains none. """ return False def handle_signature(self, sig, signode): """Parse the signature *sig* into individual nodes and append them to the *signode*. If ValueError is raises, parsing is aborted and the whole *sig* string is put into a single desc_name node. The return value is the value that identifies the object. IOW, it is the identifier that will be used to reference this object, datum, attribute, proc, etc. It is a tuple of "fullname" (including module and class(es)) and the classes. See also :py:meth:`add_target_and_index`. """ if self._is_attr_like(): sig_match = chpl_attr_sig_pattern.match(sig) if sig_match is None: raise ValueError('Signature does not parse: {0}'.format(sig)) func_prefix, name_prefix, name, retann = sig_match.groups() arglist = None else: sig_match = chpl_sig_pattern.match(sig) if sig_match is None: raise ValueError('Signature does not parse: {0}'.format(sig)) func_prefix, name_prefix, name, arglist, retann = \ sig_match.groups() modname = self.options.get( 'module', self.env.temp_data.get('chpl:module')) classname = self.env.temp_data.get('chpl:class') if classname: if name_prefix and name_prefix.startswith(classname): fullname = name_prefix + name # class name is given again in the signature name_prefix = name_prefix[len(classname):].lstrip('.') elif name_prefix: # class name is given in the signature, but different # (shouldn't happen) fullname = classname + '.' + name_prefix + name else: # class name is not given in the signature fullname = classname + '.' + name else: if name_prefix: classname = name_prefix.rstrip('.') fullname = name_prefix + name else: classname = '' fullname = name signode['module'] = modname signode['class'] = classname signode['fullname'] = fullname sig_prefix = self.get_signature_prefix(sig) if sig_prefix: signode += addnodes.desc_annotation(sig_prefix, sig_prefix) # if func_prefix: # signode += addnodes.desc_addname(func_prefix, func_prefix) if name_prefix: signode += addnodes.desc_addname(name_prefix, name_prefix) anno = self.options.get('annotation') signode += addnodes.desc_name(name, name) if not arglist: # If this needs an arglist, and parens were provided in the # signature, add a parameterlist. Chapel supports paren-less # functions and methods, which can act as computed properties. If # arglist is the empty string, the signature included parens. If # arglist is None, it did not include parens. if self.needs_arglist() and arglist is not None: # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() if retann: signode += addnodes.desc_type(retann, retann) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, name_prefix self._pseudo_parse_arglist(signode, arglist) if retann: signode += addnodes.desc_type(retann, retann) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, name_prefix def get_index_text(self, modname, name): """Return the text for the index entry of the object.""" raise NotImplementedError('must be implemented in subclasses') def add_target_and_index(self, name_cls, sig, signode): """Add cross-reference IDs and entries to the index node, if applicable. *name_cls* is the return value of :py:meth:`handle_signature`. """ modname = self.options.get( 'module', self.env.temp_data.get('chpl:module')) fullname = (modname and modname + '.' or '') + name_cls[0] # note target if fullname not in self.state.document.ids: signode['names'].append(fullname) signode['ids'].append(fullname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) objects = self.env.domaindata['chpl']['objects'] if fullname in objects: self.state_machine.reporter.warning( 'duplicate object description of %s, ' % fullname + 'other instance in ' + self.env.doc2path(objects[fullname][0]) + ', use :noindex: for one of them', line=self.lineno) objects[fullname] = (self.env.docname, self.objtype) indextext = self.get_index_text(modname, name_cls) if indextext: self.indexnode['entries'].append(('single', indextext, fullname, '', None)) def before_content(self): """Called before parsing content. Set flag to help with class scoping. """ self.clsname_set = False def after_content(self): """Called after parsing content. If any classes were added to the env temp_data, make sure they are removed. """ if self.clsname_set: self.env.temp_data.pop('chpl:class', None)
class PyObject(ObjectDescription): """ Description of a general Python object. :cvar allow_nesting: Class is an object that allows for nested namespaces :vartype allow_nesting: bool """ option_spec = { 'noindex': directives.flag, 'module': directives.unchanged, 'annotation': directives.unchanged, } doc_field_types = [ PyTypedField('parameter', label=_('Parameters'), names=('param', 'parameter', 'arg', 'argument', 'keyword', 'kwarg', 'kwparam'), typerolename='class', typenames=('paramtype', 'type'), can_collapse=True), PyTypedField('variable', label=_('Variables'), rolename='obj', names=('var', 'ivar', 'cvar'), typerolename='class', typenames=('vartype',), can_collapse=True), PyGroupedField('exceptions', label=_('Raises'), rolename='exc', names=('raises', 'raise', 'exception', 'except'), can_collapse=True), Field('returnvalue', label=_('Returns'), has_arg=False, names=('returns', 'return')), PyField('returntype', label=_('Return type'), has_arg=False, names=('rtype',), bodyrolename='class'), ] allow_nesting = False def get_signature_prefix(self, sig: str) -> str: """May return a prefix to put before the object name in the signature. """ return '' def needs_arglist(self) -> bool: """May return true if an empty argument list is to be generated even if the document contains none. """ return False def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]: """Transform a Python signature into RST nodes. Return (fully qualified name of the thing, classname if any). If inside a class, the current class name is handled intelligently: * it is stripped from the displayed name if present * it is added to the full name (return value) if not present """ m = py_sig_re.match(sig) if m is None: raise ValueError prefix, name, arglist, retann = m.groups() # determine module and class name (if applicable), as well as full name modname = self.options.get('module', self.env.ref_context.get('py:module')) classname = self.env.ref_context.get('py:class') if classname: add_module = False if prefix and (prefix == classname or prefix.startswith(classname + ".")): fullname = prefix + name # class name is given again in the signature prefix = prefix[len(classname):].lstrip('.') elif prefix: # class name is given in the signature, but different # (shouldn't happen) fullname = classname + '.' + prefix + name else: # class name is not given in the signature fullname = classname + '.' + name else: add_module = True if prefix: classname = prefix.rstrip('.') fullname = prefix + name else: classname = '' fullname = name signode['module'] = modname signode['class'] = classname signode['fullname'] = fullname sig_prefix = self.get_signature_prefix(sig) if sig_prefix: signode += addnodes.desc_annotation(sig_prefix, sig_prefix) if prefix: signode += addnodes.desc_addname(prefix, prefix) elif add_module and self.env.config.add_module_names: if modname and modname != 'exceptions': # exceptions are a special case, since they are documented in the # 'exceptions' module. nodetext = modname + '.' signode += addnodes.desc_addname(nodetext, nodetext) signode += addnodes.desc_name(name, name) if arglist: try: signode += _parse_arglist(arglist) except SyntaxError: # fallback to parse arglist original parser. # it supports to represent optional arguments (ex. "func(foo [, bar])") _pseudo_parse_arglist(signode, arglist) except NotImplementedError as exc: logger.warning("could not parse arglist (%r): %s", arglist, exc) _pseudo_parse_arglist(signode, arglist) else: if self.needs_arglist(): # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() if retann: signode += addnodes.desc_returns(retann, retann) anno = self.options.get('annotation') if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, prefix def get_index_text(self, modname: str, name: Tuple[str, str]) -> str: """Return the text for the index entry of the object.""" raise NotImplementedError('must be implemented in subclasses') def add_target_and_index(self, name_cls: Tuple[str, str], sig: str, signode: desc_signature) -> None: modname = self.options.get('module', self.env.ref_context.get('py:module')) fullname = (modname + '.' if modname else '') + name_cls[0] node_id = make_id(self.env, self.state.document, modname or '', name_cls[0]) signode['ids'].append(node_id) # Assign old styled node_id(fullname) not to break old hyperlinks (if possible) # Note: Will removed in Sphinx-5.0 (RemovedInSphinx50Warning) if node_id != fullname and fullname not in self.state.document.ids: signode['ids'].append(fullname) self.state.document.note_explicit_target(signode) domain = cast(PythonDomain, self.env.get_domain('py')) domain.note_object(fullname, self.objtype, node_id, location=signode) indextext = self.get_index_text(modname, name_cls) if indextext: self.indexnode['entries'].append(('single', indextext, node_id, '', None)) def before_content(self) -> None: """Handle object nesting before content :py:class:`PyObject` represents Python language constructs. For constructs that are nestable, such as a Python classes, this method will build up a stack of the nesting heirarchy so that it can be later de-nested correctly, in :py:meth:`after_content`. For constructs that aren't nestable, the stack is bypassed, and instead only the most recent object is tracked. This object prefix name will be removed with :py:meth:`after_content`. """ prefix = None if self.names: # fullname and name_prefix come from the `handle_signature` method. # fullname represents the full object name that is constructed using # object nesting and explicit prefixes. `name_prefix` is the # explicit prefix given in a signature (fullname, name_prefix) = self.names[-1] if self.allow_nesting: prefix = fullname elif name_prefix: prefix = name_prefix.strip('.') if prefix: self.env.ref_context['py:class'] = prefix if self.allow_nesting: classes = self.env.ref_context.setdefault('py:classes', []) classes.append(prefix) if 'module' in self.options: modules = self.env.ref_context.setdefault('py:modules', []) modules.append(self.env.ref_context.get('py:module')) self.env.ref_context['py:module'] = self.options['module'] def after_content(self) -> None: """Handle object de-nesting after content If this class is a nestable object, removing the last nested class prefix ends further nesting in the object. If this class is not a nestable object, the list of classes should not be altered as we didn't affect the nesting levels in :py:meth:`before_content`. """ classes = self.env.ref_context.setdefault('py:classes', []) if self.allow_nesting: try: classes.pop() except IndexError: pass self.env.ref_context['py:class'] = (classes[-1] if len(classes) > 0 else None) if 'module' in self.options: modules = self.env.ref_context.setdefault('py:modules', []) if modules: self.env.ref_context['py:module'] = modules.pop() else: self.env.ref_context.pop('py:module')
class PyObject(ObjectDescription): """ Description of a general Python object. """ option_spec = { 'noindex': directives.flag, 'module': directives.unchanged, 'annotation': directives.unchanged, } doc_field_types = [ PyTypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument', 'keyword', 'kwarg', 'kwparam'), typerolename='obj', typenames=('paramtype', 'type'), can_collapse=True), PyTypedField('variable', label=l_('Variables'), rolename='obj', names=('var', 'ivar', 'cvar'), typerolename='obj', typenames=('vartype', ), can_collapse=True), PyGroupedField('exceptions', label=l_('Raises'), rolename='exc', names=('raises', 'raise', 'exception', 'except'), can_collapse=True), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), PyField('returntype', label=l_('Return type'), has_arg=False, names=('rtype', ), bodyrolename='obj'), ] def get_signature_prefix(self, sig): # type: (unicode) -> unicode """May return a prefix to put before the object name in the signature. """ return '' def needs_arglist(self): # type: () -> bool """May return true if an empty argument list is to be generated even if the document contains none. """ return False def handle_signature(self, sig, signode): # type: ignore # type: (unicode, addnodes.desc_signature) -> Tuple[unicode, unicode] """Transform a Python signature into RST nodes. Return (fully qualified name of the thing, classname if any). If inside a class, the current class name is handled intelligently: * it is stripped from the displayed name if present * it is added to the full name (return value) if not present """ m = py_sig_re.match(sig) # type: ignore if m is None: raise ValueError name_prefix, name, arglist, retann = m.groups() # determine module and class name (if applicable), as well as full name modname = self.options.get('module', self.env.ref_context.get('py:module')) classname = self.env.ref_context.get('py:class') if classname: add_module = False if name_prefix and name_prefix.startswith(classname): fullname = name_prefix + name # class name is given again in the signature name_prefix = name_prefix[len(classname):].lstrip('.') elif name_prefix: # class name is given in the signature, but different # (shouldn't happen) fullname = classname + '.' + name_prefix + name else: # class name is not given in the signature fullname = classname + '.' + name else: add_module = True if name_prefix: classname = name_prefix.rstrip('.') fullname = name_prefix + name else: classname = '' fullname = name signode['module'] = modname signode['class'] = classname signode['fullname'] = fullname sig_prefix = self.get_signature_prefix(sig) if sig_prefix: signode += addnodes.desc_annotation(sig_prefix, sig_prefix) if name_prefix: signode += addnodes.desc_addname(name_prefix, name_prefix) # exceptions are a special case, since they are documented in the # 'exceptions' module. elif add_module and self.env.config.add_module_names: modname = self.options.get('module', self.env.ref_context.get('py:module')) if modname and modname != 'exceptions': nodetext = modname + '.' signode += addnodes.desc_addname(nodetext, nodetext) anno = self.options.get('annotation') signode += addnodes.desc_name(name, name) if not arglist: if self.needs_arglist(): # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() if retann: signode += addnodes.desc_returns(retann, retann) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, name_prefix _pseudo_parse_arglist(signode, arglist) if retann: signode += addnodes.desc_returns(retann, retann) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, name_prefix def get_index_text(self, modname, name): # type: (unicode, unicode) -> unicode """Return the text for the index entry of the object.""" raise NotImplementedError('must be implemented in subclasses') def add_target_and_index(self, name_cls, sig, signode): # type: (unicode, unicode, addnodes.desc_signature) -> None modname = self.options.get('module', self.env.ref_context.get('py:module')) fullname = (modname and modname + '.' or '') + name_cls[0] # note target if fullname not in self.state.document.ids: signode['names'].append(fullname) signode['ids'].append(fullname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) objects = self.env.domaindata['py']['objects'] if fullname in objects: self.state_machine.reporter.warning( 'duplicate object description of %s, ' % fullname + 'other instance in ' + self.env.doc2path(objects[fullname][0]) + ', use :noindex: for one of them', line=self.lineno) objects[fullname] = (self.env.docname, self.objtype) indextext = self.get_index_text(modname, name_cls) if indextext: self.indexnode['entries'].append( ('single', indextext, fullname, '', None)) def before_content(self): # type: () -> None # needed for automatic qualification of members (reset in subclasses) self.clsname_set = False def after_content(self): # type: () -> None if self.clsname_set: self.env.ref_context.pop('py:class', None)
def __init__(self, name, names=(), label=None, rolename=None): Field.__init__(self, name, names, label, False, rolename)
class CPPObject(ObjectDescription): """Description of a C++ language object.""" doc_field_types = [ GroupedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument'), can_collapse=True), GroupedField('exceptions', label=l_('Throws'), rolename='cpp:class', names=('throws', 'throw', 'exception'), can_collapse=True), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), ] def attach_name(self, node, name): owner, name = name.split_owner() varname = unicode(name) if owner is not None: owner = unicode(owner) + '::' node += addnodes.desc_addname(owner, owner) node += addnodes.desc_name(varname, varname) def attach_type_suffixes(self, node, suffixes): for suffix in suffixes: node += nodes.Text(unicode(suffix)) def attach_type(self, node, type): # XXX: link to c? text = unicode(type) pnode = addnodes.pending_xref( '', refdomain='cpp', reftype='type', reftarget=text, modname=None, classname=None) pnode['cpp:parent'] = self.env.temp_data.get('cpp:parent') pnode += nodes.Text(text) node += pnode def attach_modifiers(self, node, obj, visibility='public'): if obj.visibility != visibility: node += addnodes.desc_annotation(obj.visibility, obj.visibility) node += nodes.Text(' ') if obj.static: node += addnodes.desc_annotation('static', 'static') node += nodes.Text(' ') if getattr(obj, 'constexpr', False): node += addnodes.desc_annotation('constexpr', 'constexpr') node += nodes.Text(' ') def add_target_and_index(self, sigobj, sig, signode): theid = sigobj.get_id() name = unicode(sigobj.name) if theid not in self.state.document.ids: signode['names'].append(theid) signode['ids'].append(theid) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) self.env.domaindata['cpp']['objects'].setdefault(name, (self.env.docname, self.objtype, theid)) indextext = self.get_index_text(name) if indextext: self.indexnode['entries'].append(('single', indextext, theid, '')) def before_content(self): lastname = self.names and self.names[-1] if lastname and not self.env.temp_data.get('cpp:parent'): assert isinstance(lastname, NamedDefExpr) self.env.temp_data['cpp:parent'] = lastname.name self.parentname_set = True else: self.parentname_set = False def after_content(self): if self.parentname_set: self.env.temp_data['cpp:parent'] = None def parse_definition(self, parser): raise NotImplementedError() def describe_signature(self, signode, arg): raise NotImplementedError() def handle_signature(self, sig, signode): parser = DefinitionParser(sig) try: rv = self.parse_definition(parser) parser.assert_end() except DefinitionError, e: self.state_machine.reporter.warning(e.description, line=self.lineno) raise ValueError self.describe_signature(signode, rv) parent = self.env.temp_data.get('cpp:parent') if parent is not None: rv = rv.clone() rv.name = rv.name.prefix(parent) return rv
class JavaMethod(JavaObject): doc_field_types = [ TypedField( 'parameter', label=_('Parameters'), # replaced the old "label=l_('Parameters')" names=('param', 'parameter', 'arg', 'argument'), typerolename='type', typenames=('type', )), Field( 'returnvalue', label=_('Returns'), # replaced the old "label=l_('Returns')" has_arg=False, names=('returns', 'return')), GroupedField( 'throws', names=('throws', ), label=_('Throws'), # replaced the old "label=l_('Throws')" rolename='type') ] def handle_method_signature(self, sig, signode): try: member = javalang.parse.parse_member_signature(sig) except javalang.parser.JavaSyntaxError: raise self.error("syntax error in method signature") if not isinstance(member, javalang.tree.MethodDeclaration): raise self.error("expected method declaration") mods = formatter.output_modifiers(member.modifiers).build() signode += nodes.Text(mods + ' ', mods + ' ') if member.type_parameters: type_params = formatter.output_type_params( member.type_parameters).build() signode += nodes.Text(type_params, type_params) signode += nodes.Text(' ', ' ') rnode = addnodes.desc_type('', '') rnode += self._build_type_node(member.return_type) signode += rnode signode += nodes.Text(' ', ' ') signode += addnodes.desc_name(member.name, member.name) paramlist = addnodes.desc_parameterlist() for parameter in member.parameters: param = addnodes.desc_parameter('', '', noemph=True) param += self._build_type_node(parameter.type) if parameter.varargs: param += nodes.Text('...', '') param += nodes.emphasis(' ' + parameter.name, ' ' + parameter.name) paramlist += param signode += paramlist param_reprs = [ formatter.output_type(param.type, with_generics=False).build() for param in member.parameters ] return member.name + '(' + ', '.join(param_reprs) + ')' def get_index_text(self, package, type, name): return _('%s (Java method)' % (name, ))
class PhpObject(ObjectDescription): """ Description of a general PHP object. """ option_spec = { 'noindex': directives.flag, 'module': directives.unchanged, } doc_field_types = [ TypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument'), typerolename='obj', typenames=('paramtype', 'type')), TypedField('variable', label=l_('Variables'), rolename='obj', names=('var', 'ivar', 'cvar'), typerolename='obj', typenames=('vartype',)), GroupedField('exceptions', label=l_('Throws'), rolename='exc', names=('throws', 'throw', 'exception', 'except'), can_collapse=True), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), Field('returntype', label=l_('Return type'), has_arg=False, names=('rtype', 'returntype')), ] def get_signature_prefix(self, sig): """ May return a prefix to put before the object name in the signature. """ return '' def needs_arglist(self): """ May return true if an empty argument list is to be generated even if the document contains none. """ return False def handle_signature(self, sig, signode): """ Transform a PHP signature into RST nodes. Returns (fully qualified name of the thing, classname if any). If inside a class, the current class name is handled intelligently: * it is stripped from the displayed name if present * it is added to the full name (return value) if not present """ m = php_sig_re.match(sig) if m is None: raise ValueError name_prefix, name, arglist, retann = m.groups() if not name_prefix: name_prefix = "" # determine module and class name (if applicable), as well as full name modname = self.options.get( 'namespace', self.env.temp_data.get('php:namespace')) classname = self.env.temp_data.get('php:class') separator = separators[self.objtype] if self.objtype == 'global' or self.objtype == 'function': add_module = False modname = None classname = None fullname = name else: add_module = True # name_prefix and a non-static method, means the classname was # repeated. Trim off the <class>:: if name_prefix and self.objtype != 'staticmethod': if name_prefix.startswith(classname): name_prefix = name_prefix[len(classname):].rstrip('::') classname = classname.rstrip('::') fullname = name_prefix + classname + separator + name elif name_prefix: classname = classname.rstrip('::') fullname = name_prefix + name # Currently in a class, but not creating another class, elif classname and not self.objtype in ['class', 'exception', 'interface', 'trait']: if not self.env.temp_data['php:in_class']: name_prefix = classname + separator fullname = classname + separator + name else: classname = '' fullname = name signode['namespace'] = modname signode['class'] = self.class_name = classname signode['fullname'] = fullname sig_prefix = self.get_signature_prefix(sig) if sig_prefix: signode += addnodes.desc_annotation(sig_prefix, sig_prefix) if name_prefix: if modname and not self.env.temp_data['php:in_class']: name_prefix = modname + NS + name_prefix signode += addnodes.desc_addname(name_prefix, name_prefix) elif add_module and self.env.config.add_module_names: if self.objtype == 'global': nodetext = '' signode += addnodes.desc_addname(nodetext, nodetext) else: modname = self.options.get( 'namespace', self.env.temp_data.get('php:namespace')) if modname and not self.env.temp_data.get('php:in_class', False): nodetext = modname + NS signode += addnodes.desc_addname(nodetext, nodetext) signode += addnodes.desc_name(name, name) if not arglist: if self.needs_arglist(): # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() if retann: signode += addnodes.desc_returns(retann, retann) return fullname, name_prefix signode += addnodes.desc_parameterlist() stack = [signode[-1]] for token in php_paramlist_re.split(arglist): if token == '[': opt = addnodes.desc_optional() stack[-1] += opt stack.append(opt) elif token == ']': try: stack.pop() except IndexError: raise ValueError elif not token or token == ',' or token.isspace(): pass else: token = token.strip() stack[-1] += addnodes.desc_parameter(token, token) if len(stack) != 1: raise ValueError if retann: signode += addnodes.desc_returns(retann, retann) return fullname, name_prefix def get_index_text(self, modname, name): """ Return the text for the index entry of the object. """ raise NotImplementedError('must be implemented in subclasses') def _is_class_member(self): return self.objtype.startswith('method') or self.objtype.startswith('attr') def add_target_and_index(self, name_cls, sig, signode): if self.objtype == 'global': modname = '' else: modname = self.options.get( 'namespace', self.env.temp_data.get('php:namespace')) separator = separators[self.objtype] if self._is_class_member(): if signode['class']: prefix = modname and modname + NS or '' else: prefix = modname and modname + NS or '' else: prefix = modname and modname + NS or '' fullname = prefix + name_cls[0] # note target if fullname not in self.state.document.ids: signode['names'].append(fullname) signode['ids'].append(fullname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) objects = self.env.domaindata['php']['objects'] if fullname in objects: self.env.warn( self.env.docname, 'duplicate object description of %s, ' % fullname + 'other instance in ' + self.env.doc2path(objects[fullname][0]), self.lineno) objects[fullname] = (self.env.docname, self.objtype) indextext = self.get_index_text(modname, name_cls) if indextext: self.indexnode['entries'].append(('single', indextext, fullname, fullname))
('index', slug, project, author, slug, project, 'Miscellaneous'), ] # Extensions to theme docs def setup(app): from sphinx.domains.python import PyField from sphinx.util.docfields import Field app.add_object_type( 'confval', 'confval', objname='configuration value', indextemplate='pair: %s; configuration value', doc_field_types=[ PyField( 'type', label=_('Type'), has_arg=False, names=('type',), bodyrolename='class' ), Field( 'default', label=_('Default'), has_arg=False, names=('default',), ), ] )
class AdaObject(ObjectDescription): """ Description of an Ada language object. """ doc_field_types = [ TypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument'), typerolename='type', typenames=('type', )), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), Field('returntype', label=l_('Return type'), has_arg=False, names=('rtype', )), ] def needs_arglist(self): return self.objtype == 'function' or self.objtype == 'procedure' def _resolve_module_name(self, signode, modname, name): env_modname = self.options.get( 'module', self.env.temp_data.get('ada:module', 'ada')) if modname: fullname = modname + name signode['module'] = modname[:-1] else: fullname = env_modname + '.' + name signode['module'] = env_modname signode['fullname'] = fullname name_prefix = signode['module'] + '.' signode += addnodes.desc_addname(name_prefix, name_prefix) signode += addnodes.desc_name(name, name) return fullname def _handle_function_signature(self, sig, signode): m = ada_func_sig_re.match(sig) if m is None: print("m did not match the function") raise ValueError modname, name, dummy, arglist, returntype, abstract = m.groups() fullname = self._resolve_module_name(signode, modname, name) if not arglist: if self.needs_arglist(): # for functions and procedures, add an empty parameter list new_node = addnodes.desc_parameterlist() new_node.child_text_separator = '; ' signode += new_node if returntype: signode += addnodes.desc_returns(returntype, returntype) return fullname signode += nodes.Text(' ') new_node = addnodes.desc_parameterlist() new_node.child_text_separator = '; ' signode += new_node stack = [signode[-1]] counters = [0, 0] for token in string.split(arglist, ';'): pieces = string.split(token, ':') name = pieces[0].strip() stack[-1] += addnodes.desc_parameter( name, name + " : " + pieces[1].strip()) if len(stack) == 1: counters[0] += 1 else: counters[1] += 1 if len(stack) != 1: raise ValueError if not counters[1]: fullname = '%s/%d' % (fullname, counters[0]) else: fullname = '%s/%d..%d' % (fullname, counters[0], sum(counters)) if returntype: signode += addnodes.desc_returns(returntype, returntype) return fullname def _handle_procedure_signature(self, sig, signode): m = ada_proc_sig_re.match(sig) if m is None: print("m did not match") raise ValueError modname, name, dummy, arglist, abstract = m.groups() fullname = self._resolve_module_name(signode, modname, name) if not arglist: if self.needs_arglist(): # for functions and procedures, add an empty parameter list newnode = addnodes.desc_parameterlist() newnode.child_text_separator = '; ' signode += newnode signode += nodes.Text(' ') newnode = addnodes.desc_parameterlist() newnode.child_text_separator = '; ' signode += newnode stack = [signode[-1]] counters = [0, 0] for token in string.split(arglist, ';'): pieces = string.split(token, ':') name = pieces[0].strip() stack[-1] += addnodes.desc_parameter( name, name + " : " + pieces[1].strip()) if len(stack) == 1: counters[0] += 1 else: counters[1] += 1 if len(stack) != 1: raise ValueError if not counters[1]: fullname = '%s/%d' % (fullname, counters[0]) else: fullname = '%s/%d..%d' % (fullname, counters[0], sum(counters)) return fullname def _handle_type_signature(self, sig, signode): m = ada_type_sig_re.match(sig) if m is None: print("m did not match") raise ValueError name, value = m.groups() fullname = self._resolve_module_name(signode, '', name) # signode += addnodes.desc_parameterlist() # stack = [signode[-1]] # signode += addnodes.desc_type(name, name + " is " + value) signode += addnodes.desc_type(name, '') return fullname def handle_signature(self, sig, signode): if sig.startswith('function'): return self._handle_function_signature(sig, signode) elif sig.startswith('type'): return self._handle_type_signature(sig, signode) else: # sig.startswith('procedure'): return self._handle_procedure_signature(sig, signode) def _get_index_text(self, name): if self.objtype == 'function': return _('%s (Ada function)') % name elif self.objtype == 'procedure': return _('%s (Ada procedure)') % name elif self.objtype == 'type': return _('%s (Ada type)') % name else: return '' def add_target_and_index(self, name, sig, signode): pieces = string.split(name, '.') if name not in self.state.document.ids: signode['names'].append(name) signode['ids'].append(name) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) if self.objtype == 'function': finv = self.env.domaindata['ada']['functions'] fname, arity = name.split('/') if '..' in arity: first, last = map(int, arity.split('..')) else: first = last = int(arity) for arity_index in range(first, last + 1): if fname in finv and arity_index in finv[fname]: self.env.warn( self.env.docname, ('duplicate Ada function description' 'of %s, ') % name + 'other instance in ' + self.env.doc2path(finv[fname][arity_index][0]), self.lineno) arities = finv.setdefault(fname, {}) arities[arity_index] = (self.env.docname, name) if self.objtype == 'procedure': finv = self.env.domaindata['ada']['procedures'] fname, arity = name.split('/') if '..' in arity: first, last = map(int, arity.split('..')) else: first = last = int(arity) for arity_index in range(first, last + 1): if fname in finv and arity_index in finv[fname]: self.env.warn( self.env.docname, ('duplicate Ada procedure description' 'of %s, ') % name + 'other instance in ' + self.env.doc2path(finv[fname][arity_index][0]), self.lineno) arities = finv.setdefault(fname, {}) arities[arity_index] = (self.env.docname, name) else: oinv = self.env.domaindata['ada']['objects'] if name in oinv: self.env.warn( self.env.docname, 'duplicate Ada object description of %s, ' % name + 'other instance in ' + self.env.doc2path(oinv[name][0]), self.lineno) oinv[name] = (self.env.docname, self.objtype) indextext = self._get_index_text(name) if indextext: self.indexnode['entries'].append(('single', indextext, name, name)) plain_name = pieces[-1] indextext = self._get_index_text(plain_name) if indextext: self.indexnode['entries'].append( ('single', indextext, name, plain_name))
def __init__(self, name, names=(), typenames=(), label=None, typerolename=None): Field.__init__(self, name, names, label, False, None) self.typenames = typenames self.typerolename = typerolename
class CephOption(ObjectDescription): """ emit option loaded from given command/options/<name>.yaml.in file """ has_content = True required_arguments = 1 optional_arguments = 0 final_argument_whitespace = False option_spec = { 'module': directives.unchanged, 'default': directives.unchanged } doc_field_types = [ Field('default', label=_('Default'), has_arg=False, names=('default', )), Field('type', label=_('Type'), has_arg=False, names=('type', ), bodyrolename='class'), ] template = jinja_template() opts: Dict[str, Dict[str, FieldValueT]] = {} mgr_opts: Dict[str, # module name Dict[str, # option name Dict[str, # field_name FieldValueT]]] = {} def _load_yaml(self) -> Dict[str, Dict[str, FieldValueT]]: if CephOption.opts: return CephOption.opts opts = [] for fn in status_iterator(self.config.ceph_confval_imports, 'loading options...', 'red', len(self.config.ceph_confval_imports), self.env.app.verbosity): self.env.note_dependency(fn) try: with open(fn, 'r') as f: yaml_in = io.StringIO() for line in f: if '@' not in line: yaml_in.write(line) yaml_in.seek(0) opts += yaml.safe_load(yaml_in)['options'] except OSError as e: message = f'Unable to open option file "{fn}": {e}' raise self.error(message) CephOption.opts = dict((opt['name'], opt) for opt in opts) return CephOption.opts def _normalize_path(self, dirname): my_dir = os.path.dirname(os.path.realpath(__file__)) src_dir = os.path.abspath(os.path.join(my_dir, '../..')) return os.path.join(src_dir, dirname) def _is_mgr_module(self, dirname, name): if not os.path.isdir(os.path.join(dirname, name)): return False if not os.path.isfile(os.path.join(dirname, name, '__init__.py')): return False return name not in ['tests'] @contextlib.contextmanager def mocked_modules(self): # src/pybind/mgr/tests from tests import mock mock_imports = [ 'rados', 'rbd', 'cephfs', 'dateutil', 'dateutil.parser' ] # make dashboard happy mock_imports += [ 'OpenSSL', 'jwt', 'bcrypt', 'jsonpatch', 'rook.rook_client', 'rook.rook_client.ceph', 'rook.rook_client._helper', 'cherrypy=3.2.3' ] # make diskprediction_local happy mock_imports += ['numpy', 'scipy'] # make restful happy mock_imports += [ 'pecan', 'pecan.rest', 'pecan.hooks', 'werkzeug', 'werkzeug.serving' ] for m in mock_imports: args = {} parts = m.split('=', 1) mocked = parts[0] if len(parts) > 1: args['__version__'] = parts[1] sys.modules[mocked] = mock.Mock(**args) try: yield finally: for m in mock_imports: mocked = m.split('=', 1)[0] sys.modules.pop(mocked) def _collect_options_from_module(self, name): with self.mocked_modules(): mgr_mod = __import__(name, globals(), locals(), [], 0) # import 'M' from src/pybind/mgr/tests from tests import M def subclass(x): try: return issubclass(x, M) except TypeError: return False ms = [ c for c in mgr_mod.__dict__.values() if subclass(c) and 'Standby' not in c.__name__ ] [m] = ms assert isinstance(m.MODULE_OPTIONS, list) return m.MODULE_OPTIONS def _load_module(self, module) -> Dict[str, Dict[str, FieldValueT]]: mgr_opts = CephOption.mgr_opts.get(module) if mgr_opts is not None: return mgr_opts python_path = self.config.ceph_confval_mgr_python_path for path in python_path.split(':'): sys.path.insert(0, self._normalize_path(path)) module_path = self.env.config.ceph_confval_mgr_module_path module_path = self._normalize_path(module_path) sys.path.insert(0, module_path) if not self._is_mgr_module(module_path, module): raise self.error( f'module "{module}" not found under {module_path}') fn = os.path.join(module_path, module, 'module.py') if os.path.exists(fn): self.env.note_dependency(fn) os.environ['UNITTEST'] = 'true' opts = self._collect_options_from_module(module) CephOption.mgr_opts[module] = dict((opt['name'], opt) for opt in opts) return CephOption.mgr_opts[module] def _current_module(self) -> str: return self.options.get('module', self.env.ref_context.get('ceph:module')) def _render_option(self, name) -> str: cur_module = self._current_module() if cur_module: opt = self._load_module(cur_module).get(name) else: opt = self._load_yaml().get(name) if opt is None: raise self.error(f'Option "{name}" not found!') if cur_module and 'type' not in opt: # the type of module option defaults to 'str' opt['type'] = 'str' desc = opt.get('fmt_desc') or opt.get('long_desc') or opt.get('desc') opt_default = opt.get('default') default = self.options.get('default', opt_default) try: return self.template.render(opt=opt, desc=desc, default=default) except Exception as e: message = (f'Unable to render option "{name}": {e}. ', f'opt={opt}, desc={desc}, default={default}') raise self.error(message) def handle_signature(self, sig: str, signode: addnodes.desc_signature) -> str: signode.clear() signode += addnodes.desc_name(sig, sig) # normalize whitespace like XRefRole does name = ws_re.sub(' ', sig) cur_module = self._current_module() if cur_module: return '/'.join(['mgr', cur_module, name]) else: return name def transform_content(self, contentnode: addnodes.desc_content) -> None: name = self.arguments[0] source, lineno = self.get_source_info() source = f'{source}:{lineno}:<confval>' fields = StringList(self._render_option(name).splitlines() + [''], source=source, parent_offset=lineno) with switch_source_input(self.state, fields): self.state.nested_parse(fields, 0, contentnode) def add_target_and_index(self, name: str, sig: str, signode: addnodes.desc_signature) -> None: node_id = make_id(self.env, self.state.document, self.objtype, name) signode['ids'].append(node_id) self.state.document.note_explicit_target(signode) entry = f'{name}; configuration option' self.indexnode['entries'].append(('pair', entry, node_id, '', None)) std = self.env.get_domain('std') std.note_object(self.objtype, name, node_id, location=signode)
def __init__(self, name, names=(), label=None, rolename=None, can_collapse=False): Field.__init__(self, name, names, label, True, rolename) self.can_collapse = can_collapse
class PyObject(ObjectDescription): """ Description of a general Python object. :cvar allow_nesting: Class is an object that allows for nested namespaces :vartype allow_nesting: bool """ option_spec = { 'noindex': directives.flag, 'module': directives.unchanged, 'annotation': directives.unchanged, } doc_field_types = [ PyTypedField('parameter', label=_('Parameters'), names=('param', 'parameter', 'arg', 'argument', 'keyword', 'kwarg', 'kwparam'), typerolename='class', typenames=('paramtype', 'type'), can_collapse=True), PyTypedField('variable', label=_('Variables'), rolename='obj', names=('var', 'ivar', 'cvar'), typerolename='class', typenames=('vartype',), can_collapse=True), PyGroupedField('exceptions', label=_('Raises'), rolename='exc', names=('raises', 'raise', 'exception', 'except'), can_collapse=True), Field('returnvalue', label=_('Returns'), has_arg=False, names=('returns', 'return')), PyField('returntype', label=_('Return type'), has_arg=False, names=('rtype',), bodyrolename='class'), ] allow_nesting = False def get_signature_prefix(self, sig): # type: (unicode) -> unicode """May return a prefix to put before the object name in the signature. """ return '' def needs_arglist(self): # type: () -> bool """May return true if an empty argument list is to be generated even if the document contains none. """ return False def handle_signature(self, sig, signode): # type: (unicode, addnodes.desc_signature) -> Tuple[unicode, unicode] """Transform a Python signature into RST nodes. Return (fully qualified name of the thing, classname if any). If inside a class, the current class name is handled intelligently: * it is stripped from the displayed name if present * it is added to the full name (return value) if not present """ m = py_sig_re.match(sig) # type: ignore if m is None: raise ValueError name_prefix, name, arglist, retann = m.groups() # determine module and class name (if applicable), as well as full name modname = self.options.get( 'module', self.env.ref_context.get('py:module')) classname = self.env.ref_context.get('py:class') if classname: add_module = False if name_prefix and name_prefix.startswith(classname): fullname = name_prefix + name # class name is given again in the signature name_prefix = name_prefix[len(classname):].lstrip('.') elif name_prefix: # class name is given in the signature, but different # (shouldn't happen) fullname = classname + '.' + name_prefix + name else: # class name is not given in the signature fullname = classname + '.' + name else: add_module = True if name_prefix: classname = name_prefix.rstrip('.') fullname = name_prefix + name else: classname = '' fullname = name signode['module'] = modname signode['class'] = classname signode['fullname'] = fullname sig_prefix = self.get_signature_prefix(sig) if sig_prefix: signode += addnodes.desc_annotation(sig_prefix, sig_prefix) if name_prefix: signode += addnodes.desc_addname(name_prefix, name_prefix) # exceptions are a special case, since they are documented in the # 'exceptions' module. elif add_module and self.env.config.add_module_names: modname = self.options.get( 'module', self.env.ref_context.get('py:module')) if modname and modname != 'exceptions': nodetext = modname + '.' signode += addnodes.desc_addname(nodetext, nodetext) anno = self.options.get('annotation') signode += addnodes.desc_name(name, name) if not arglist: if self.needs_arglist(): # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() if retann: signode += addnodes.desc_returns(retann, retann) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, name_prefix _pseudo_parse_arglist(signode, arglist) if retann: signode += addnodes.desc_returns(retann, retann) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, name_prefix def get_index_text(self, modname, name): # type: (unicode, unicode) -> unicode """Return the text for the index entry of the object.""" raise NotImplementedError('must be implemented in subclasses') def add_target_and_index(self, name_cls, sig, signode): # type: (unicode, unicode, addnodes.desc_signature) -> None modname = self.options.get( 'module', self.env.ref_context.get('py:module')) fullname = (modname and modname + '.' or '') + name_cls[0] # note target if fullname not in self.state.document.ids: signode['names'].append(fullname) signode['ids'].append(fullname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) objects = self.env.domaindata['py']['objects'] if fullname in objects: self.state_machine.reporter.warning( 'duplicate object description of %s, ' % fullname + 'other instance in ' + self.env.doc2path(objects[fullname][0]) + ', use :noindex: for one of them', line=self.lineno) objects[fullname] = (self.env.docname, self.objtype) indextext = self.get_index_text(modname, name_cls) if indextext: self.indexnode['entries'].append(('single', indextext, fullname, '', None)) def before_content(self): # type: () -> None """Handle object nesting before content :py:class:`PyObject` represents Python language constructs. For constructs that are nestable, such as a Python classes, this method will build up a stack of the nesting heirarchy so that it can be later de-nested correctly, in :py:meth:`after_content`. For constructs that aren't nestable, the stack is bypassed, and instead only the most recent object is tracked. This object prefix name will be removed with :py:meth:`after_content`. """ prefix = None if self.names: # fullname and name_prefix come from the `handle_signature` method. # fullname represents the full object name that is constructed using # object nesting and explicit prefixes. `name_prefix` is the # explicit prefix given in a signature (fullname, name_prefix) = self.names[-1] if self.allow_nesting: prefix = fullname elif name_prefix: prefix = name_prefix.strip('.') if prefix: self.env.ref_context['py:class'] = prefix if self.allow_nesting: classes = self.env.ref_context.setdefault('py:classes', []) classes.append(prefix) if 'module' in self.options: modules = self.env.ref_context.setdefault('py:modules', []) modules.append(self.env.ref_context.get('py:module')) self.env.ref_context['py:module'] = self.options['module'] def after_content(self): # type: () -> None """Handle object de-nesting after content If this class is a nestable object, removing the last nested class prefix ends further nesting in the object. If this class is not a nestable object, the list of classes should not be altered as we didn't affect the nesting levels in :py:meth:`before_content`. """ classes = self.env.ref_context.setdefault('py:classes', []) if self.allow_nesting: try: classes.pop() except IndexError: pass self.env.ref_context['py:class'] = (classes[-1] if len(classes) > 0 else None) if 'module' in self.options: modules = self.env.ref_context.setdefault('py:modules', []) if modules: self.env.ref_context['py:module'] = modules.pop() else: self.env.ref_context.pop('py:module')
class GolangObject(ObjectDescription): """ Description of a Golang language object. """ doc_field_types = [ TypedField('parameter', label=_('Parameters'), names=('param', 'parameter', 'arg', 'argument'), typerolename='type', typenames=('type', )), Field('returnvalue', label=_('Returns'), has_arg=False, names=('returns', 'return')), Field('returntype', label=_('Return type'), has_arg=False, names=('rtype', )), ] # These Go types aren't described anywhere, so don't try to create # a cross-reference to them stopwords = set(('const', 'int', 'uint', 'uintptr', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'string', 'error', '{}interface', '..{}interface')) def handle_signature(self, sig, signode): m = go_func_sig_re.match(sig) if m is not None: return self._handle_function_signature(sig, signode, m) m = go_sig_re.match(sig) if m is not None: return self._handle_general_signature(sig, signode, m) def _handle_general_signature(self, sig, signode, m): # determine package name, as well as full name # default package is 'builtin' env_pkgname = self.options.get( 'package', self.env.temp_data.get('go:package', 'builtin')) name, = m.groups() if '.' in name: pkgname, funcname = name.split('.', 1) name_prefix = pkgname + '.' signode += addnodes.desc_addname(name_prefix, name_prefix) signode += addnodes.desc_name(funcname, funcname) fullname = name else: fullname = "%s.%s" % (env_pkgname, name) signode += addnodes.desc_name(name, name) return fullname def _parse_type(self, node, gotype): # add cross-ref nodes for all words for part in filter(None, wsplit_re.split(gotype)): tnode = nodes.Text(part, part) if part[0] in string.ascii_letters+'_' and \ part not in self.stopwords: pnode = addnodes.pending_xref('', refdomain='go', reftype='type', reftarget=part, modname=None, classname=None) pnode += tnode node += pnode else: node += tnode def _resolve_package_name(self, signode, struct, name): # determine package name, as well as full name # default package is 'builtin' env_pkgname = self.options.get( 'package', self.env.temp_data.get('go:package', 'builtin')) fullname = "" if struct: signode += addnodes.desc_addname("(", "(") try: arg, typ = struct.split(' ', 1) signode += addnodes.desc_addname(arg + ' ', arg + u'\xa0') except ValueError: typ = struct signode += addnodes.desc_name(typ, typ) signode += addnodes.desc_addname(") ", ")" + u'\xa0') try: pkgname, typename = typ.split('.', 1) fullname = "(%s.%s) %s" % (pkgname, typename, name) signode['package'] = pkgname except ValueError: fullname = "(%s.%s) %s" % (env_pkgname, typ, name) signode['package'] = env_pkgname else: try: pkgname, funcname = name.split('.', 1) name = funcname name_prefix = pkgname + '.' signode += addnodes.desc_name(name_prefix, name_prefix) except ValueError: pkgname = env_pkgname funcname = name fullname = "%s.%s" % (pkgname, funcname) signode['package'] = pkgname signode += addnodes.desc_name(name, name) return fullname def _handle_function_signature(self, sig, signode, m): if m is None: raise ValueError struct, name, arglist, retann = m.groups() signode += addnodes.desc_addname("func ", "func" + u'\xa0') fullname = self._resolve_package_name(signode, struct, name) if not arglist: # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() else: paramlist = addnodes.desc_parameterlist() args = arglist.split(",") for arg in args: arg = arg.strip() param = addnodes.desc_parameter('', '', noemph=True) try: argname, gotype = arg.split(' ', 1) except ValueError: # no argument name given, only the type self._parse_type(param, arg) else: param += nodes.emphasis(argname + ' ', argname + u'\xa0') self._parse_type(param, gotype) # separate by non-breaking space in the output paramlist += param signode += paramlist if retann: signode += addnodes.desc_returns(retann, retann) return fullname def _get_index_text(self, name): if self.objtype == 'function': return _('%s (Golang function)') % name elif self.objtype == 'variable': return _('%s (Golang variable)') % name elif self.objtype == 'const': return _('%s (Golang const)') % name elif self.objtype == 'type': return _('%s (Golang type)') % name else: return '' def add_target_and_index(self, name, sig, signode): if name not in self.state.document.ids: signode['names'].append(name) signode['ids'].append(name) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) if self.objtype == 'function': finv = self.env.domaindata['go']['functions'] if name in finv: self.env.warn( self.env.docname, 'duplicate Golang object description of %s, ' % name + 'other instance in ' + self.env.doc2path(finv[name][0]), self.lineno) finv[name] = (self.env.docname, self.objtype) else: oinv = self.env.domaindata['go']['objects'] if name in oinv: self.env.warn( self.env.docname, 'duplicate Golang object description of %s, ' % name + 'other instance in ' + self.env.doc2path(oinv[name][0]), self.lineno) oinv[name] = (self.env.docname, self.objtype) indextext = self._get_index_text(name) if indextext: self.indexnode['entries'].append(('single', indextext, name, name))
class CObject(ObjectDescription): """ Description of a C language object. """ doc_field_types = [ TypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument'), typerolename='type', typenames=('type', )), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), Field('returntype', label=l_('Return type'), has_arg=False, names=('rtype', )), ] # These C types aren't described anywhere, so don't try to create # a cross-reference to them stopwords = set(( 'const', 'void', 'char', 'wchar_t', 'int', 'short', 'long', 'float', 'double', 'unsigned', 'signed', 'FILE', 'clock_t', 'time_t', 'ptrdiff_t', 'size_t', 'ssize_t', 'struct', '_Bool', )) def _parse_type(self, node, ctype): # type: (nodes.Node, unicode) -> None # add cross-ref nodes for all words for part in [_f for _f in wsplit_re.split(ctype) if _f]: # type: ignore tnode = nodes.Text(part, part) if part[0] in string.ascii_letters + '_' and \ part not in self.stopwords: pnode = addnodes.pending_xref('', refdomain='c', reftype='type', reftarget=part, modname=None, classname=None) pnode += tnode node += pnode else: node += tnode def _parse_arglist(self, arglist): # type: (unicode) -> Iterator[unicode] while True: m = c_funcptr_arg_sig_re.match(arglist) # type: ignore if m: yield m.group() arglist = c_funcptr_arg_sig_re.sub('', arglist) # type: ignore if ',' in arglist: _, arglist = arglist.split(',', 1) else: break else: if ',' in arglist: arg, arglist = arglist.split(',', 1) yield arg else: yield arglist break def handle_signature(self, sig, signode): # type: (unicode, addnodes.desc_signature) -> unicode """Transform a C signature into RST nodes.""" # first try the function pointer signature regex, it's more specific m = c_funcptr_sig_re.match(sig) # type: ignore if m is None: m = c_sig_re.match(sig) # type: ignore if m is None: raise ValueError('no match') rettype, name, arglist, const = m.groups() signode += addnodes.desc_type('', '') self._parse_type(signode[-1], rettype) try: classname, funcname = name.split('::', 1) classname += '::' signode += addnodes.desc_addname(classname, classname) signode += addnodes.desc_name(funcname, funcname) # name (the full name) is still both parts except ValueError: signode += addnodes.desc_name(name, name) # clean up parentheses from canonical name m = c_funcptr_name_re.match(name) if m: name = m.group(1) typename = self.env.ref_context.get('c:type') if self.name == 'c:member' and typename: fullname = typename + '.' + name else: fullname = name if not arglist: if self.objtype == 'function': # for functions, add an empty parameter list signode += addnodes.desc_parameterlist() if const: signode += addnodes.desc_addname(const, const) return fullname paramlist = addnodes.desc_parameterlist() arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup # this messes up function pointer types, but not too badly ;) for arg in self._parse_arglist(arglist): arg = arg.strip() param = addnodes.desc_parameter('', '', noemph=True) try: m = c_funcptr_arg_sig_re.match(arg) # type: ignore if m: self._parse_type(param, m.group(1) + '(') param += nodes.emphasis(m.group(2), m.group(2)) self._parse_type(param, ')(' + m.group(3) + ')') if m.group(4): param += addnodes.desc_addname(m.group(4), m.group(4)) else: ctype, argname = arg.rsplit(' ', 1) self._parse_type(param, ctype) # separate by non-breaking space in the output param += nodes.emphasis(' ' + argname, u'\xa0' + argname) except ValueError: # no argument name given, only the type self._parse_type(param, arg) paramlist += param signode += paramlist if const: signode += addnodes.desc_addname(const, const) return fullname def get_index_text(self, name): # type: (unicode) -> unicode if self.objtype == 'function': return _('%s (C function)') % name elif self.objtype == 'member': return _('%s (C member)') % name elif self.objtype == 'macro': return _('%s (C macro)') % name elif self.objtype == 'type': return _('%s (C type)') % name elif self.objtype == 'var': return _('%s (C variable)') % name else: return '' def add_target_and_index(self, name, sig, signode): # type: (unicode, unicode, addnodes.desc_signature) -> None # for C API items we add a prefix since names are usually not qualified # by a module name and so easily clash with e.g. section titles targetname = 'c.' + name if targetname not in self.state.document.ids: signode['names'].append(targetname) signode['ids'].append(targetname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) inv = self.env.domaindata['c']['objects'] if name in inv: self.state_machine.reporter.warning( 'duplicate C object description of %s, ' % name + 'other instance in ' + self.env.doc2path(inv[name][0]), line=self.lineno) inv[name] = (self.env.docname, self.objtype) indextext = self.get_index_text(name) if indextext: self.indexnode['entries'].append( ('single', indextext, targetname, '', None)) def before_content(self): # type: () -> None self.typename_set = False if self.name == 'c:type': if self.names: self.env.ref_context['c:type'] = self.names[0] self.typename_set = True def after_content(self): # type: () -> None if self.typename_set: self.env.ref_context.pop('c:type', None)
class BsvObject(ObjectDescription): """ Description of a general Bsv object. """ option_spec = { 'noindex': directives.flag, 'package': directives.unchanged, 'annotation': directives.unchanged, 'parameter': directives.unchanged, 'returntype': directives.unchanged, } doc_field_types = [ TypedField('parameter', label=l_('Parameters'), names=('param', 'parameter', 'arg', 'argument', 'keyword', 'kwarg', 'kwparam'), typerolename='obj', typenames=('paramtype', 'type'), can_collapse=True), TypedField('variable', label=l_('Variables'), rolename='obj', names=('var', 'ivar', 'cvar'), typerolename='obj', typenames=('vartype', ), can_collapse=True), GroupedField('exceptions', label=l_('Raises'), rolename='exc', names=('raises', 'raise', 'exception', 'except'), can_collapse=True), Field('returnvalue', label=l_('Returns'), has_arg=False, names=('returns', 'return')), Field('returntype', label=l_('Return type'), has_arg=False, names=('rtype', )), ] def get_signatures(self): siglines = ObjectDescription.get_signatures(self) return siglines def get_signature_prefix(self, sig): """May return a prefix to put before the object name in the signature. """ return '' def needs_arglist(self): """May return true if an empty argument list is to be generated even if the document contains none. """ return False def handle_signature(self, sig, signode): """Transform a Bsv signature into RST nodes. Return (fully qualified name of the thing, interfacename if any). If inside a interface, the current interface name is handled intelligently: * it is stripped from the displayed name if present * it is added to the full name (return value) if not present """ print('BsvObject.handle_signature', sig) name_prefix = '' name = sig arglist = '' retann = '' if self.objtype in ['interface', 'instance', 'typeclass']: split = sig.split('#', 1) name = split[0] if len(split) > 1: arglist = split[1] m = bsv_param_re.match(arglist) if m: arglist = m.group(1) elif self.objtype in ['subinterface', 'field']: split = sig.rsplit(' ', 1) print('rsplit', split) name = split[-1] if len(split) > 1: retann = split[0] elif self.objtype in ['method', 'function']: split = sig.split(' ', 1) retann = split[0] nameparams = split[1] split = nameparams.split('(', 1) name = split[0] if len(split) > 1: arglist = split[1][0:-1] elif self.objtype in ['module']: split = sig.split('#', 1) name = split[0] if len(split) > 1: depth = 0 paramreturn = split[1] #print('module', paramreturn, len(paramreturn)) for i in range(0, len(paramreturn)): c = paramreturn[i] if c == '(': depth = depth + 1 elif c == ')': depth = depth - 1 #print(i, c, depth) if depth == 0: endofparam = i break arglist = paramreturn[1:endofparam] retann = paramreturn[endofparam + 1:-1] #print(arglist) #print(endofparam, retann) # determine package and interface name (if applicable), as well as full name modname = self.options.get('package', self.env.temp_data.get('bsv:package')) interfacename = self.env.temp_data.get('bsv:interface') if interfacename: add_package = False if name_prefix and name_prefix.startswith(interfacename): fullname = name_prefix + name # interface name is given again in the signature name_prefix = name_prefix[len(interfacename):].lstrip('.') elif name_prefix: # interface name is given in the signature, but different # (shouldn't happen) fullname = interfacename + '.' + name_prefix + name else: # interface name is not given in the signature fullname = interfacename + '.' + name else: add_package = True if name_prefix: interfacename = name_prefix.rstrip('.') fullname = name_prefix + name else: interfacename = '' fullname = name signode['package'] = modname signode['interface'] = interfacename signode['fullname'] = fullname sig_prefix = self.get_signature_prefix(sig) if sig_prefix: signode += addnodes.desc_annotation(sig_prefix, sig_prefix) if name_prefix: signode += addnodes.desc_addname(name_prefix, name_prefix) # exceptions are a special case, since they are documented in the # 'exceptions' package. elif add_package and self.env.config.add_package_names: modname = self.options.get('package', self.env.temp_data.get('bsv:package')) if modname and modname != 'exceptions': nodetext = modname + '::' signode += addnodes.desc_addname(nodetext, nodetext) anno = self.options.get('annotation') signode += addnodes.desc_name(name, name) #print('arglist', arglist) if not arglist: if self.needs_arglist(): # for callables, add an empty parameter list if arglist: signode += addnodes.desc_parameterlist(text=arglist) elif self.options.get('parameter'): signode += addnodes.desc_parameterlist( text=self.options.get('parameter')) if retann: signode += addnodes.desc_returns(text=retann) elif self.options.get('returntype'): signode += addnodes.desc_returns( text=self.options.get('returntype')) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) #print('signode', signode) return fullname, name_prefix _pseudo_parse_arglist(signode, arglist) if retann: signode += addnodes.desc_returns(retann, retann) if anno: signode += addnodes.desc_annotation(' ' + anno, ' ' + anno) return fullname, name_prefix def get_index_text(self, modname, name): """Return the text for the index entry of the object.""" raise NotImplementedError('must be implemented in subinterfacees') def add_target_and_index(self, name_cls, sig, signode): modname = self.options.get('package', self.env.temp_data.get('bsv:package')) fullname = (modname and modname + '::' or '') + name_cls[0] # note target if fullname not in self.state.document.ids: signode['names'].append(fullname) signode['ids'].append(fullname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) objects = self.env.domaindata['bsv']['objects'] if fullname in objects: self.state_machine.reporter.warning( 'duplicate object description of %s, ' % fullname + 'other instance in ' + self.env.doc2path(objects[fullname][0]) + ', use :noindex: for one of them', line=self.lineno) objects[fullname] = (self.env.docname, self.objtype) indextext = self.get_index_text(modname, name_cls) if indextext: self.indexnode['entries'].append( ('single', indextext, fullname, '')) def before_content(self): # needed for automatic qualification of members (reset in subinterfacees) self.clsname_set = False def after_content(self): if self.clsname_set: self.env.temp_data['bsv:interface'] = None