def _AddMember(member_name, member_obj, proto): """Add the child object to the object being constructed.""" _, member_obj = tf_decorator.unwrap(member_obj) if member_name == '__init__' or not member_name.startswith('_'): if tf_inspect.isroutine(member_obj): new_method = proto.member_method.add() new_method.name = member_name # If member_obj is a python builtin, there is no way to get its # argspec, because it is implemented on the C side. It also has no # func_code. if getattr(member_obj, 'func_code', None): new_method.argspec = _SanitizedArgSpec(member_obj) else: new_member = proto.member.add() new_member.name = member_name new_member.mtype = str(type(member_obj))
def _AddMember(member_name, member_obj, proto): """Add the child object to the object being constructed.""" _, member_obj = tf_decorator.unwrap(member_obj) if (_SkipMember(parent, member_name) or member_obj == deprecation.HIDDEN_ATTRIBUTE): return if member_name == '__init__' or not member_name.startswith('_'): if tf_inspect.isroutine(member_obj): new_method = proto.member_method.add() new_method.name = member_name # If member_obj is a python builtin, there is no way to get its # argspec, because it is implemented on the C side. It also has no # func_code. if hasattr(member_obj, '__code__'): new_method.argspec = _SanitizedArgSpec(member_obj) else: new_member = proto.member.add() new_member.name = member_name new_member.mtype = _NormalizeType(str(type(member_obj)))
def testIsRoutine(self): self.assertTrue(tf_inspect.isroutine(len)) self.assertFalse(tf_inspect.isroutine(TestDecoratedClass))
def collect_docs_for_class(self, py_class, parser_config): """Collect information necessary specifically for a class's doc page. Mainly, this is details about information about the class's members. Args: py_class: the class object being documented parser_config: An instance of ParserConfig. """ doc_path = documentation_path(self.full_name) relative_path = os.path.relpath( path='.', start=os.path.dirname(doc_path) or '.') for short_name in parser_config.tree[self.full_name]: # Remove builtin members that we never want to document. if short_name in ['__class__', '__base__', '__weakref__', '__doc__', '__module__', '__dict__', '__abstractmethods__', '__slots__', '__getnewargs__']: continue child_name = '.'.join([self.full_name, short_name]) child = parser_config.py_name_to_object(child_name) # Don't document anything that is defined in object or by protobuf. defining_class = _get_defining_class(py_class, short_name) if (defining_class is object or defining_class is type or defining_class is tuple or defining_class is BaseException or defining_class is Exception or # The following condition excludes most protobuf-defined symbols. defining_class and defining_class.__name__ in ['CMessage', 'Message', 'MessageMeta']): continue # TODO(markdaoust): Add a note in child docs showing the defining class. child_doc = _parse_md_docstring(child, relative_path, parser_config.reference_resolver) if isinstance(child, property): self._add_property(short_name, child_name, child, child_doc) elif tf_inspect.isclass(child): if defining_class is None: continue url = parser_config.reference_resolver.reference_to_url( child_name, relative_path) self._add_class(short_name, child_name, child, child_doc, url) elif (tf_inspect.ismethod(child) or tf_inspect.isfunction(child) or tf_inspect.isroutine(child)): if defining_class is None: continue # Omit methods defined by namedtuple. original_method = defining_class.__dict__[short_name] if (hasattr(original_method, '__module__') and (original_method.__module__ or '').startswith('namedtuple')): continue # Some methods are often overridden without documentation. Because it's # obvious what they do, don't include them in the docs if there's no # docstring. if not child_doc.brief.strip() and short_name in [ '__str__', '__repr__', '__hash__', '__del__', '__copy__']: print('Skipping %s, defined in %s, no docstring.' % (child_name, defining_class)) continue try: child_signature = _generate_signature(child, parser_config.reverse_index) except TypeError: # If this is a (dynamically created) slot wrapper, tf_inspect will # raise typeerror when trying to get to the code. Ignore such # functions. continue self._add_method(short_name, child_name, child, child_doc, child_signature) else: # Exclude members defined by protobuf that are useless if issubclass(py_class, ProtoMessage): if (short_name.endswith('_FIELD_NUMBER') or short_name in ['__slots__', 'DESCRIPTOR']): continue # TODO(wicke): We may want to also remember the object itself. self._add_other_member(short_name, child_name, child, child_doc)
def docs_for_object(full_name, py_object, parser_config): """Return a PageInfo object describing a given object from the TF API. This function uses _parse_md_docstring to parse the docs pertaining to `object`. This function resolves '@{symbol}' references in the docstrings into links to the appropriate location. It also adds a list of alternative names for the symbol automatically. It assumes that the docs for each object live in a file given by `documentation_path`, and that relative links to files within the documentation are resolvable. Args: full_name: The fully qualified name of the symbol to be documented. py_object: The Python object to be documented. Its documentation is sourced from `py_object`'s docstring. parser_config: A ParserConfig object. Returns: Either a `_FunctionPageInfo`, `_ClassPageInfo`, or a `_ModulePageInfo` depending on the type of the python object being documented. Raises: RuntimeError: If an object is encountered for which we don't know how to make docs. """ # Which other aliases exist for the object referenced by full_name? master_name = parser_config.reference_resolver.py_master_name(full_name) duplicate_names = parser_config.duplicates.get(master_name, [full_name]) # TODO(wicke): Once other pieces are ready, enable this also for partials. if (tf_inspect.ismethod(py_object) or tf_inspect.isfunction(py_object) or # Some methods in classes from extensions come in as routines. tf_inspect.isroutine(py_object)): page_info = _FunctionPageInfo(master_name) page_info.set_signature(py_object, parser_config.reverse_index) elif tf_inspect.isclass(py_object): page_info = _ClassPageInfo(master_name) page_info.collect_docs_for_class(py_object, parser_config) elif tf_inspect.ismodule(py_object): page_info = _ModulePageInfo(master_name) page_info.collect_docs_for_module(parser_config) else: raise RuntimeError('Cannot make docs for object %s: %r' % (full_name, py_object)) relative_path = os.path.relpath( path='.', start=os.path.dirname(documentation_path(full_name)) or '.') page_info.set_doc(_parse_md_docstring( py_object, relative_path, parser_config.reference_resolver)) page_info.set_aliases(duplicate_names) page_info.set_guides(_get_guides_markdown( duplicate_names, parser_config.guide_index, relative_path)) page_info.set_defined_in(_get_defined_in(py_object, parser_config)) return page_info
def collect_docs_for_class(self, py_class, parser_config): """Collect information necessary specifically for a class's doc page. Mainly, this is details about information about the class's members. Args: py_class: the class object being documented parser_config: An instance of ParserConfig. """ doc_path = documentation_path(self.full_name) relative_path = os.path.relpath(path='.', start=os.path.dirname(doc_path) or '.') for short_name in parser_config.tree[self.full_name]: # Remove builtin members that we never want to document. if short_name in [ '__class__', '__base__', '__weakref__', '__doc__', '__module__', '__dict__', '__abstractmethods__', '__slots__', '__getnewargs__' ]: continue child_name = '.'.join([self.full_name, short_name]) child = parser_config.py_name_to_object(child_name) # Don't document anything that is defined in object or by protobuf. defining_class = _get_defining_class(py_class, short_name) if (defining_class is object or defining_class is type or defining_class is tuple or defining_class is BaseException or defining_class is Exception or # The following condition excludes most protobuf-defined symbols. defining_class and defining_class.__name__ in ['CMessage', 'Message', 'MessageMeta']): continue # TODO(markdaoust): Add a note in child docs showing the defining class. child_doc = _parse_md_docstring(child, relative_path, parser_config.reference_resolver) if isinstance(child, property): self._add_property(short_name, child_name, child, child_doc) elif tf_inspect.isclass(child): if defining_class is None: continue url = parser_config.reference_resolver.reference_to_url( child_name, relative_path) self._add_class(short_name, child_name, child, child_doc, url) elif (tf_inspect.ismethod(child) or tf_inspect.isfunction(child) or tf_inspect.isroutine(child)): if defining_class is None: continue # Omit methods defined by namedtuple. original_method = defining_class.__dict__[short_name] if (hasattr(original_method, '__module__') and (original_method.__module__ or '').startswith('namedtuple')): continue # Some methods are often overridden without documentation. Because it's # obvious what they do, don't include them in the docs if there's no # docstring. if not child_doc.brief.strip() and short_name in [ '__str__', '__repr__', '__hash__', '__del__', '__copy__' ]: print('Skipping %s, defined in %s, no docstring.' % (child_name, defining_class)) continue try: child_signature = _generate_signature( child, parser_config.reverse_index) except TypeError: # If this is a (dynamically created) slot wrapper, tf_inspect will # raise typeerror when trying to get to the code. Ignore such # functions. continue self._add_method(short_name, child_name, child, child_doc, child_signature) else: # Exclude members defined by protobuf that are useless if issubclass(py_class, ProtoMessage): if (short_name.endswith('_FIELD_NUMBER') or short_name in ['__slots__', 'DESCRIPTOR']): continue # TODO(wicke): We may want to also remember the object itself. self._add_other_member(short_name, child_name, child, child_doc)
def docs_for_object(full_name, py_object, parser_config): """Return a PageInfo object describing a given object from the TF API. This function uses _parse_md_docstring to parse the docs pertaining to `object`. This function resolves '@{symbol}' references in the docstrings into links to the appropriate location. It also adds a list of alternative names for the symbol automatically. It assumes that the docs for each object live in a file given by `documentation_path`, and that relative links to files within the documentation are resolvable. Args: full_name: The fully qualified name of the symbol to be documented. py_object: The Python object to be documented. Its documentation is sourced from `py_object`'s docstring. parser_config: A ParserConfig object. Returns: Either a `_FunctionPageInfo`, `_ClassPageInfo`, or a `_ModulePageInfo` depending on the type of the python object being documented. Raises: RuntimeError: If an object is encountered for which we don't know how to make docs. """ # Which other aliases exist for the object referenced by full_name? master_name = parser_config.reference_resolver.py_master_name(full_name) duplicate_names = parser_config.duplicates.get(master_name, [full_name]) # TODO(wicke): Once other pieces are ready, enable this also for partials. if (tf_inspect.ismethod(py_object) or tf_inspect.isfunction(py_object) or # Some methods in classes from extensions come in as routines. tf_inspect.isroutine(py_object)): page_info = _FunctionPageInfo(master_name) page_info.set_signature(py_object, parser_config.reverse_index) elif tf_inspect.isclass(py_object): page_info = _ClassPageInfo(master_name) page_info.collect_docs_for_class(py_object, parser_config) elif tf_inspect.ismodule(py_object): page_info = _ModulePageInfo(master_name) page_info.collect_docs_for_module(parser_config) else: raise RuntimeError('Cannot make docs for object %s: %r' % (full_name, py_object)) relative_path = os.path.relpath( path='.', start=os.path.dirname(documentation_path(full_name)) or '.') page_info.set_doc( _parse_md_docstring(py_object, relative_path, parser_config.reference_resolver)) page_info.set_aliases(duplicate_names) page_info.set_guides( _get_guides_markdown(duplicate_names, parser_config.guide_index, relative_path)) page_info.set_defined_in(_get_defined_in(py_object, parser_config)) return page_info