def __init__(self, *args, **kargs): CPPDomain.__init__(self, *args, **kargs) self.directives['function'].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 add_target_and_index(self, name, sig, signode): targetparts = get_id_from_cfg(name) targetname = 'cfg_%s' % '_'.join(targetparts) signode['ids'].append(targetname) self.state.document.note_explicit_target(signode) indextype = 'single' # Generic index entries indexentry = self.indextemplate % (name,) self.indexnode['entries'].append((indextype, indexentry, targetname, targetname)) self.indexnode['entries'].append((indextype, name, targetname, targetname)) # Server section if targetparts[0] == 'Servers' and len(targetparts) > 1: indexname = ', '.join(targetparts[1:]) self.indexnode['entries'].append((indextype, l_('server configuration; %s') % indexname, targetname, targetname)) self.indexnode['entries'].append((indextype, indexname, targetname, targetname)) else: indexname = ', '.join(targetparts) self.indexnode['entries'].append((indextype, indexname, targetname, targetname)) self.env.domaindata['config']['objects'][self.objtype, name] = \ self.env.docname, targetname
def add_samples(): protocols = get_protocols( self.options.protocols or self.env.app.config.wsme_protocols ) content = [] if protocols: sample_obj = make_sample_object(self.object) content.extend([ l_(u'Data samples:'), u'', u'.. cssclass:: toggle', u'' ]) for name, protocol in protocols: language, sample = protocol.encode_sample_value( self.object, sample_obj, format=True) content.extend([ name, u' .. code-block:: ' + language, u'', ]) content.extend(( u' ' * 8 + line for line in sample.split('\n'))) for line in content: self.add_line(line, u'<wsmeext.sphinxext') self.add_line(u'', '<wsmeext.sphinxext>')
def get_index_text(self, modname, name_cls): if self.objtype == 'dirtymodel': label = l_(self.env.app.config.dirty_model_class_label or 'model') if not modname: return '%s (%s)' % (name_cls[0], label) return '%s (%s %s)' % (name_cls[0], modname, label) else: return ''
def setup(app): app.add_autodocumenter(ColumnAttributeDocumenter) app.add_autodocumenter(MapperDocumenter) domain = sphinx.domains.python.PythonDomain domain.object_types['mapper'] = sphinx.domains.python.ObjType( l_('mapper'), 'mapper', 'obj') domain.directives['mapper'] = MapperDirective domain.roles['mapper'] = sphinx.domains.python.PyXRefRole()
def get_doc_field_types(self): return [ TypedField(self.field_name, label=l_(self.field_label), names=(self.field_name,), typerolename='msg', typenames=('{0}-{1}'.format(self.field_name, TYPE_SUFFIX),)), TypedField(self.constant_name, label=l_(self.constant_label), names=(self.constant_name,), typerolename='msg', typenames=('{0}-{1}'.format(self.constant_name, TYPE_SUFFIX),)), GroupedField('{0}-{1}'.format(self.constant_name, VALUE_SUFFIX), label=l_('{0} (Value)'.format(self.constant_label)), names=('{0}-{1}'.format(self.constant_name, VALUE_SUFFIX),)), ]
def setup(app): app.add_autodoc_attrgetter(zope.interface.interface.InterfaceClass, interface_getattr) app.add_autodocumenter(InterfaceDocumenter) app.add_autodocumenter(InterfaceAttributeDocumenter) app.add_autodocumenter(InterfaceMethodDocumenter) domain = sphinx.domains.python.PythonDomain domain.object_types['interface'] = sphinx.domains.python.ObjType( l_('interface'), 'interface', 'obj') domain.directives['interface'] = InterfaceDirective domain.roles['interface'] = sphinx.domains.python.PyXRefRole()
def get_index_text(self, modname, name_cls): name, cls = name_cls add_modules = self.env.config.add_module_names if self.objtype == 'dirtymodelattribute': label = l_(self.env.app.config.dirty_model_property_label or 'attribute') clsname, attrname = name.rsplit('.', 1) if modname and add_modules: return '%s (%s.%s %s)' % (attrname, modname, clsname, label) else: return '%s (%s %s)' % (attrname, clsname, label) else: return ''
def setup(app): app.add_autodocumenter(DirtyModelDocumenter) app.add_autodocumenter(DirtyModelAttributeDocumenter) app.add_config_value('dirty_model_add_classes_to_toc', True, True) app.add_config_value('dirty_model_add_attributes_to_toc', True, True) app.add_config_value('dirty_model_class_label', 'Model', True) app.add_config_value('dirty_model_property_label', 'property', True) app.add_config_value('dirty_model_field_type_as_annotation', True, True) app.connect('doctree-read', process_dirty_model_toc) domain = sphinx.domains.python.PythonDomain domain.object_types['dirtymodel'] = sphinx.domains.python.ObjType( l_('Model'), 'dirtymodel', 'obj') domain.directives['dirtymodel'] = DirtyModelDirective domain.roles['dirtymodel'] = sphinx.domains.python.PyXRefRole() domain.object_types['dirtymodelattribute'] = sphinx.domains.python.ObjType( l_('Attribute'), 'dirtymodelattribute', 'obj') domain.directives['dirtymodelattribute'] = DirtyModelAttributeDirective domain.roles['dirtymodelattribute'] = sphinx.domains.python.PyXRefRole()
def setup(app): # builders app.add_builder(StandaloneHTMLBuilder) app.add_builder(DirectoryHTMLBuilder) app.add_builder(SingleFileHTMLBuilder) app.add_builder(PickleHTMLBuilder) app.add_builder(JSONHTMLBuilder) # config values app.add_config_value('html_theme', 'alabaster', 'html') app.add_config_value('html_theme_path', [], 'html') app.add_config_value('html_theme_options', {}, 'html') app.add_config_value('html_title', lambda self: l_('%s %s documentation') % (self.project, self.release), 'html', string_classes) app.add_config_value('html_short_title', lambda self: self.html_title, 'html') app.add_config_value('html_style', None, 'html', string_classes) app.add_config_value('html_logo', None, 'html', string_classes) app.add_config_value('html_favicon', None, 'html', string_classes) app.add_config_value('html_static_path', [], 'html') app.add_config_value('html_extra_path', [], 'html') app.add_config_value('html_last_updated_fmt', None, 'html', string_classes) app.add_config_value('html_use_smartypants', True, 'html') app.add_config_value('html_translator_class', None, 'html', string_classes) app.add_config_value('html_sidebars', {}, 'html') app.add_config_value('html_additional_pages', {}, 'html') app.add_config_value('html_use_modindex', True, 'html') # deprecated app.add_config_value('html_domain_indices', True, 'html', [list]) app.add_config_value('html_add_permalinks', u'\u00B6', 'html') app.add_config_value('html_use_index', True, 'html') app.add_config_value('html_split_index', False, 'html') app.add_config_value('html_copy_source', True, 'html') app.add_config_value('html_show_sourcelink', True, 'html') app.add_config_value('html_sourcelink_suffix', '.txt', 'html') app.add_config_value('html_use_opensearch', '', 'html') app.add_config_value('html_file_suffix', None, 'html', string_classes) app.add_config_value('html_link_suffix', None, 'html', string_classes) app.add_config_value('html_show_copyright', True, 'html') app.add_config_value('html_show_sphinx', True, 'html') app.add_config_value('html_context', {}, 'html') app.add_config_value('html_output_encoding', 'utf-8', 'html') app.add_config_value('html_compact_lists', True, 'html') app.add_config_value('html_secnumber_suffix', '. ', 'html') app.add_config_value('html_search_language', None, 'html', string_classes) app.add_config_value('html_search_options', {}, 'html') app.add_config_value('html_search_scorer', '', None) app.add_config_value('html_scaled_image_link', True, 'html')
def render_domain_data(mongodb_directives): directives = { } roles = { } object_types = { } for directive in mongodb_directives: reftype = directive['name'] roles[reftype] = MongoDBXRefRole() object_types[reftype] = ObjType(l_(reftype), reftype) if directive['callable']: directives[reftype] = MongoDBMethod else: directives[reftype] = MongoDBObject return directives, roles, object_types
def handle_signature(self, sig, signode): result = super(DirtyModelAttributeDirective, self).handle_signature(sig, signode) if self.options.get('annotation'): anno = addnodes.desc_annotation() old_node = signode[2] if not isinstance(old_node, addnodes.desc_annotation): old_node = signode[3] del signode[1] old_node.replace_self(anno) self.state.nested_parse(ViewList([': ', self.options.get('annotation')]), 0, anno) readonly = 'readonly' in self.options if readonly: signode['classes'].append('readonly') t = ' [{}]'.format(l_('READ ONLY')) signode += nodes.emphasis(t, t, classes=['readonly-label']) return result
class PythonDomain(Domain): """Python language domain.""" name = 'py' label = 'Python' object_types = { 'function': ObjType(l_('function'), 'func', 'obj'), 'data': ObjType(l_('data'), 'data', 'obj'), 'class': ObjType(l_('class'), 'class', 'exc', 'obj'), 'exception': ObjType(l_('exception'), 'exc', 'class', 'obj'), 'method': ObjType(l_('method'), 'meth', 'obj'), 'classmethod': ObjType(l_('class method'), 'meth', 'obj'), 'staticmethod': ObjType(l_('static method'), 'meth', 'obj'), 'attribute': ObjType(l_('attribute'), 'attr', 'obj'), 'module': ObjType(l_('module'), 'mod', 'obj'), } # type: Dict[unicode, ObjType] directives = { 'function': PyModulelevel, 'data': PyModulelevel, 'class': PyClasslike, 'exception': PyClasslike, 'method': PyClassmember, 'classmethod': PyClassmember, 'staticmethod': PyClassmember, 'attribute': PyClassmember, 'module': PyModule, 'currentmodule': PyCurrentModule, 'decorator': PyDecoratorFunction, 'decoratormethod': PyDecoratorMethod, } roles = { 'data': PyXRefRole(), 'exc': PyXRefRole(), 'func': PyXRefRole(fix_parens=True), 'class': PyXRefRole(), 'const': PyXRefRole(), 'attr': PyXRefRole(), 'meth': PyXRefRole(fix_parens=True), 'mod': PyXRefRole(), 'obj': PyXRefRole(), } initial_data = { 'objects': {}, # fullname -> docname, objtype 'modules': {}, # modname -> docname, synopsis, platform, deprecated } # type: Dict[unicode, Dict[unicode, Tuple[Any]]] indices = [ PythonModuleIndex, ] def clear_doc(self, docname): # type: (unicode) -> None for fullname, (fn, _l) in list(self.data['objects'].items()): if fn == docname: del self.data['objects'][fullname] for modname, (fn, _x, _x, _x) in list(self.data['modules'].items()): if fn == docname: del self.data['modules'][modname] def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None # XXX check duplicates? for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: self.data['objects'][fullname] = (fn, objtype) for modname, data in otherdata['modules'].items(): if data[0] in docnames: self.data['modules'][modname] = data def find_obj(self, env, modname, classname, name, type, searchmode=0): # type: (BuildEnvironment, unicode, unicode, unicode, unicode, int) -> List[Tuple[unicode, Any]] # NOQA """Find a Python object for "name", perhaps using the given module and/or classname. Returns a list of (name, object entry) tuples. """ # skip parens if name[-2:] == '()': name = name[:-2] if not name: return [] objects = self.data['objects'] matches = [] # type: List[Tuple[unicode, Any]] newname = None if searchmode == 1: if type is None: objtypes = list(self.object_types) else: objtypes = self.objtypes_for_role(type) if objtypes is not None: if modname and classname: fullname = modname + '.' + classname + '.' + name if fullname in objects and objects[fullname][1] in objtypes: newname = fullname if not newname: if modname and modname + '.' + name in objects and \ objects[modname + '.' + name][1] in objtypes: newname = modname + '.' + name elif name in objects and objects[name][1] in objtypes: newname = name else: # "fuzzy" searching mode searchname = '.' + name matches = [(oname, objects[oname]) for oname in objects if oname.endswith(searchname) and objects[oname][1] in objtypes] else: # NOTE: searching for exact match, object type is not considered if name in objects: newname = name elif type == 'mod': # only exact matches allowed for modules return [] elif classname and classname + '.' + name in objects: newname = classname + '.' + name elif modname and modname + '.' + name in objects: newname = modname + '.' + name elif modname and classname and \ modname + '.' + classname + '.' + name in objects: newname = modname + '.' + classname + '.' + name # special case: builtin exceptions have module "exceptions" set elif type == 'exc' and '.' not in name and \ 'exceptions.' + name in objects: newname = 'exceptions.' + name # special case: object methods elif type in ('func', 'meth') and '.' not in name and \ 'object.' + name in objects: newname = 'object.' + name if newname is not None: matches.append((newname, objects[newname])) return matches def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA modname = node.get('py:module') clsname = node.get('py:class') searchmode = node.hasattr('refspecific') and 1 or 0 matches = self.find_obj(env, modname, clsname, target, type, searchmode) if not matches: return None elif len(matches) > 1: logger.warning( 'more than one target found for cross-reference %r: %s', target, ', '.join(match[0] for match in matches), type='ref', subtype='python', location=node) name, obj = matches[0] if obj[1] == 'module': return self._make_module_refnode(builder, fromdocname, name, contnode) else: return make_refnode(builder, fromdocname, obj[0], name, contnode, name) def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]] # NOQA modname = node.get('py:module') clsname = node.get('py:class') results = [] # type: List[Tuple[unicode, nodes.Node]] # always search in "refspecific" mode with the :any: role matches = self.find_obj(env, modname, clsname, target, None, 1) for name, obj in matches: if obj[1] == 'module': results.append( ('py:mod', self._make_module_refnode(builder, fromdocname, name, contnode))) else: results.append(('py:' + self.role_for_objtype(obj[1]), make_refnode(builder, fromdocname, obj[0], name, contnode, name))) return results def _make_module_refnode(self, builder, fromdocname, name, contnode): # type: (Builder, unicode, unicode, nodes.Node) -> nodes.Node # get additional info for modules docname, synopsis, platform, deprecated = self.data['modules'][name] title = name if synopsis: title += ': ' + synopsis if deprecated: title += _(' (deprecated)') if platform: title += ' (' + platform + ')' return make_refnode(builder, fromdocname, docname, 'module-' + name, contnode, title) def get_objects(self): # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]] for modname, info in iteritems(self.data['modules']): yield (modname, modname, 'module', info[0], 'module-' + modname, 0) for refname, (docname, type) in iteritems(self.data['objects']): if type != 'module': # modules are already handled yield (refname, refname, type, docname, refname, 1) def get_full_qualified_name(self, node): # type: (nodes.Node) -> unicode modname = node.get('py:module') clsname = node.get('py:class') target = node.get('reftarget') if target is None: return None else: return '.'.join(filter(None, [modname, clsname, target]))
class Config(object): """ Configuration file abstraction. """ # the values are: (default, what needs to be rebuilt if changed) # If you add a value here, don't forget to include it in the # quickstart.py file template as well as in the docs! config_values = dict( # general options project=('Python', 'env'), copyright=('', 'html'), version=('', 'env'), release=('', 'env'), today=('', 'env'), # the real default is locale-dependent today_fmt=(None, 'env', string_classes), language=(None, 'env', string_classes), locale_dirs=(['locales'], 'env'), figure_language_filename=(u'{root}.{language}{ext}', 'env', [str]), master_doc=('contents', 'env'), source_suffix=(['.rst'], 'env'), source_encoding=('utf-8-sig', 'env'), source_parsers=({}, 'env'), exclude_patterns=([], 'env'), default_role=(None, 'env', string_classes), add_function_parentheses=(True, 'env'), add_module_names=(True, 'env'), trim_footnote_reference_space=(False, 'env'), show_authors=(False, 'env'), pygments_style=(None, 'html', string_classes), highlight_language=('default', 'env'), highlight_options=({}, 'env'), templates_path=([], 'html'), template_bridge=(None, 'html', string_classes), keep_warnings=(False, 'env'), suppress_warnings=([], 'env'), modindex_common_prefix=([], 'html'), rst_epilog=(None, 'env', string_classes), rst_prolog=(None, 'env', string_classes), trim_doctest_flags=(True, 'env'), primary_domain=('py', 'env', [NoneType]), needs_sphinx=(None, None, string_classes), needs_extensions=({}, None), nitpicky=(False, None), nitpick_ignore=([], None), numfig=(False, 'env'), numfig_secnum_depth=(1, 'env'), numfig_format=({ 'section': l_('Section %s'), 'figure': l_('Fig. %s'), 'table': l_('Table %s'), 'code-block': l_('Listing %s') }, 'env'), tls_verify=(True, 'env'), tls_cacerts=(None, 'env'), # pre-initialized confval for HTML builder html_translator_class=(None, 'html', string_classes), ) def __init__(self, dirname, filename, overrides, tags): self.overrides = overrides self.values = Config.config_values.copy() config = {} if dirname is not None: config_file = path.join(dirname, filename) config['__file__'] = config_file config['tags'] = tags with cd(dirname): # we promise to have the config dir as current dir while the # config file is executed try: execfile_(filename, config) except SyntaxError as err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get('setup', None) if 'extensions' in overrides: if isinstance(overrides['extensions'], string_types): config['extensions'] = overrides.pop('extensions').split(',') else: config['extensions'] = overrides.pop('extensions') self.extensions = config.get('extensions', []) # correct values of copyright year that are not coherent with # the SOURCE_DATE_EPOCH environment variable (if set) # See https://reproducible-builds.org/specs/source-date-epoch/ if getenv('SOURCE_DATE_EPOCH') is not None: for k in ('copyright', 'epub_copyright'): if k in config: config[k] = copyright_year_re.sub( '\g<1>%s' % format_date('%Y'), config[k]) def check_types(self, warn): # check all values for deviation from the default value's type, since # that can result in TypeErrors all over the place # NB. since config values might use l_() we have to wait with calling # this method until i18n is initialized for name in self._raw_config: if name not in self.values: continue # we don't know a default value settings = self.values[name] default, dummy_rebuild = settings[:2] permitted = settings[2] if len(settings) == 3 else () if hasattr(default, '__call__'): default = default(self) # could invoke l_() if default is None and not permitted: continue # neither inferrable nor expliclitly permitted types current = self[name] if isinstance(permitted, ENUM): if not permitted.match(current): warn( CONFIG_ENUM_WARNING.format( name=name, current=current, candidates=permitted.candidates)) else: if type(current) is type(default): continue if type(current) in permitted: continue common_bases = ( set(type(current).__bases__ + (type(current), )) & set(type(default).__bases__)) common_bases.discard(object) if common_bases: continue # at least we share a non-trivial base class if permitted: warn( CONFIG_PERMITTED_TYPE_WARNING.format( name=name, current=type(current), permitted=str([cls.__name__ for cls in permitted]))) else: warn( CONFIG_TYPE_WARNING.format(name=name, current=type(current), default=type(default))) def check_unicode(self, warn): # check all string values for non-ASCII characters in bytestrings, # since that can result in UnicodeErrors all over the place for name, value in iteritems(self._raw_config): if isinstance(value, binary_type) and nonascii_re.search(value): warn('the config value %r is set to a string with non-ASCII ' 'characters; this can lead to Unicode errors occurring. ' 'Please use Unicode strings, e.g. %r.' % (name, u'Content')) def convert_overrides(self, name, value): if not isinstance(value, string_types): return value else: defvalue = self.values[name][0] if isinstance(defvalue, dict): raise ValueError( 'cannot override dictionary config setting %r, ' 'ignoring (use %r to set individual elements)' % (name, name + '.key=value')) elif isinstance(defvalue, list): return value.split(',') elif isinstance(defvalue, integer_types): try: return int(value) except ValueError: raise ValueError( 'invalid number %r for config value %r, ignoring' % (value, name)) elif hasattr(defvalue, '__call__'): return value elif defvalue is not None and not isinstance( defvalue, string_types): raise ValueError( 'cannot override config setting %r with unsupported ' 'type, ignoring' % name) else: return value def pre_init_values(self, warn): """Initialize some limited config variables before loading extensions""" variables = [ 'needs_sphinx', 'suppress_warnings', 'html_translator_class' ] for name in variables: try: if name in self.overrides: self.__dict__[name] = self.convert_overrides( name, self.overrides[name]) elif name in self._raw_config: self.__dict__[name] = self._raw_config[name] except ValueError as exc: warn(exc) def init_values(self, warn): config = self._raw_config for valname, value in iteritems(self.overrides): try: if '.' in valname: realvalname, key = valname.split('.', 1) config.setdefault(realvalname, {})[key] = value continue elif valname not in self.values: warn('unknown config value %r in override, ignoring' % valname) continue if isinstance(value, string_types): config[valname] = self.convert_overrides(valname, value) else: config[valname] = value except ValueError as exc: warn(exc) for name in config: if name in self.values: self.__dict__[name] = config[name] if isinstance(self.source_suffix, string_types): self.source_suffix = [self.source_suffix] def __getattr__(self, name): if name.startswith('_'): raise AttributeError(name) if name not in self.values: raise AttributeError('No such config value: %s' % name) default = self.values[name][0] if hasattr(default, '__call__'): return default(self) return default def __getitem__(self, name): return getattr(self, name) def __setitem__(self, name, value): setattr(self, name, value) def __delitem__(self, name): delattr(self, name) def __contains__(self, name): return name in self.values
class StandardDomain(Domain): """ Domain for all objects that don't fit into another domain or are added via the application interface. """ name = 'std' label = 'Default' object_types = { 'term': ObjType(l_('glossary term'), 'term', searchprio=-1), 'token': ObjType(l_('grammar token'), 'token', searchprio=-1), 'label': ObjType(l_('reference label'), 'ref', 'keyword', searchprio=-1), 'envvar': ObjType(l_('environment variable'), 'envvar'), 'cmdoption': ObjType(l_('program option'), 'option'), } directives = { 'program': Program, 'cmdoption': Cmdoption, # old name for backwards compatibility 'option': Cmdoption, 'envvar': EnvVar, 'glossary': Glossary, 'productionlist': ProductionList, } roles = { 'option': OptionXRefRole(warn_dangling=True), 'envvar': EnvVarXRefRole(), # links to tokens in grammar productions 'token': XRefRole(), # links to terms in glossary 'term': XRefRole(lowercase=True, innernodeclass=nodes.inline, warn_dangling=True), # links to headings or arbitrary labels 'ref': XRefRole(lowercase=True, innernodeclass=nodes.inline, warn_dangling=True), # links to labels of numbered figures, tables and code-blocks 'numref': XRefRole(lowercase=True, warn_dangling=True), # links to labels, without a different title 'keyword': XRefRole(warn_dangling=True), } initial_data = { 'progoptions': {}, # (program, name) -> docname, labelid 'objects': {}, # (type, name) -> docname, labelid 'labels': { # labelname -> docname, labelid, sectionname 'genindex': ('genindex', '', l_('Index')), 'modindex': ('py-modindex', '', l_('Module Index')), 'search': ('search', '', l_('Search Page')), }, 'anonlabels': { # labelname -> docname, labelid 'genindex': ('genindex', ''), 'modindex': ('py-modindex', ''), 'search': ('search', ''), }, } dangling_warnings = { 'term': 'term not in glossary: %(target)s', 'ref': 'undefined label: %(target)s (if the link has no caption ' 'the label must precede a section header)', 'numref': 'undefined label: %(target)s', 'keyword': 'unknown keyword: %(target)s', 'option': 'unknown option: %(target)s', } enumerable_nodes = { # node_class -> (figtype, title_getter) nodes.figure: ('figure', None), nodes.table: ('table', None), nodes.container: ('code-block', None), } def clear_doc(self, docname): for key, (fn, _l) in list(self.data['progoptions'].items()): if fn == docname: del self.data['progoptions'][key] for key, (fn, _l) in list(self.data['objects'].items()): if fn == docname: del self.data['objects'][key] for key, (fn, _l, _l) in list(self.data['labels'].items()): if fn == docname: del self.data['labels'][key] for key, (fn, _l) in list(self.data['anonlabels'].items()): if fn == docname: del self.data['anonlabels'][key] def merge_domaindata(self, docnames, otherdata): # XXX duplicates? for key, data in otherdata['progoptions'].items(): if data[0] in docnames: self.data['progoptions'][key] = data for key, data in otherdata['objects'].items(): if data[0] in docnames: self.data['objects'][key] = data for key, data in otherdata['labels'].items(): if data[0] in docnames: self.data['labels'][key] = data for key, data in otherdata['anonlabels'].items(): if data[0] in docnames: self.data['anonlabels'][key] = data def process_doc(self, env, docname, document): labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in iteritems(document.nametypes): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if name.isdigit() or 'refuri' in node or \ node.tagname.startswith('desc_'): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: env.warn_node( 'duplicate label %s, ' % name + 'other instance ' 'in ' + env.doc2path(labels[name][0]), node) anonlabels[name] = docname, labelid if node.tagname == 'section': sectname = clean_astext(node[0]) # node[0] == title node elif self.is_enumerable_node(node): sectname = self.get_numfig_title(node) if sectname is None: continue elif node.traverse(addnodes.toctree): n = node.traverse(addnodes.toctree)[0] if n.get('caption'): sectname = n['caption'] else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname def build_reference_node(self, fromdocname, builder, docname, labelid, sectname, rolename, **options): nodeclass = options.pop('nodeclass', nodes.reference) newnode = nodeclass('', '', internal=True, **options) innernode = nodes.inline(sectname, sectname) if innernode.get('classes') is not None: innernode['classes'].append('std') innernode['classes'].append('std-' + rolename) if docname == fromdocname: newnode['refid'] = labelid else: # set more info in contnode; in case the # get_relative_uri call raises NoUri, # the builder will then have to resolve these contnode = addnodes.pending_xref('') contnode['refdocname'] = docname contnode['refsectname'] = sectname newnode['refuri'] = builder.get_relative_uri(fromdocname, docname) if labelid: newnode['refuri'] += '#' + labelid newnode.append(innernode) return newnode def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): if typ == 'ref': if node['refexplicit']: # reference to anonymous label; the reference uses # the supplied link caption docname, labelid = self.data['anonlabels'].get( target, ('', '')) sectname = node.astext() else: # reference to named label; the final node will # contain the section name after the label docname, labelid, sectname = self.data['labels'].get( target, ('', '', '')) if not docname: return None return self.build_reference_node(fromdocname, builder, docname, labelid, sectname, 'ref') elif typ == 'numref': docname, labelid = self.data['anonlabels'].get(target, ('', '')) if not docname: return None if env.config.numfig is False: env.warn(fromdocname, 'numfig is disabled. :numref: is ignored.', lineno=node.line) return contnode target_node = env.get_doctree(docname).ids.get(labelid) figtype = self.get_figtype(target_node) if figtype is None: return None try: figure_id = target_node['ids'][0] fignumber = env.toc_fignumbers[docname][figtype][figure_id] except (KeyError, IndexError): # target_node is found, but fignumber is not assigned. # Maybe it is defined in orphaned document. env.warn(fromdocname, "no number is assigned for %s: %s" % (figtype, labelid), lineno=node.line) return contnode title = contnode.astext() if target == fully_normalize_name(title): title = env.config.numfig_format.get(figtype, '') try: newtitle = title % '.'.join(map(str, fignumber)) except TypeError: env.warn(fromdocname, 'invalid numfig_format: %s' % title, lineno=node.line) return None return self.build_reference_node( fromdocname, builder, docname, labelid, newtitle, 'numref', nodeclass=addnodes.number_reference, title=title) elif typ == 'keyword': # keywords are oddballs: they are referenced by named labels docname, labelid, _ = self.data['labels'].get(target, ('', '', '')) if not docname: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) elif typ == 'option': progname = node.get('std:program') target = target.strip() docname, labelid = self.data['progoptions'].get((progname, target), ('', '')) if not docname: commands = [] while ws_re.search(target): subcommand, target = ws_re.split(target, 1) commands.append(subcommand) progname = "-".join(commands) docname, labelid = self.data['progoptions'].get( (progname, target), ('', '')) if docname: break else: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) else: objtypes = self.objtypes_for_role(typ) or [] for objtype in objtypes: if (objtype, target) in self.data['objects']: docname, labelid = self.data['objects'][objtype, target] break else: docname, labelid = '', '' if not docname: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): results = [] ltarget = target.lower() # :ref: lowercases its target automatically for role in ('ref', 'option'): # do not try "keyword" res = self.resolve_xref(env, fromdocname, builder, role, ltarget if role == 'ref' else target, node, contnode) if res: results.append(('std:' + role, res)) # all others for objtype in self.object_types: key = (objtype, target) if objtype == 'term': key = (objtype, ltarget) if key in self.data['objects']: docname, labelid = self.data['objects'][key] results.append(('std:' + self.role_for_objtype(objtype), make_refnode(builder, fromdocname, docname, labelid, contnode))) return results def get_objects(self): # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) for (prog, option), info in iteritems(self.data['progoptions']): yield (option, option, 'option', info[0], info[1], 1) for (type, name), info in iteritems(self.data['objects']): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, info in iteritems(self.data['labels']): yield (name, info[2], 'label', info[0], info[1], -1) # add anonymous-only labels as well non_anon_labels = set(self.data['labels']) for name, info in iteritems(self.data['anonlabels']): if name not in non_anon_labels: yield (name, name, 'label', info[0], info[1], -1) def get_type_name(self, type, primary=False): # never prepend "Default" return type.lname def is_enumerable_node(self, node): return node.__class__ in self.enumerable_nodes def get_numfig_title(self, node): """Get the title of enumerable nodes to refer them using its title""" if self.is_enumerable_node(node): _, title_getter = self.enumerable_nodes.get( node.__class__, (None, None)) if title_getter: return title_getter(node) else: for subnode in node: if subnode.tagname in ('caption', 'title'): return clean_astext(subnode) return None def get_figtype(self, node): """Get figure type of nodes.""" def has_child(node, cls): return any(isinstance(child, cls) for child in node) if isinstance(node, nodes.container): if node.get('literal_block') and has_child(node, nodes.literal_block): return 'code-block' else: return None else: figtype, _ = self.enumerable_nodes.get(node.__class__, (None, None)) return figtype
class ReSTDomain(Domain): """ReStructuredText domain.""" name = 'rst' label = 'reStructuredText' object_types = { 'directive': ObjType(l_('directive'), 'dir'), 'role': ObjType(l_('role'), 'role'), } directives = { 'directive': ReSTDirective, 'role': ReSTRole, } roles = { 'dir': XRefRole(), 'role': XRefRole(), } initial_data = { 'objects': {}, # fullname -> docname, objtype } # type: Dict[unicode, Dict[unicode, Tuple[unicode, ObjType]]] def clear_doc(self, docname): # type: (unicode) -> None for (typ, name), doc in list(self.data['objects'].items()): if doc == docname: del self.data['objects'][typ, name] def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None # XXX check duplicates for (typ, name), doc in otherdata['objects'].items(): if doc in docnames: self.data['objects'][typ, name] = doc def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA objects = self.data['objects'] objtypes = self.objtypes_for_role(typ) for objtype in objtypes: if (objtype, target) in objects: return make_refnode(builder, fromdocname, objects[objtype, target], objtype + '-' + target, contnode, target + ' ' + objtype) def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[nodes.Node] # NOQA objects = self.data['objects'] results = [] for objtype in self.object_types: if (objtype, target) in self.data['objects']: results.append( ('rst:' + self.role_for_objtype(objtype), make_refnode(builder, fromdocname, objects[objtype, target], objtype + '-' + target, contnode, target + ' ' + objtype))) return results def get_objects(self): # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]] for (typ, name), docname in iteritems(self.data['objects']): yield name, name, typ, docname, typ + '-' + name, 1
class PythonModuleIndex(Index): """ Index subclass to provide the Python module index. """ name = 'modindex' localname = l_('Python Module Index') shortname = l_('modules') def generate(self, docnames=None): content = {} # list of prefixes to ignore ignores = self.domain.env.config['modindex_common_prefix'] ignores = sorted(ignores, key=len, reverse=True) # list of all modules, sorted by module name modules = sorted(iteritems(self.domain.data['modules']), key=lambda x: x[0].lower()) # sort out collapsable modules prev_modname = '' num_toplevels = 0 for modname, (docname, synopsis, platforms, deprecated) in modules: if docnames and docname not in docnames: continue for ignore in ignores: if modname.startswith(ignore): modname = modname[len(ignore):] stripped = ignore break else: stripped = '' # we stripped the whole module name? if not modname: modname, stripped = stripped, '' entries = content.setdefault(modname[0].lower(), []) package = modname.split('.')[0] if package != modname: # it's a submodule if prev_modname == package: # first submodule - make parent a group head if entries: entries[-1][1] = 1 elif not prev_modname.startswith(package): # submodule without parent in list, add dummy entry entries.append([stripped + package, 1, '', '', '', '', '']) subtype = 2 else: num_toplevels += 1 subtype = 0 qualifier = deprecated and _('Deprecated') or '' entries.append([stripped + modname, subtype, docname, 'module-' + stripped + modname, platforms, qualifier, synopsis]) prev_modname = modname # apply heuristics when to collapse modindex at page load: # only collapse if number of toplevel modules is larger than # number of submodules collapse = len(modules) - num_toplevels < num_toplevels # sort by first letter content = sorted(iteritems(content)) return content, collapse
class EverettComponent(ObjectDescription): """ Description of an Everett component"" """ doc_field_types = [ TypedField('options', label=l_('Options'), names=('option', 'opt'), typerolename='obj', typenames=('parser', ), can_collapse=True), ] allow_nesting = False def handle_signature(self, sig, signode): if sig != 'Configuration': # Add "component" to the beginning if it's a specific component signode.clear() # Add "component" which is the type of this thing signode += addnodes.desc_annotation('component ', 'component ') if '.' in sig: modname, clsname = sig.rsplit('.', 1) else: modname, clsname = '', sig # If there's a module name, then we add the module if modname: signode += addnodes.desc_addname(modname + '.', modname + '.') # Add the class name signode += addnodes.desc_name(clsname, clsname) else: # Add just "Configuration" signode += addnodes.desc_name(sig, sig) return sig def add_target_and_index(self, name, sig, signode): targetname = '%s-%s' % (self.objtype, 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) objects = self.env.domaindata['everett']['objects'] key = (self.objtype, name) if key in objects: self.state_machine.reporter.warning( 'duplicate description of %s %s, ' % (self.objtype, name) + 'other instance in ' + self.env.doc2path(objects[key]), line=self.lineno) objects[key] = self.env.docname indextext = _('%s (component)') % name self.indexnode['entries'].append( ('single', indextext, targetname, '', None))
class BroDomain(Domain): """Bro domain.""" name = 'bro' label = 'Bro' object_types = { 'type': ObjType(l_('type'), 'type'), 'namespace': ObjType(l_('namespace'), 'namespace'), 'id': ObjType(l_('id'), 'id'), 'enum': ObjType(l_('enum'), 'enum'), 'attr': ObjType(l_('attr'), 'attr'), } directives = { 'type': BroGeneric, 'namespace': BroNamespace, 'id': BroIdentifier, 'enum': BroEnum, 'attr': BroAttribute, } roles = { 'type': XRefRole(), 'namespace': XRefRole(), 'id': XRefRole(), 'enum': XRefRole(), 'attr': XRefRole(), 'see': XRefRole(), } indices = [ BroNotices, ] initial_data = { 'objects': {}, # fullname -> docname, objtype } def clear_doc(self, docname): for (typ, name), doc in self.data['objects'].items(): if doc == docname: del self.data['objects'][typ, name] def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): objects = self.data['objects'] if typ == "see": if target not in self.data['idtypes']: self.env.warn(fromdocname, 'unknown target for ":bro:see:`%s`"' % (target)) return [] objtype = self.data['idtypes'][target] return make_refnode(builder, fromdocname, objects[objtype, target], objtype + '-' + target, contnode, target + ' ' + objtype) else: objtypes = self.objtypes_for_role(typ) for objtype in objtypes: if (objtype, target) in objects: return make_refnode(builder, fromdocname, objects[objtype, target], objtype + '-' + target, contnode, target + ' ' + objtype) else: self.env.warn( fromdocname, 'unknown target for ":bro:%s:`%s`"' % (typ, target)) def get_objects(self): for (typ, name), docname in self.data['objects'].iteritems(): yield name, name, typ, docname, typ + '-' + name, 1
class NimObject(ObjectDescription): """ Description of a Nim 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 Nim types aren't described anywhere, so don't try to create # a cross-reference to them stopwords = set( ('int', 'uint', 'float', 'bool', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'float32', 'float64', 'char', 'string', 'cstring', 'pointer', 'void', 'expr', 'typedesc', 'tsignedint', 'tunsignedint', 'tinteger', 'tordinal', 'treal', 'tnumber', 'byte', 'natural', 'positive', 'exception')) 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.lower() not in self.stopwords: pnode = addnodes.pending_xref('', refdomain='nim', reftype='type', reftarget=part, modname=None, classname=None) pnode += tnode node += pnode else: node += tnode def _handle_proc_signature(self, sig, signode, m): "Transform a Nim proc node into RST nodes." name, arglist, rettype, pragmas = m.groups() signode += addnodes.desc_type('proc', 'proc') signode += addnodes.desc_name(name, name) if arglist is None: signode += addnodes.desc_parameterlist() else: arguments = nim_arg_sig_re.match(arglist).groups()[0] signode += addnodes.desc_parameterlist(arguments, arguments) if rettype is not None: retnode = addnodes.desc_returns() self._parse_type(retnode, nim_rettype_sig_re.match(rettype).groups()[0]) signode += retnode if pragmas: signode += addnodes.desc_addname(pragmas, pragmas) return name def _handle_enum_signature(self, sig, signode, m): "Transform a Nim enum into RST nodes." name, values = m.groups() signode += addnodes.desc_type('enum', 'enum') signode += addnodes.desc_name(name, name) signode += addnodes.desc_addname(values, '= ' + values) return name def _handle_object_signature(self, sig, signode, m): "Transform a Nim object into RST nodes." name = m.groups()[0] signode += addnodes.desc_type('object', 'object') signode += addnodes.desc_name(name, name) return name def handle_signature(self, sig, signode): "Transform a Nim signature into RST nodes." print "handle_signature:", sig m = nim_proc_sig_re.match(sig) if m is not None: return self._handle_proc_signature(sig, signode, m) m = nim_enum_sig_re.match(sig) if m is not None: return self._handle_enum_signature(sig, signode, m) m = nim_object_sig_re.match(sig) if m is not None: return self._handle_object_signature(sig, signode, m) raise ValueError('no match') def get_index_text(self, name): if self.objtype == 'proc': return _('%s (Nim procedure)') % name elif self.objtype == 'template': return _('%s (Nim template)') % name elif self.objtype == 'enum': return _('%s (Nim enumeration)') % name elif self.objtype == 'type': return _('%s (Nim type)') % name elif self.objtype == 'const': return _('%s (Nim constant)') % name else: return '' def add_target_and_index(self, name, sig, signode): # for Nim 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 = 'nim.' + 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['nim']['objects'] if name in inv: self.state_machine.reporter.warning( 'duplicate Nim 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, '')) def before_content(self): self.typename_set = False if self.name == 'nim:type': if self.names: self.env.temp_data['nim:type'] = self.names[0] self.typename_set = True def after_content(self): if self.typename_set: self.env.temp_data['nim:type'] = None
class CDomain(Domain): """C language domain.""" name = 'c' label = 'C' object_types = { 'function': ObjType(l_('function'), 'func'), 'member': ObjType(l_('member'), 'member'), 'macro': ObjType(l_('macro'), 'macro'), 'type': ObjType(l_('type'), 'type'), 'var': ObjType(l_('variable'), 'data'), } directives = { 'function': CObject, 'member': CObject, 'macro': CObject, 'type': CObject, 'var': CObject, } roles = { 'func': CXRefRole(fix_parens=True), 'member': CXRefRole(), 'macro': CXRefRole(), 'data': CXRefRole(), 'type': CXRefRole(), } initial_data = { 'objects': {}, # fullname -> docname, objtype } def clear_doc(self, docname): for fullname, (fn, _) in list(self.data['objects'].items()): if fn == docname: del self.data['objects'][fullname] def merge_domaindata(self, docnames, otherdata): # XXX check duplicates for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: self.data['objects'][fullname] = (fn, objtype) def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): # strip pointer asterisk target = target.rstrip(' *') if target not in self.data['objects']: return None obj = self.data['objects'][target] return make_refnode(builder, fromdocname, obj[0], 'c.' + target, contnode, target) def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): # strip pointer asterisk target = target.rstrip(' *') if target not in self.data['objects']: return [] obj = self.data['objects'][target] return [('c:' + self.role_for_objtype(obj[1]), make_refnode(builder, fromdocname, obj[0], 'c.' + target, contnode, target))] def get_objects(self): for refname, (docname, type) in list(self.data['objects'].items()): yield (refname, refname, type, docname, 'c.' + refname, 1)
class OCamlDomain(PolyglotDomain): name, label = 'ml', l_('OCaml') directives = { 'module': make_namespace_directive('module'), 'package': make_directive('package'), }
class LuaDomain(PolyglotDomain): name, label = 'lua', l_('Lua') directives = { 'module': make_namespace_directive('module'), }
class JavaDomain(JVMDomain): name, label = 'java', l_('Java')
# -*- coding: utf-8 -*- """ Adds a new "exercise" admonition type """ def setup(app): app.add_directive('exercise', Exercise) app.add_node(exercise, html=( lambda self, node: self.visit_admonition(node, 'exercise'), lambda self, node: self.depart_admonition(node) ), latex=( lambda self, node: self.visit_admonition(node), lambda self, node: self.depart_admonition(node) )) from docutils import nodes from docutils.parsers.rst.directives import admonitions class exercise(nodes.Admonition, nodes.Element): pass class Exercise(admonitions.BaseAdmonition): node_class = exercise from sphinx.locale import admonitionlabels, l_ admonitionlabels['exercise'] = l_('Exercise')
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.env.warn( self.env.docname, 'duplicate C object description of %s, ' % name + 'other instance in ' + self.env.doc2path(inv[name][0]), 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 ErlangDomain(PolyglotDomain): name, label = 'erl', l_('Erlang') directives = { 'module': make_namespace_directive('module'), 'package': make_directive('package'), }
class MATLABDomain(Domain): """MATLAB language domain.""" name = 'mat' label = 'MATLAB' object_types = { 'function': ObjType(l_('function'), 'func', 'obj'), 'data': ObjType(l_('data'), 'data', 'obj'), 'class': ObjType(l_('class'), 'class', 'obj'), 'exception': ObjType(l_('exception'), 'exc', 'obj'), 'method': ObjType(l_('method'), 'meth', 'obj'), 'classmethod': ObjType(l_('class method'), 'meth', 'obj'), 'staticmethod': ObjType(l_('static method'), 'meth', 'obj'), 'attribute': ObjType(l_('attribute'), 'attr', 'obj'), 'module': ObjType(l_('module'), 'mod', 'obj'), } directives = { 'function': MatModulelevel, 'data': MatModulelevel, 'class': MatClasslike, 'exception': MatClasslike, 'method': MatClassmember, 'classmethod': MatClassmember, 'staticmethod': MatClassmember, 'attribute': MatClassmember, 'module': MatModule, 'currentmodule': MatCurrentModule, 'decorator': MatDecoratorFunction, 'decoratormethod': MatDecoratorMethod, } roles = { 'data': MatXRefRole(), 'exc': MatXRefRole(), 'func': MatXRefRole(fix_parens=True), 'class': MatXRefRole(), 'const': MatXRefRole(), 'attr': MatXRefRole(), 'meth': MatXRefRole(fix_parens=True), 'mod': MatXRefRole(), 'obj': MatXRefRole(), } initial_data = { 'objects': {}, # fullname -> docname, objtype 'modules': {}, # modname -> docname, synopsis, platform, deprecated } indices = [ MATLABModuleIndex, ] def clear_doc(self, docname): for fullname, (fn, _) in self.data['objects'].items(): if fn == docname: del self.data['objects'][fullname] for modname, (fn, _, _, _) in self.data['modules'].items(): if fn == docname: del self.data['modules'][modname] def find_obj(self, env, modname, classname, name, type, searchmode=0): """Find a MATLAB object for "name", perhaps using the given module and/or classname. Returns a list of (name, object entry) tuples. """ # skip parens if name[-2:] == '()': name = name[:-2] if not name: return [] objects = self.data['objects'] matches = [] newname = None if searchmode == 1: objtypes = self.objtypes_for_role(type) if objtypes is not None: if modname and classname: fullname = modname + '.' + classname + '.' + name if fullname in objects and objects[fullname][1] in objtypes: newname = fullname if not newname: if modname and modname + '.' + name in objects and \ objects[modname + '.' + name][1] in objtypes: newname = modname + '.' + name elif name in objects and objects[name][1] in objtypes: newname = name else: # "fuzzy" searching mode searchname = '.' + name matches = [(oname, objects[oname]) for oname in objects if oname.endswith(searchname) and objects[oname][1] in objtypes] else: # NOTE: searching for exact match, object type is not considered if name in objects: newname = name elif type == 'mod': # only exact matches allowed for modules return [] elif classname and classname + '.' + name in objects: newname = classname + '.' + name elif modname and modname + '.' + name in objects: newname = modname + '.' + name elif modname and classname and \ modname + '.' + classname + '.' + name in objects: newname = modname + '.' + classname + '.' + name # special case: builtin exceptions have module "exceptions" set elif type == 'exc' and '.' not in name and \ 'exceptions.' + name in objects: newname = 'exceptions.' + name # special case: object methods elif type in ('func', 'meth') and '.' not in name and \ 'object.' + name in objects: newname = 'object.' + name if newname is not None: matches.append((newname, objects[newname])) return matches def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode): modname = node.get('mat:module') clsname = node.get('mat:class') searchmode = node.hasattr('refspecific') and 1 or 0 matches = self.find_obj(env, modname, clsname, target, type, searchmode) if not matches: return None elif len(matches) > 1: env.warn_node( 'more than one target found for cross-reference ' '%r: %s' % (target, ', '.join(match[0] for match in matches)), node) name, obj = matches[0] if obj[1] == 'module': # get additional info for modules docname, synopsis, platform, deprecated = self.data['modules'][name] assert docname == obj[0] title = name if synopsis: title += ': ' + synopsis if deprecated: title += _(' (deprecated)') if platform: title += ' (' + platform + ')' return make_refnode(builder, fromdocname, docname, 'module-' + name, contnode, title) else: return make_refnode(builder, fromdocname, obj[0], name, contnode, name) def get_objects(self): for modname, info in self.data['modules'].iteritems(): yield (modname, modname, 'module', info[0], 'module-' + modname, 0) for refname, (docname, type) in self.data['objects'].iteritems(): yield (refname, refname, type, docname, refname, 1)
def document_function(funcdef, docstrings=None, protocols=['restjson']): """A helper function to complete a function documentation with return and parameter types""" # If the function doesn't have a docstring, add an empty list # so the default behaviors below work correctly. if not docstrings: docstrings = [[]] found_params = set() for si, docstring in enumerate(docstrings): for i, line in enumerate(docstring): m = field_re.match(line) if m and m.group('field') == 'param': found_params.add(m.group('name')) next_param_pos = (0, 0) for arg in funcdef.arguments: content = [ u':type %s: :wsme:type:`%s`' % (arg.name, datatypename(arg.datatype)) ] if arg.name not in found_params: content.insert(0, u':param %s: ' % (arg.name)) pos = next_param_pos else: for si, docstring in enumerate(docstrings): for i, line in enumerate(docstring): m = field_re.match(line) if m and m.group('field') == 'param' \ and m.group('name') == arg.name: pos = (si, i + 1) break docstring = docstrings[pos[0]] docstring[pos[1]:pos[1]] = content next_param_pos = (pos[0], pos[1] + len(content)) if funcdef.return_type: content = [u':rtype: %s' % datatypename(funcdef.return_type)] pos = None for si, docstring in enumerate(docstrings): for i, line in enumerate(docstring): m = field_re.match(line) if m and m.group('field') == 'return': pos = (si, i + 1) break else: pos = next_param_pos docstring = docstrings[pos[0]] docstring[pos[1]:pos[1]] = content codesamples = [] if protocols: params = [] for arg in funcdef.arguments: params.append( (arg.name, arg.datatype, make_sample_object(arg.datatype))) codesamples.extend([ u':%s:' % l_(u'Parameters samples'), u' .. cssclass:: toggle', u'' ]) for name, protocol in protocols: language, sample = protocol.encode_sample_params(params, format=True) codesamples.extend([ u' ' * 4 + name, u' .. code-block:: ' + language, u'', ]) codesamples.extend((u' ' * 12 + line for line in six.text_type(sample).split('\n'))) if funcdef.return_type: codesamples.extend([ u':%s:' % l_(u'Return samples'), u' .. cssclass:: toggle', u'' ]) sample_obj = make_sample_object(funcdef.return_type) for name, protocol in protocols: language, sample = protocol.encode_sample_result( funcdef.return_type, sample_obj, format=True) codesamples.extend([ u' ' * 4 + name, u' .. code-block:: ' + language, u'', ]) codesamples.extend( (u' ' * 12 + line for line in six.text_type(sample).split('\n'))) docstrings[0:0] = [codesamples] return docstrings
class Config(object): """ Configuration file abstraction. """ # the values are: (default, what needs to be rebuilt if changed) # If you add a value here, don't forget to include it in the # quickstart.py file template as well as in the docs! config_values = dict( # general options project=('Python', 'env'), copyright=('', 'html'), version=('', 'env'), release=('', 'env'), today=('', 'env'), # the real default is locale-dependent today_fmt=(None, 'env', string_classes), language=(None, 'env', string_classes), locale_dirs=(['locales'], 'env'), figure_language_filename=(u'{root}.{language}{ext}', 'env', [str]), master_doc=('contents', 'env'), source_suffix=(['.rst'], 'env'), source_encoding=('utf-8-sig', 'env'), source_parsers=({}, 'env'), exclude_patterns=([], 'env'), default_role=(None, 'env', string_classes), add_function_parentheses=(True, 'env'), add_module_names=(True, 'env'), trim_footnote_reference_space=(False, 'env'), show_authors=(False, 'env'), pygments_style=(None, 'html', string_classes), highlight_language=('default', 'env'), highlight_options=({}, 'env'), templates_path=([], 'html'), template_bridge=(None, 'html', string_classes), keep_warnings=(False, 'env'), suppress_warnings=([], 'env'), modindex_common_prefix=([], 'html'), rst_epilog=(None, 'env', string_classes), rst_prolog=(None, 'env', string_classes), trim_doctest_flags=(True, 'env'), primary_domain=('py', 'env', [NoneType]), needs_sphinx=(None, None, string_classes), needs_extensions=({}, None), nitpicky=(False, None), nitpick_ignore=([], None), numfig=(False, 'env'), numfig_secnum_depth=(1, 'env'), numfig_format=({ 'figure': l_('Fig. %s'), 'table': l_('Table %s'), 'code-block': l_('Listing %s') }, 'env'), # HTML options html_theme=('alabaster', 'html'), html_theme_path=([], 'html'), html_theme_options=({}, 'html'), html_title=(lambda self: l_('%s %s documentation') % (self.project, self.release), 'html', string_classes), html_short_title=(lambda self: self.html_title, 'html'), html_style=(None, 'html', string_classes), html_logo=(None, 'html', string_classes), html_favicon=(None, 'html', string_classes), html_static_path=([], 'html'), html_extra_path=([], 'html'), # the real default is locale-dependent html_last_updated_fmt=(None, 'html', string_classes), html_use_smartypants=(True, 'html'), html_translator_class=(None, 'html', string_classes), html_sidebars=({}, 'html'), html_additional_pages=({}, 'html'), html_use_modindex=(True, 'html'), # deprecated html_domain_indices=(True, 'html', [list]), html_add_permalinks=(u'\u00B6', 'html'), html_use_index=(True, 'html'), html_split_index=(False, 'html'), html_copy_source=(True, 'html'), html_show_sourcelink=(True, 'html'), html_use_opensearch=('', 'html'), html_file_suffix=(None, 'html', string_classes), html_link_suffix=(None, 'html', string_classes), html_show_copyright=(True, 'html'), html_show_sphinx=(True, 'html'), html_context=({}, 'html'), html_output_encoding=('utf-8', 'html'), html_compact_lists=(True, 'html'), html_secnumber_suffix=('. ', 'html'), html_search_language=(None, 'html', string_classes), html_search_options=({}, 'html'), html_search_scorer=('', None), html_scaled_image_link=(True, 'html'), # HTML help only options htmlhelp_basename=(lambda self: make_filename(self.project), None), # Qt help only options qthelp_basename=(lambda self: make_filename(self.project), None), # Devhelp only options devhelp_basename=(lambda self: make_filename(self.project), None), # Apple help options applehelp_bundle_name=(lambda self: make_filename(self.project), 'applehelp'), applehelp_bundle_id=(None, 'applehelp', string_classes), applehelp_dev_region=('en-us', 'applehelp'), applehelp_bundle_version=('1', 'applehelp'), applehelp_icon=(None, 'applehelp', string_classes), applehelp_kb_product=(lambda self: '%s-%s' % (make_filename(self.project), self.release), 'applehelp'), applehelp_kb_url=(None, 'applehelp', string_classes), applehelp_remote_url=(None, 'applehelp', string_classes), applehelp_index_anchors=(False, 'applehelp', string_classes), applehelp_min_term_length=(None, 'applehelp', string_classes), applehelp_stopwords=(lambda self: self.language or 'en', 'applehelp'), applehelp_locale=(lambda self: self.language or 'en', 'applehelp'), applehelp_title=(lambda self: self.project + ' Help', 'applehelp'), applehelp_codesign_identity=( lambda self: environ.get('CODE_SIGN_IDENTITY', None), 'applehelp'), applehelp_codesign_flags=( lambda self: shlex.split(environ.get('OTHER_CODE_SIGN_FLAGS', '')), 'applehelp'), applehelp_indexer_path=('/usr/bin/hiutil', 'applehelp'), applehelp_codesign_path=('/usr/bin/codesign', 'applehelp'), applehelp_disable_external_tools=(False, None), # Epub options epub_basename=(lambda self: make_filename(self.project), None), epub_theme=('epub', 'html'), epub_theme_options=({}, 'html'), epub_title=(lambda self: self.html_title, 'html'), epub3_description=('', 'epub3', string_classes), epub_author=('unknown', 'html'), epub3_contributor=('unknown', 'epub3', string_classes), epub_language=(lambda self: self.language or 'en', 'html'), epub_publisher=('unknown', 'html'), epub_copyright=(lambda self: self.copyright, 'html'), epub_identifier=('unknown', 'html'), epub_scheme=('unknown', 'html'), epub_uid=('unknown', 'env'), epub_cover=((), 'env'), epub_guide=((), 'env'), epub_pre_files=([], 'env'), epub_post_files=([], 'env'), epub_exclude_files=([], 'env'), epub_tocdepth=(3, 'env'), epub_tocdup=(True, 'env'), epub_tocscope=('default', 'env'), epub_fix_images=(False, 'env'), epub_max_image_width=(0, 'env'), epub_show_urls=('inline', 'html'), epub_use_index=(lambda self: self.html_use_index, 'html'), epub3_page_progression_direction=('ltr', 'epub3', string_classes), # LaTeX options latex_documents=( lambda self: [(self.master_doc, make_filename(self.project) + '.tex', self.project, '', 'manual')], None), latex_logo=(None, None, string_classes), latex_appendices=([], None), # now deprecated - use latex_toplevel_sectioning latex_use_parts=(False, None), latex_toplevel_sectioning=(None, None, [str]), latex_use_modindex=(True, None), # deprecated latex_domain_indices=(True, None, [list]), latex_show_urls=('no', None), latex_show_pagerefs=(False, None), # paper_size and font_size are still separate values # so that you can give them easily on the command line latex_paper_size=('letter', None), latex_font_size=('10pt', None), latex_elements=({}, None), latex_additional_files=([], None), latex_docclass=({}, None), # now deprecated - use latex_elements latex_preamble=('', None), # text options text_sectionchars=('*=-~"+`', 'env'), text_newlines=('unix', 'env'), # manpage options man_pages=(lambda self: [(self.master_doc, make_filename( self.project).lower(), '%s %s' % (self.project, self.release), [], 1)], None), man_show_urls=(False, None), # Texinfo options texinfo_documents=(lambda self: [( self.master_doc, make_filename(self.project).lower(), self.project, '', make_filename(self.project), 'The %s reference manual.' % make_filename(self.project), 'Python')], None), texinfo_appendices=([], None), texinfo_elements=({}, None), texinfo_domain_indices=(True, None, [list]), texinfo_show_urls=('footnote', None), texinfo_no_detailmenu=(False, None), # linkcheck options linkcheck_ignore=([], None), linkcheck_retries=(1, None), linkcheck_timeout=(None, None, [int]), linkcheck_workers=(5, None), linkcheck_anchors=(True, None), # gettext options gettext_compact=(True, 'gettext'), gettext_location=(True, 'gettext'), gettext_uuid=(False, 'gettext'), gettext_auto_build=(True, 'env'), gettext_additional_targets=([], 'env'), # XML options xml_pretty=(True, 'env'), ) def __init__(self, dirname, filename, overrides, tags): self.overrides = overrides self.values = Config.config_values.copy() config = {} if 'extensions' in overrides: # XXX do we need this? if isinstance(overrides['extensions'], string_types): config['extensions'] = overrides.pop('extensions').split(',') else: config['extensions'] = overrides.pop('extensions') if dirname is not None: config_file = path.join(dirname, filename) config['__file__'] = config_file config['tags'] = tags with cd(dirname): # we promise to have the config dir as current dir while the # config file is executed try: execfile_(filename, config) except SyntaxError as err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) except SystemExit: raise ConfigError(CONFIG_EXIT_ERROR) self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get('setup', None) self.extensions = config.get('extensions', []) # correct values of copyright year that are not coherent with # the SOURCE_DATE_EPOCH environment variable (if set) # See https://reproducible-builds.org/specs/source-date-epoch/ if getenv('SOURCE_DATE_EPOCH') is not None: for k in ('copyright', 'epub_copyright'): if k in config: config[k] = copyright_year_re.sub( '\g<1>%s' % format_date('%Y'), config[k]) def check_types(self, warn): # check all values for deviation from the default value's type, since # that can result in TypeErrors all over the place # NB. since config values might use l_() we have to wait with calling # this method until i18n is initialized for name in self._raw_config: if name not in self.values: continue # we don't know a default value settings = self.values[name] default, dummy_rebuild = settings[:2] permitted = settings[2] if len(settings) == 3 else () if hasattr(default, '__call__'): default = default(self) # could invoke l_() if default is None and not permitted: continue # neither inferrable nor expliclitly permitted types current = self[name] if type(current) is type(default): continue if type(current) in permitted: continue common_bases = (set(type(current).__bases__ + (type(current), )) & set(type(default).__bases__)) common_bases.discard(object) if common_bases: continue # at least we share a non-trivial base class warn( CONFIG_TYPE_WARNING.format(name=name, current=type(current), default=type(default))) def check_unicode(self, warn): # check all string values for non-ASCII characters in bytestrings, # since that can result in UnicodeErrors all over the place for name, value in iteritems(self._raw_config): if isinstance(value, binary_type) and nonascii_re.search(value): warn('the config value %r is set to a string with non-ASCII ' 'characters; this can lead to Unicode errors occurring. ' 'Please use Unicode strings, e.g. %r.' % (name, u'Content')) def convert_overrides(self, name, value): if not isinstance(value, string_types): return value else: defvalue = self.values[name][0] if isinstance(defvalue, dict): raise ValueError( 'cannot override dictionary config setting %r, ' 'ignoring (use %r to set individual elements)' % (name, name + '.key=value')) elif isinstance(defvalue, list): return value.split(',') elif isinstance(defvalue, integer_types): try: return int(value) except ValueError: raise ValueError( 'invalid number %r for config value %r, ignoring' % (value, name)) elif hasattr(defvalue, '__call__'): return value elif defvalue is not None and not isinstance( defvalue, string_types): raise ValueError( 'cannot override config setting %r with unsupported ' 'type, ignoring' % name) else: return value def pre_init_values(self, warn): """Initialize some limited config variables before loading extensions""" variables = ['needs_sphinx', 'suppress_warnings'] for name in variables: try: if name in self.overrides: self.__dict__[name] = self.convert_overrides( name, self.overrides[name]) elif name in self._raw_config: self.__dict__[name] = self._raw_config[name] except ValueError as exc: warn(exc) def init_values(self, warn): config = self._raw_config for valname, value in iteritems(self.overrides): try: if '.' in valname: realvalname, key = valname.split('.', 1) config.setdefault(realvalname, {})[key] = value continue elif valname not in self.values: warn('unknown config value %r in override, ignoring' % valname) continue if isinstance(value, string_types): config[valname] = self.convert_overrides(valname, value) else: config[valname] = value except ValueError as exc: warn(exc) for name in config: if name in self.values: self.__dict__[name] = config[name] if isinstance(self.source_suffix, string_types): self.source_suffix = [self.source_suffix] def __getattr__(self, name): if name.startswith('_'): raise AttributeError(name) if name not in self.values: raise AttributeError('No such config value: %s' % name) default = self.values[name][0] if hasattr(default, '__call__'): return default(self) return default def __getitem__(self, name): return getattr(self, name) def __setitem__(self, name, value): setattr(self, name, value) def __delitem__(self, name): delattr(self, name) def __contains__(self, name): return name in self.values
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), 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): """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 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 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('gobject:module')) classname = self.env.ref_context.get('gobject:class') if not classname: classname = self.env.ref_context.get('gobject:interface') if not classname: classname = self.env.ref_context.get('gobject:enum') 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) elif add_module and self.env.config.add_module_names: modname = self.options.get( 'module', self.env.ref_context.get('gobject:module')) if modname: 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): """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): modname = self.options.get( 'module', self.env.ref_context.get('gobject: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): # needed for automatic qualification of members (reset in subclasses) self.clsname_set = False def after_content(self): if self.clsname_set: self.env.ref_context.pop('gobject:class', None) self.env.ref_context.pop('gobject:interface', None) self.env.ref_context.pop('gobject:enum', None)
class PolyglotDomain(Domain): """Base class for polyglot domains.""" # See: http://www.sphinx-doc.org/en/stable/extdev/domainapi.html #name, label = 'polyglot', l_('Polyglot') object_types = { 'assembly': ObjType(l_('assembly'), 'assembly'), 'channel': ObjType(l_('channel'), 'channel'), 'class': ObjType(l_('class'), 'class'), 'const': ObjType(l_('constant'), 'constant'), 'func': ObjType(l_('function'), 'function'), 'function': ObjType(l_('function'), 'function'), 'header': ObjType(l_('header'), 'header'), 'library': ObjType(l_('library'), 'library'), 'method': ObjType(l_('method'), 'method'), 'module': ObjType(l_('module'), 'module'), 'namespace': ObjType(l_('namespace'), 'namespace'), 'package': ObjType(l_('package'), 'package'), 'property': ObjType(l_('property'), 'property'), 'schema': ObjType(l_('schema'), 'schema'), 'system': ObjType(l_('system'), 'system'), 'table': ObjType(l_('table'), 'table'), 'trigger': ObjType(l_('trigger'), 'trigger'), 'type': ObjType(l_('type'), 'type'), 'view': ObjType(l_('view'), 'view'), } directives = {} initial_data = { 'objects': {}, # (objtype, name) -> docname } data_version = 0 # bump this when the format of self.data changes
class PythonDomain(Domain): """Python language domain.""" name = 'gobject' label = 'GObject' object_types = { 'function': ObjType(l_('function'), 'func', 'obj'), 'class': ObjType(l_('class'), 'class', 'exc', 'obj'), 'interface': ObjType(l_('interface'), 'interface', 'exc', 'obj'), 'enum': ObjType(l_('enum'), 'enum', 'exc', 'obj'), 'method': ObjType(l_('method'), 'meth', 'obj'), 'classmethod': ObjType(l_('class method'), 'meth', 'obj'), 'staticmethod': ObjType(l_('static method'), 'meth', 'obj'), 'property': ObjType(l_('property'), 'prop', 'obj'), 'member': ObjType(l_('property'), 'member', 'obj'), 'signal': ObjType(l_('signal'), 'signal', 'obj'), 'module': ObjType(l_('module'), 'mod', 'obj'), } directives = { 'function': PyModulelevel, 'class': PyClasslike, 'interface': PyClasslike, 'enum': PyClasslike, 'member': PyClassmember, 'method': PyClassmember, 'classmethod': PyClassmember, 'staticmethod': PyClassmember, 'property': PyClassmember, 'signal': PyClassmember, 'module': PyModule, 'currentmodule': PyCurrentModule, } roles = { 'exc': PyXRefRole(), 'func': PyXRefRole(fix_parens=True), 'class': PyXRefRole(), 'interface': PyXRefRole(), 'const': PyXRefRole(), 'prop': PyXRefRole(), 'signal': PyXRefRole(fix_parens=True), 'meth': PyXRefRole(fix_parens=True), 'mod': PyXRefRole(), 'obj': PyXRefRole(), 'enum': PyXRefRole(), 'member': PyXRefRole(), } initial_data = { 'objects': {}, # fullname -> docname, objtype 'modules': {}, # modname -> docname, synopsis, platform, deprecated } indices = [ PythonModuleIndex, ] def clear_doc(self, docname): for fullname, (fn, _l) in list(self.data['objects'].items()): if fn == docname: del self.data['objects'][fullname] for modname, (fn, _x, _x, _x) in list(self.data['modules'].items()): if fn == docname: del self.data['modules'][modname] def merge_domaindata(self, docnames, otherdata): # XXX check duplicates? for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: self.data['objects'][fullname] = (fn, objtype) for modname, data in otherdata['modules'].items(): if data[0] in docnames: self.data['modules'][modname] = data def find_obj(self, env, modname, classname, name, type, searchmode=0): """Find a Python object for "name", perhaps using the given module and/or classname. Returns a list of (name, object entry) tuples. """ # skip parens if name[-2:] == '()': name = name[:-2] if not name: return [] objects = self.data['objects'] matches = [] newname = None if searchmode == 1: if type is None: objtypes = list(self.object_types) else: objtypes = self.objtypes_for_role(type) if objtypes is not None: if modname and classname: fullname = modname + '.' + classname + '.' + name if fullname in objects and objects[fullname][1] in objtypes: newname = fullname if not newname: if modname and modname + '.' + name in objects and \ objects[modname + '.' + name][1] in objtypes: newname = modname + '.' + name elif name in objects and objects[name][1] in objtypes: newname = name else: # "fuzzy" searching mode searchname = '.' + name matches = [(oname, objects[oname]) for oname in objects if oname.endswith(searchname) and objects[oname][1] in objtypes] else: # NOTE: searching for exact match, object type is not considered if name in objects: newname = name elif type == 'mod': # only exact matches allowed for modules return [] elif classname and classname + '.' + name in objects: newname = classname + '.' + name elif modname and modname + '.' + name in objects: newname = modname + '.' + name elif modname and classname and \ modname + '.' + classname + '.' + name in objects: newname = modname + '.' + classname + '.' + name # special case: object methods elif type in ('func', 'meth', 'signal', ) and '.' not in name and \ 'object.' + name in objects: newname = 'object.' + name if newname is not None: matches.append((newname, objects[newname])) return matches def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode): modname = node.get('gobject:module') clsname = node.get('gobject:class') # FIXME searchmode = 0 # node.hasprop('refspecific') and 1 or 0 matches = self.find_obj(env, modname, clsname, target, type, searchmode) if not matches: return None elif len(matches) > 1: env.warn_node( 'more than one target found for cross-reference ' '%r: %s' % (target, ', '.join(match[0] for match in matches)), node) name, obj = matches[0] if obj[1] == 'module': return self._make_module_refnode(builder, fromdocname, name, contnode) else: return make_refnode(builder, fromdocname, obj[0], name, contnode, name) def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): modname = node.get('gobject:module') clsname = node.get('gobject:class') results = [] # always search in "refspecific" mode with the :any: role matches = self.find_obj(env, modname, clsname, target, None, 1) for name, obj in matches: if obj[1] == 'module': results.append(('gobject:mod', self._make_module_refnode(builder, fromdocname, name, contnode))) else: results.append(('gobject:' + self.role_for_objtype(obj[1]), make_refnode(builder, fromdocname, obj[0], name, contnode, name))) return results def _make_module_refnode(self, builder, fromdocname, name, contnode): # get additional info for modules docname, synopsis, platform, deprecated = self.data['modules'][name] title = name if synopsis: title += ': ' + synopsis if deprecated: title += _(' (deprecated)') if platform: title += ' (' + platform + ')' return make_refnode(builder, fromdocname, docname, 'module-' + name, contnode, title) def get_objects(self): for modname, info in iteritems(self.data['modules']): yield (modname, modname, 'module', info[0], 'module-' + modname, 0) for refname, (docname, type) in iteritems(self.data['objects']): if type != 'module': # modules are already handled yield (refname, refname, type, docname, refname, 1)
class TrafficServerDomain(Domain): """ Apache Traffic Server Documentation. """ name = 'ts' label = 'Traffic Server' data_version = 2 object_types = { 'cv': ObjType(l_('configuration variable'), 'cv'), 'stat': ObjType(l_('statistic'), 'stat') } directives = {'cv': TSConfVar, 'stat': TSStat} roles = {'cv': TSConfVarRef(), 'stat': TSStatRef()} initial_data = { 'cv': {}, # full name -> docname 'stat': {} } dangling_warnings = { 'cv': "No definition found for configuration variable '%(target)s'", 'stat': "No definition found for statistic '%(target)s'" } def clear_doc(self, docname): cv_list = self.data['cv'] for var, doc in cv_list.items(): if doc == docname: del cv_list[var] stat_list = self.data['stat'] for var, doc in stat_list.items(): if doc == docname: del stat_list[var] def find_doc(self, key, obj_type): zret = None if obj_type == 'cv': obj_list = self.data['cv'] elif obj_type == 'stat': obj_list = self.data['stat'] else: obj_list = None if obj_list and key in obj_list: zret = obj_list[key] return zret def resolve_xref(self, env, src_doc, builder, obj_type, target, node, cont_node): dst_doc = self.find_doc(target, obj_type) if (dst_doc): return sphinx.util.nodes.make_refnode(builder, src_doc, dst_doc, nodes.make_id(target), cont_node, 'records.config') def get_objects(self): for var, doc in self.data['cv'].iteritems(): yield var, var, 'cv', doc, var, 1 for var, doc in self.data['stat'].iteritems(): yield var, var, 'stat', doc, var, 1
class AvroFixedField(AvroObject): prefix = 'fixed' doc_field_types = [Field('size', label=l_('Size'), names=('size', ))]
class StandardDomain(Domain): """ Domain for all objects that don't fit into another domain or are added via the application interface. """ name = 'std' label = 'Default' object_types = { 'term': ObjType(l_('glossary term'), 'term', searchprio=-1), 'token': ObjType(l_('grammar token'), 'token', searchprio=-1), 'label': ObjType(l_('reference label'), 'ref', 'keyword', searchprio=-1), 'envvar': ObjType(l_('environment variable'), 'envvar'), 'cmdoption': ObjType(l_('program option'), 'option'), 'doc': ObjType(l_('document'), 'doc', searchprio=-1) } # type: Dict[unicode, ObjType] directives = { 'program': Program, 'cmdoption': Cmdoption, # old name for backwards compatibility 'option': Cmdoption, 'envvar': EnvVar, 'glossary': Glossary, 'productionlist': ProductionList, } # type: Dict[unicode, Type[Directive]] roles = { 'option': OptionXRefRole(warn_dangling=True), 'envvar': EnvVarXRefRole(), # links to tokens in grammar productions 'token': XRefRole(), # links to terms in glossary 'term': XRefRole(lowercase=True, innernodeclass=nodes.inline, warn_dangling=True), # links to headings or arbitrary labels 'ref': XRefRole(lowercase=True, innernodeclass=nodes.inline, warn_dangling=True), # links to labels of numbered figures, tables and code-blocks 'numref': XRefRole(lowercase=True, warn_dangling=True), # links to labels, without a different title 'keyword': XRefRole(warn_dangling=True), # links to documents 'doc': XRefRole(warn_dangling=True, innernodeclass=nodes.inline), } # type: Dict[unicode, Union[RoleFunction, XRefRole]] initial_data = { 'progoptions': {}, # (program, name) -> docname, labelid 'objects': {}, # (type, name) -> docname, labelid 'citations': {}, # name -> docname, labelid 'labels': { # labelname -> docname, labelid, sectionname 'genindex': ('genindex', '', l_('Index')), 'modindex': ('py-modindex', '', l_('Module Index')), 'search': ('search', '', l_('Search Page')), }, 'anonlabels': { # labelname -> docname, labelid 'genindex': ('genindex', ''), 'modindex': ('py-modindex', ''), 'search': ('search', ''), }, } dangling_warnings = { 'term': 'term not in glossary: %(target)s', 'ref': 'undefined label: %(target)s (if the link has no caption ' 'the label must precede a section header)', 'numref': 'undefined label: %(target)s', 'keyword': 'unknown keyword: %(target)s', 'doc': 'unknown document: %(target)s', 'option': 'unknown option: %(target)s', 'citation': 'citation not found: %(target)s', } enumerable_nodes = { # node_class -> (figtype, title_getter) nodes.figure: ('figure', None), nodes.table: ('table', None), nodes.container: ('code-block', None), } # type: Dict[nodes.Node, Tuple[unicode, Callable]] def clear_doc(self, docname): # type: (unicode) -> None for key, (fn, _l) in list(self.data['progoptions'].items()): if fn == docname: del self.data['progoptions'][key] for key, (fn, _l) in list(self.data['objects'].items()): if fn == docname: del self.data['objects'][key] for key, (fn, _l) in list(self.data['citations'].items()): if fn == docname: del self.data['citations'][key] for key, (fn, _l, _l) in list(self.data['labels'].items()): if fn == docname: del self.data['labels'][key] for key, (fn, _l) in list(self.data['anonlabels'].items()): if fn == docname: del self.data['anonlabels'][key] def merge_domaindata(self, docnames, otherdata): # type: (List[unicode], Dict) -> None # XXX duplicates? for key, data in otherdata['progoptions'].items(): if data[0] in docnames: self.data['progoptions'][key] = data for key, data in otherdata['objects'].items(): if data[0] in docnames: self.data['objects'][key] = data for key, data in otherdata['citations'].items(): if data[0] in docnames: self.data['citations'][key] = data for key, data in otherdata['labels'].items(): if data[0] in docnames: self.data['labels'][key] = data for key, data in otherdata['anonlabels'].items(): if data[0] in docnames: self.data['anonlabels'][key] = data def process_doc(self, env, docname, document): # type: (BuildEnvironment, unicode, nodes.Node) -> None self.note_citations(env, docname, document) self.note_labels(env, docname, document) def note_citations(self, env, docname, document): # type: (BuildEnvironment, unicode, nodes.Node) -> None for node in document.traverse(nodes.citation): label = node[0].astext() if label in self.data['citations']: path = env.doc2path(self.data['citations'][label][0]) logger.warning('duplicate citation %s, other instance in %s', label, path, location=node) self.data['citations'][label] = (docname, node['ids'][0]) def note_labels(self, env, docname, document): # type: (BuildEnvironment, unicode, nodes.Node) -> None labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in iteritems(document.nametypes): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if node.tagname == 'target' and 'refid' in node: # indirect hyperlink targets node = document.ids.get(node['refid']) labelid = node['names'][0] if name.isdigit() or 'refuri' in node or \ node.tagname.startswith('desc_'): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: logger.warning('duplicate label %s, ' % name + 'other instance ' 'in ' + env.doc2path(labels[name][0]), location=node) anonlabels[name] = docname, labelid if node.tagname in ('section', 'rubric'): sectname = clean_astext(node[0]) # node[0] == title node elif self.is_enumerable_node(node): sectname = self.get_numfig_title(node) if not sectname: continue elif node.traverse(addnodes.toctree): n = node.traverse(addnodes.toctree)[0] if n.get('caption'): sectname = n['caption'] else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname def build_reference_node(self, fromdocname, builder, docname, labelid, sectname, rolename, **options): # type: (unicode, Builder, unicode, unicode, unicode, unicode, Any) -> nodes.Node nodeclass = options.pop('nodeclass', nodes.reference) newnode = nodeclass('', '', internal=True, **options) innernode = nodes.inline(sectname, sectname) if innernode.get('classes') is not None: innernode['classes'].append('std') innernode['classes'].append('std-' + rolename) if docname == fromdocname: newnode['refid'] = labelid else: # set more info in contnode; in case the # get_relative_uri call raises NoUri, # the builder will then have to resolve these contnode = addnodes.pending_xref('') contnode['refdocname'] = docname contnode['refsectname'] = sectname newnode['refuri'] = builder.get_relative_uri( fromdocname, docname) if labelid: newnode['refuri'] += '#' + labelid newnode.append(innernode) return newnode def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA if typ == 'ref': resolver = self._resolve_ref_xref elif typ == 'numref': resolver = self._resolve_numref_xref elif typ == 'keyword': resolver = self._resolve_keyword_xref elif typ == 'doc': resolver = self._resolve_doc_xref elif typ == 'option': resolver = self._resolve_option_xref elif typ == 'citation': resolver = self._resolve_citation_xref else: resolver = self._resolve_obj_xref return resolver(env, fromdocname, builder, typ, target, node, contnode) def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA if node['refexplicit']: # reference to anonymous label; the reference uses # the supplied link caption docname, labelid = self.data['anonlabels'].get(target, ('', '')) sectname = node.astext() else: # reference to named label; the final node will # contain the section name after the label docname, labelid, sectname = self.data['labels'].get(target, ('', '', '')) if not docname: return None return self.build_reference_node(fromdocname, builder, docname, labelid, sectname, 'ref') def _resolve_numref_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA if target in self.data['labels']: docname, labelid, figname = self.data['labels'].get(target, ('', '', '')) else: docname, labelid = self.data['anonlabels'].get(target, ('', '')) figname = None if not docname: return None if env.config.numfig is False: logger.warning('numfig is disabled. :numref: is ignored.', location=node) return contnode target_node = env.get_doctree(docname).ids.get(labelid) figtype = self.get_figtype(target_node) if figtype is None: return None try: fignumber = self.get_fignumber(env, builder, figtype, docname, target_node) if fignumber is None: return contnode except ValueError: logger.warning("no number is assigned for %s: %s", figtype, labelid, location=node) return contnode try: if node['refexplicit']: title = contnode.astext() else: title = env.config.numfig_format.get(figtype, '') if figname is None and '{name}' in title: logger.warning('the link has no caption: %s', title, location=node) return contnode else: fignum = '.'.join(map(str, fignumber)) if '{name}' in title or 'number' in title: # new style format (cf. "Fig.{number}") if figname: newtitle = title.format(name=figname, number=fignum) else: newtitle = title.format(number=fignum) else: # old style format (cf. "Fig.%s") newtitle = title % fignum except KeyError as exc: logger.warning('invalid numfig_format: %s (%r)', title, exc, location=node) return contnode except TypeError: logger.warning('invalid numfig_format: %s', title, location=node) return contnode return self.build_reference_node(fromdocname, builder, docname, labelid, newtitle, 'numref', nodeclass=addnodes.number_reference, title=title) def _resolve_keyword_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA # keywords are oddballs: they are referenced by named labels docname, labelid, _ = self.data['labels'].get(target, ('', '', '')) if not docname: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) def _resolve_doc_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA # directly reference to document by source name; can be absolute or relative refdoc = node.get('refdoc', fromdocname) docname = docname_join(refdoc, node['reftarget']) if docname not in env.all_docs: return None else: if node['refexplicit']: # reference with explicit title caption = node.astext() else: caption = clean_astext(env.titles[docname]) innernode = nodes.inline(caption, caption, classes=['doc']) return make_refnode(builder, fromdocname, docname, None, innernode) def _resolve_option_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA progname = node.get('std:program') target = target.strip() docname, labelid = self.data['progoptions'].get((progname, target), ('', '')) if not docname: commands = [] while ws_re.search(target): subcommand, target = ws_re.split(target, 1) commands.append(subcommand) progname = "-".join(commands) docname, labelid = self.data['progoptions'].get((progname, target), ('', '')) if docname: break else: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) def _resolve_citation_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA from sphinx.environment import NoUri docname, labelid = self.data['citations'].get(target, ('', '')) if not docname: if 'ids' in node: # remove ids attribute that annotated at # transforms.CitationReference.apply. del node['ids'][:] return None try: return make_refnode(builder, fromdocname, docname, labelid, contnode) except NoUri: # remove the ids we added in the CitationReferences # transform since they can't be transfered to # the contnode (if it's a Text node) if not isinstance(contnode, nodes.Element): del node['ids'][:] raise def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA objtypes = self.objtypes_for_role(typ) or [] for objtype in objtypes: if (objtype, target) in self.data['objects']: docname, labelid = self.data['objects'][objtype, target] break else: docname, labelid = '', '' if not docname: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]] # NOQA results = [] # type: List[Tuple[unicode, nodes.Node]] ltarget = target.lower() # :ref: lowercases its target automatically for role in ('ref', 'option'): # do not try "keyword" res = self.resolve_xref(env, fromdocname, builder, role, ltarget if role == 'ref' else target, node, contnode) if res: results.append(('std:' + role, res)) # all others for objtype in self.object_types: key = (objtype, target) if objtype == 'term': key = (objtype, ltarget) if key in self.data['objects']: docname, labelid = self.data['objects'][key] results.append(('std:' + self.role_for_objtype(objtype), make_refnode(builder, fromdocname, docname, labelid, contnode))) return results def get_objects(self): # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]] # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) for (prog, option), info in iteritems(self.data['progoptions']): yield (option, option, 'option', info[0], info[1], 1) for (type, name), info in iteritems(self.data['objects']): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, info in iteritems(self.data['labels']): yield (name, info[2], 'label', info[0], info[1], -1) # add anonymous-only labels as well non_anon_labels = set(self.data['labels']) for name, info in iteritems(self.data['anonlabels']): if name not in non_anon_labels: yield (name, name, 'label', info[0], info[1], -1) def get_type_name(self, type, primary=False): # type: (ObjType, bool) -> unicode # never prepend "Default" return type.lname def is_enumerable_node(self, node): # type: (nodes.Node) -> bool return node.__class__ in self.enumerable_nodes def get_numfig_title(self, node): # type: (nodes.Node) -> unicode """Get the title of enumerable nodes to refer them using its title""" if self.is_enumerable_node(node): _, title_getter = self.enumerable_nodes.get(node.__class__, (None, None)) if title_getter: return title_getter(node) else: for subnode in node: if subnode.tagname in ('caption', 'title'): return clean_astext(subnode) return None def get_figtype(self, node): # type: (nodes.Node) -> unicode """Get figure type of nodes.""" def has_child(node, cls): # type: (nodes.Node, Type) -> bool return any(isinstance(child, cls) for child in node) if isinstance(node, nodes.section): return 'section' elif isinstance(node, nodes.container): if node.get('literal_block') and has_child(node, nodes.literal_block): return 'code-block' else: return None else: figtype, _ = self.enumerable_nodes.get(node.__class__, (None, None)) return figtype def get_fignumber(self, env, builder, figtype, docname, target_node): # type: (BuildEnvironment, Builder, unicode, unicode, nodes.Node) -> Tuple[int, ...] if figtype == 'section': if builder.name == 'latex': return tuple() elif docname not in env.toc_secnumbers: raise ValueError # no number assigned else: anchorname = '#' + target_node['ids'][0] if anchorname not in env.toc_secnumbers[docname]: # try first heading which has no anchor return env.toc_secnumbers[docname].get('') else: return env.toc_secnumbers[docname].get(anchorname) else: try: figure_id = target_node['ids'][0] return env.toc_fignumbers[docname][figtype][figure_id] except (KeyError, IndexError): # target_node is found, but fignumber is not assigned. # Maybe it is defined in orphaned document. raise ValueError
class AvroEnum(AvroObject): prefix = 'enum' doc_field_types = [ Field('symbols', label=l_('Symbols'), names=('symbols', )) ]
class StandardDomain(Domain): """ Domain for all objects that don't fit into another domain or are added via the application interface. """ name = 'std' label = 'Default' object_types = { 'term': ObjType(l_('glossary term'), 'term', searchprio=-1), 'token': ObjType(l_('grammar token'), 'token', searchprio=-1), 'label': ObjType(l_('reference label'), 'ref', searchprio=-1), 'envvar': ObjType(l_('environment variable'), 'envvar'), 'cmdoption': ObjType(l_('program option'), 'option'), } directives = { 'program': Program, 'cmdoption': Cmdoption, # old name for backwards compatibility 'option': Cmdoption, 'envvar': EnvVar, 'glossary': Glossary, 'productionlist': ProductionList, } roles = { 'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis), 'envvar': EnvVarXRefRole(), # links to tokens in grammar productions 'token': XRefRole(), # links to terms in glossary 'term': XRefRole(lowercase=True, innernodeclass=nodes.emphasis, warn_dangling=True), # links to headings or arbitrary labels 'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis, warn_dangling=True), # links to labels, without a different title 'keyword': XRefRole(warn_dangling=True), } initial_data = { 'progoptions': {}, # (program, name) -> docname, labelid 'objects': {}, # (type, name) -> docname, labelid 'labels': { # labelname -> docname, labelid, sectionname 'genindex': ('genindex', '', l_('Index')), 'modindex': ('py-modindex', '', l_('Module Index')), 'search': ('search', '', l_('Search Page')), }, 'anonlabels': { # labelname -> docname, labelid 'genindex': ('genindex', ''), 'modindex': ('py-modindex', ''), 'search': ('search', ''), }, } dangling_warnings = { 'term': 'term not in glossary: %(target)s', 'ref': 'undefined label: %(target)s (if the link has no caption ' 'the label must precede a section header)', 'keyword': 'unknown keyword: %(target)s', } def clear_doc(self, docname): for key, (fn, _) in self.data['progoptions'].items(): if fn == docname: del self.data['progoptions'][key] for key, (fn, _) in self.data['objects'].items(): if fn == docname: del self.data['objects'][key] for key, (fn, _, _) in self.data['labels'].items(): if fn == docname: del self.data['labels'][key] for key, (fn, _) in self.data['anonlabels'].items(): if fn == docname: del self.data['anonlabels'][key] def process_doc(self, env, docname, document): labels, anonlabels = self.data['labels'], self.data['anonlabels'] for name, explicit in document.nametypes.iteritems(): if not explicit: continue labelid = document.nameids[name] if labelid is None: continue node = document.ids[labelid] if name.isdigit() or node.has_key('refuri') or \ node.tagname.startswith('desc_'): # ignore footnote labels, labels automatically generated from a # link and object descriptions continue if name in labels: env.warn(docname, 'duplicate label %s, ' % name + 'other instance in ' + env.doc2path(labels[name][0]), node.line) anonlabels[name] = docname, labelid if node.tagname == 'section': sectname = clean_astext(node[0]) # node[0] == title node elif node.tagname == 'figure': for n in node: if n.tagname == 'caption': sectname = clean_astext(n) break else: continue elif node.tagname == 'table': for n in node: if n.tagname == 'title': sectname = clean_astext(n) break else: continue else: # anonymous-only labels continue labels[name] = docname, labelid, sectname def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): if typ == 'ref': if node['refexplicit']: # reference to anonymous label; the reference uses # the supplied link caption docname, labelid = self.data['anonlabels'].get(target, ('','')) sectname = node.astext() else: # reference to named label; the final node will # contain the section name after the label docname, labelid, sectname = self.data['labels'].get(target, ('','','')) if not docname: return None newnode = nodes.reference('', '', internal=True) innernode = nodes.emphasis(sectname, sectname) if docname == fromdocname: newnode['refid'] = labelid else: # set more info in contnode; in case the # get_relative_uri call raises NoUri, # the builder will then have to resolve these contnode = addnodes.pending_xref('') contnode['refdocname'] = docname contnode['refsectname'] = sectname newnode['refuri'] = builder.get_relative_uri( fromdocname, docname) if labelid: newnode['refuri'] += '#' + labelid newnode.append(innernode) return newnode elif typ == 'keyword': # keywords are oddballs: they are referenced by named labels docname, labelid, _ = self.data['labels'].get(target, ('','','')) if not docname: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) elif typ == 'option': progname = node['refprogram'] docname, labelid = self.data['progoptions'].get((progname, target), ('', '')) if not docname: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) else: objtypes = self.objtypes_for_role(typ) or [] for objtype in objtypes: if (objtype, target) in self.data['objects']: docname, labelid = self.data['objects'][objtype, target] break else: docname, labelid = '', '' if not docname: return None return make_refnode(builder, fromdocname, docname, labelid, contnode) def get_objects(self): for (prog, option), info in self.data['progoptions'].iteritems(): yield (option, option, 'option', info[0], info[1], 1) for (type, name), info in self.data['objects'].iteritems(): yield (name, name, type, info[0], info[1], self.object_types[type].attrs['searchprio']) for name, info in self.data['labels'].iteritems(): yield (name, info[2], 'label', info[0], info[1], -1) def get_type_name(self, type, primary=False): # never prepend "Default" return type.lname
def get_signature_prefix(self, sig): if self.env.app.config.dirty_model_class_label is None: return super(DirtyModelDirective, self).get_signature_prefix() return '{} '.format(l_(self.env.app.config.dirty_model_class_label))
class EnvVar(GenericObject): indextemplate = l_('environment variable; %s')
def get_type(cls): return ObjType(l_(cls.long_name), cls.short_name, cls.long_name, 'obj')
github.setup(app) app.add_directive('exercise', Exercise) app.add_node( exercise, html=(lambda self, node: self.visit_admonition(node, 'exercise'), lambda self, node: self.depart_admonition(node)), latex=(lambda self, node: self.visit_admonition(node), lambda self, node: self.depart_admonition(node))) from docutils import nodes from docutils.parsers.rst.directives import admonitions class exercise(nodes.Admonition, nodes.Element): pass class Exercise(admonitions.BaseAdmonition): node_class = exercise from sphinx.locale import admonitionlabels, l_ admonitionlabels['exercise'] = l_('Exercise') # monkeypatch PHP lexer to not require <?php from sphinx.highlighting import lexers from pygments.lexers.web import PhpLexer lexers['php'] = PhpLexer(startinline=True)
class FortranDomain(Domain): """Fortran language domain.""" name = 'f' label = 'Fortran' object_types = { 'program': ObjType(l_('program'), 'prog'), 'type': ObjType(l_('type'), 'type'), 'variable': ObjType(l_('variable'), 'var'), 'function': ObjType(l_('function'), 'func'), 'subroutine': ObjType(l_('subroutine'), 'func', 'subr'), 'module': ObjType(l_('module'), 'mod'), } directives = { 'program': FortranProgram, 'type': FortranType, 'variable': FortranObject, 'function': FortranWithSig, 'subroutine': FortranWithSig, 'module': FortranModule, 'currentmodule': FortranCurrentModule, } roles = { 'prog': FortranXRefRole(), 'type': FortranXRefRole(), 'var': FortranXRefRole(), 'func': FortranXRefRole(fix_parens=True), 'subr': FortranXRefRole(fix_parens=True), 'mod': FortranXRefRole(), } initial_data = { 'objects': {}, # fullname -> docname, objtype 'modules': {}, # modname -> docname, synopsis, platform, deprecated } indices = [ FortranModuleIndex, ] def clear_doc(self, docname): for fullname, (fn, _) in self.data['objects'].items(): if fn == docname: del self.data['objects'][fullname] for modname, (fn, _, _, _) in self.data['modules'].items(): if fn == docname: del self.data['modules'][modname] def find_obj(self, env, modname, name, role, searchorder=0): """ Find a Fortran object for "name", perhaps using the given module and/or typename. :Params: - **searchorder**, optional: Start using relative search """ # skip parens if name.endswith('()'): name = name[:-2] if not name: return None, None if f_sep in name: modname, name = name.split(f_sep) #modname = modname or '_' if '%' in name: name, tmp = name.split('%') objects = self.data['objects'] newname = None matches = [] objtypes = self.objtypes_for_role(role) if searchorder == 1: # :role:`/toto` if role in ['mod', 'prog']: if 'f' + f_sep + name not in objects: # exact match return [] newname = 'f' + f_sep + name elif modname and 'f'+f_sep + modname + f_sep + name in objects and \ objects['f'+f_sep + modname + f_sep + name][1] in objtypes: newname = 'f' + f_sep + modname + f_sep + name elif 'f'+f_sep + '_' + f_sep + name in objects and \ objects['f'+f_sep + '_' + f_sep + name][1] in objtypes: newname = 'f' + f_sep + '_' + f_sep + name elif 'f'+f_sep + name in objects and \ objects['f'+f_sep + name][1] in objtypes: newname = 'f' + f_sep + name elif name in objects and \ objects[name][1] in objtypes: newname = name else: # :role:`toto` # NOTE: searching for exact match, object type is not considered if 'f' + f_sep + name in objects: newname = 'f' + f_sep + name elif role in ['mod', 'prog']: # only exact matches allowed for modules return [] elif 'f' + f_sep + '_' + f_sep + name in objects: newname = 'f' + f_sep + '_' + f_sep + name elif modname and 'f' + f_sep + modname + f_sep + name in objects: newname = 'f' + f_sep + modname + f_sep + name # Last chance: fuzzy search if newname is None: matches = [ (oname, objects[oname]) for oname in objects if oname.endswith(f_sep + name) and objects[oname][1] in objtypes ] else: matches.append((newname, objects[newname])) return matches def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode): modname = node.get('f:module', node.get('modname')) typename = node.get('f:type', node.get('typename')) searchorder = node.hasattr('refspecific') and 1 or 0 matches = self.find_obj(env, modname, target, type, searchorder) if not matches: return None elif len(matches) > 1: env.warn( fromdocname, 'more than one target found for cross-reference ' '%r: %s' % (target, ', '.join(match[0] for match in matches)), node.line) name, obj = matches[0] if obj[1] == 'module': # get additional info for modules docname, synopsis, platform, deprecated = self.data['modules'][ name[1 + len(f_sep):]] assert docname == obj[0] title = name if synopsis: title += ': ' + synopsis if deprecated: title += _(' (deprecated)') #return make_refnode(builder, fromdocname, docname, #'module-' + name, contnode, title) return make_refnode(builder, fromdocname, docname, name, contnode, title) else: return make_refnode(builder, fromdocname, obj[0], name, contnode, name) def get_objects(self): for modname, info in self.data['modules'].iteritems(): yield (modname, modname, 'module', info[0], 'module-' + modname, 0) for refname, (docname, type) in self.data['objects'].iteritems(): yield (refname, refname, type, docname, refname, 1)
class ElixirDomain(PolyglotDomain): name, label = 'ex', l_('Elixir') directives = { 'module': make_namespace_directive('module'), 'package': make_directive('package'), }
def document_function(funcdef, docstrings=None, protocols=['restjson']): """A helper function to complete a function documentation with return and parameter types""" # If the function doesn't have a docstring, add an empty list # so the default behaviors below work correctly. if not docstrings: docstrings = [[]] found_params = set() for si, docstring in enumerate(docstrings): for i, line in enumerate(docstring): m = field_re.match(line) if m and m.group('field') == 'param': found_params.add(m.group('name')) next_param_pos = (0, 0) for arg in funcdef.arguments: content = [ u':type %s: :wsme:type:`%s`' % ( arg.name, datatypename(arg.datatype)) ] if arg.name not in found_params: content.insert(0, u':param %s: ' % (arg.name)) pos = next_param_pos else: for si, docstring in enumerate(docstrings): for i, line in enumerate(docstring): m = field_re.match(line) if m and m.group('field') == 'param' \ and m.group('name') == arg.name: pos = (si, i + 1) break docstring = docstrings[pos[0]] docstring[pos[1]:pos[1]] = content next_param_pos = (pos[0], pos[1] + len(content)) if funcdef.return_type: content = [ u':rtype: %s' % datatypename(funcdef.return_type) ] pos = None for si, docstring in enumerate(docstrings): for i, line in enumerate(docstring): m = field_re.match(line) if m and m.group('field') == 'return': pos = (si, i + 1) break else: pos = next_param_pos docstring = docstrings[pos[0]] docstring[pos[1]:pos[1]] = content codesamples = [] if protocols: params = [] for arg in funcdef.arguments: params.append(( arg.name, arg.datatype, make_sample_object(arg.datatype) )) codesamples.extend([ u':%s:' % l_(u'Parameters samples'), u' .. cssclass:: toggle', u'' ]) for name, protocol in protocols: language, sample = protocol.encode_sample_params( params, format=True) codesamples.extend([ u' ' * 4 + name, u' .. code-block:: ' + language, u'', ]) codesamples.extend(( u' ' * 12 + line for line in sample.split('\n'))) if funcdef.return_type: codesamples.extend([ u':%s:' % l_(u'Return samples'), u' .. cssclass:: toggle', u'' ]) sample_obj = make_sample_object(funcdef.return_type) for name, protocol in protocols: language, sample = protocol.encode_sample_result( funcdef.return_type, sample_obj, format=True) codesamples.extend([ u' ' * 4 + name, u' .. code-block:: ' + language, u'', ]) codesamples.extend(( u' ' * 12 + line for line in sample.split('\n'))) docstrings[0:0] = [codesamples] return docstrings
class FortranObject(ObjectDescription): """ Description of a general Fortran object. """ option_spec = { 'noindex': directives.flag, 'module': directives.unchanged, 'type': directives.unchanged, 'shape': parse_shape, 'attrs': directives.unchanged, } doc_field_types = [ FortranCompleteField( 'parameter', label=l_('Parameters'), names=('p', 'param', 'parameter', 'a', 'arg', 'argument'), #rolename='var', typerolename='type', typenames=('paramtype', 'type', 'ptype'), shapenames=('shape', 'pshape'), attrnames=('attrs', 'pattrs', 'attr'), can_collapse=True), FortranCompleteField( 'optional', label=l_('Options'), names=('o', 'optional', 'opt', 'keyword', 'option'), #rolename='var', typerolename='type', typenames=('optparamtype', 'otype'), shapenames=('oshape', ), attrnames=('oattrs', 'oattr'), can_collapse=True), FortranCompleteField( 'typefield', label=l_('Type fields'), names=('f', 'field', 'typef', 'typefield'), #rolename='typef', typerolename='type', typenames=('fieldtype', 'ftype'), shapenames=('fshape', ), attrnames=('fattrs', 'fattr'), prefix='% ', strong=False, can_collapse=False), FortranCompleteField('return', label=l_('Return'), names=('r', 'return', 'returns'), typerolename='type', typenames=('returntype', 'rtype'), shapenames=('rshape', ), attrnames=('rattrs', 'rattr'), can_collapse=True), FortranCallField('calledfrom', label=l_('Called from'), names=('calledfrom', 'from')), FortranCallField('callto', label=l_('Call to'), names=('callto', 'to')), ] # These Fortran types aren't described anywhere, so don't try to create # a cross-reference to them stopwords = set(('float', 'integer', 'character', 'double', 'long')) _parens = '' # def _parse_type(self, node, ftype): # m = f_type_re.match(ftype) # tnode = nodes.Text(ftype, ftype) # modname = self.options.get( # 'module', self.env.temp_data.get('f:module')) # if m : # ftype = m.groups(0) # if ftype not in self.stopwords: # pnode = addnodes.pending_xref( # '', refdomain='f', reftype='type', reftarget=ftype, # modname=modname) # pnode += tnode # node += pnode # else: # node += tnode # else: # node += tnode 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 Fortran 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 = f_sig_re.match(sig) if m is None: raise ValueError ftype, objtype, modname, typename, name, arglist = m.groups() if not typename: typename = "" # determine module, type, shape and attributes modname = (modname and modname[:-1]) or self.options.get( 'module', self.env.temp_data.get('f:module')) if typename: name = typename[:-1] attrs = self.options.get('attrs') shape = parse_shape(self.options.get('shape')) ftype = ftype or self.options.get('type') if self.objtype == 'typefield' and not typename: raise ValueError #if typename: name = typename+'%'+name #fullname = name #if modname: if self.objtype == 'program': fullname = name else: fullname = (modname or '_') + f_sep + name signode['module'] = modname signode['type'] = typename signode['fullname'] = fullname # Add "function" or "subroutine" tag sig_prefix = self.get_signature_prefix(sig) if objtype or sig_prefix: objtype = objtype or sig_prefix signode += addnodes.desc_annotation(objtype + ' ', objtype + ' ') # Add module if self.env.config.add_module_names and modname and self.objtype != 'typefield': nodetext = modname + f_sep signode += addnodes.desc_addname(nodetext, nodetext) # Add name signode += addnodes.desc_name(name, name) # In the parenthesis if self.needs_arglist(): # call for functions and subroutines if arglist: # Calling arguments _pseudo_parse_arglist(signode, arglist) elif self.needs_arglist( ): # for callables, add an empty parameter list signode += addnodes.desc_parameterlist() elif arglist and not shape: # Declare shape instead of arguments (variables) shape = arglist # Add remaining self.add_shape_and_attrs(signode, modname, ftype, shape, attrs) return fullname, ftype def add_shape_and_attrs(self, signode, modname, ftype, shape, attrs): # add shape if shape: add_shape(signode, shape, modname=modname) #signode += nodes.Text(' '+shape) # add type ('float', 'interger', etc) if ftype or attrs: signode += nodes.emphasis(' [', ' [') if ftype: refnode = addnodes.pending_xref( '', refdomain='f', reftype='type', reftarget=ftype, modname=modname, ) refnode += nodes.emphasis(ftype, ftype) signode += refnode #tnode = addnodes.desc_type(ftype, ftype) #tnode += #signode += addnodes.desc_type(ftype, ftype) #signode += # signode += addnodes.desc_type('', '') # self._parse_type(signode[-1], ftype) if attrs: if ftype: signode += nodes.emphasis(',', ',') for iatt, att in enumerate(re.split('\s*,\s*', attrs)): if iatt: signode += nodes.emphasis(',', ',') if att.startswith('parameter'): value = att.split('=')[1] signode += nodes.emphasis('parameter=', 'parameter=') convert_arithm(signode, value, modname=modname) else: signode += nodes.emphasis(att, att) #signode += nodes.emphasis(attrs, attrs) if ftype or attrs: signode += nodes.emphasis(']', ']') def add_target_and_index(self, name, sig, signode): #modname = self.options.get( #'module', self.env.temp_data.get('f:module')) modname = signode.get('module', self.env.temp_data.get('f:module')) # fullname = (modname and modname + '/' or '') + name[0] fullname = 'f' + f_sep + name[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['f']['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, fullname) if indextext: self.indexnode['entries'].append( ('single', indextext, fullname, fullname)) def before_content(self): # needed for automatic qualification of fields (reset in subclasses) self.typename_set = False def after_content(self): if self.typename_set: self.env.temp_data['f:type'] = None def get_index_text(self, modname, name): add_modules = self.env.config.add_module_names if name.startswith('f' + f_sep): name = name[2:] mn = modname or '_' sobj = '' if name.startswith(mn + f_sep): name = name[len(mn) + 1:] if self.objtype == 'type': sobj = _('fortran type') if self.objtype == 'typefield': sobj = _('fortran type field') elif self.objtype == 'variable': sobj = _('fortran variable') elif self.objtype == 'subroutine': sobj = _('fortran subroutine') elif self.objtype == 'function': sobj = _('fortran function') elif self.objtype == 'module': sobj = _('fortran module') modname = '' elif self.objtype == 'program': sobj = _('fortran program') modname = '' sinmodule = (_(' in module %s') % modname) if modname and add_modules else '' return '%s%s (%s%s)' % (name, self._parens, sobj, sinmodule)