aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/tools/docs/parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'tensorflow/tools/docs/parser.py')
-rw-r--r--tensorflow/tools/docs/parser.py90
1 files changed, 55 insertions, 35 deletions
diff --git a/tensorflow/tools/docs/parser.py b/tensorflow/tools/docs/parser.py
index 549056c6c4..a6159fa692 100644
--- a/tensorflow/tools/docs/parser.py
+++ b/tensorflow/tools/docs/parser.py
@@ -35,6 +35,28 @@ from tensorflow.python.util import tf_inspect
from tensorflow.tools.docs import doc_controls
+def is_free_function(py_object, full_name, index):
+ """Check if input is a free function (and not a class- or static method).
+
+ Args:
+ py_object: The the object in question.
+ full_name: The full name of the object, like `tf.module.symbol`.
+ index: The {full_name:py_object} dictionary for the public API.
+
+ Returns:
+ True if the obeject is a stand-alone function, and not part of a class
+ definition.
+ """
+ if not tf_inspect.isfunction(py_object):
+ return False
+
+ parent_name = full_name.rsplit('.', 1)[0]
+ if tf_inspect.isclass(index[parent_name]):
+ return False
+
+ return True
+
+
# A regular expression capturing a python identifier.
IDENTIFIER_RE = r'[a-zA-Z_]\w*'
@@ -74,7 +96,7 @@ class _Errors(object):
return self._errors == other._errors # pylint: disable=protected-access
-def documentation_path(full_name):
+def documentation_path(full_name, is_fragment=False):
"""Returns the file path for the documentation for the given API symbol.
Given the fully qualified name of a library symbol, compute the path to which
@@ -84,12 +106,22 @@ def documentation_path(full_name):
Args:
full_name: Fully qualified name of a library symbol.
-
+ is_fragment: If `False` produce a direct markdown link (`tf.a.b.c` -->
+ `tf/a/b/c.md`). If `True` produce fragment link, `tf.a.b.c` -->
+ `tf/a/b.md#c`
Returns:
The file path to which to write the documentation for `full_name`.
"""
- dirs = full_name.split('.')
- return os.path.join(*dirs) + '.md'
+ parts = full_name.split('.')
+ if is_fragment:
+ parts, fragment = parts[:-1], parts[-1]
+
+ result = os.path.join(*parts) + '.md'
+
+ if is_fragment:
+ result = result + '#' + fragment
+
+ return result
def _get_raw_docstring(py_object):
@@ -136,8 +168,7 @@ class ReferenceResolver(object):
doc.
"""
- def __init__(self, duplicate_of, doc_index, is_class, is_module,
- py_module_names):
+ def __init__(self, duplicate_of, doc_index, is_fragment, py_module_names):
"""Initializes a Reference Resolver.
Args:
@@ -145,15 +176,15 @@ class ReferenceResolver(object):
symbols.
doc_index: A `dict` mapping symbol name strings to objects with `url`
and `title` fields. Used to resolve @{$doc} references in docstrings.
- is_class: A map from full names to bool for each symbol.
- is_module: A map from full names to bool for each symbol.
+ is_fragment: A map from full names to bool for each symbol. If True the
+ object lives at a page fragment `tf.a.b.c` --> `tf/a/b#c`. If False
+ object has a page to itself: `tf.a.b.c` --> `tf/a/b/c`.
py_module_names: A list of string names of Python modules.
"""
self._duplicate_of = duplicate_of
self._doc_index = doc_index
- self._is_class = is_class
- self._is_module = is_module
- self._all_names = set(is_class.keys())
+ self._is_fragment = is_fragment
+ self._all_names = set(is_fragment.keys())
self._py_module_names = py_module_names
self.current_doc_full_name = None
@@ -180,21 +211,18 @@ class ReferenceResolver(object):
Returns:
an instance of `ReferenceResolver` ()
"""
- is_class = {
- name: tf_inspect.isclass(visitor.index[name])
- for name, obj in visitor.index.items()
- }
+ is_fragment = {}
+ for name, obj in visitor.index.items():
+ has_page = (
+ tf_inspect.isclass(obj) or tf_inspect.ismodule(obj) or
+ is_free_function(obj, name, visitor.index))
- is_module = {
- name: tf_inspect.ismodule(visitor.index[name])
- for name, obj in visitor.index.items()
- }
+ is_fragment[name] = not has_page
return cls(
duplicate_of=visitor.duplicate_of,
doc_index=doc_index,
- is_class=is_class,
- is_module=is_module,
+ is_fragment=is_fragment,
**kwargs)
@classmethod
@@ -210,6 +238,10 @@ class ReferenceResolver(object):
Args:
filepath: The file path to write the json to.
"""
+ try:
+ os.makedirs(os.path.dirname(filepath))
+ except OSError:
+ pass
json_dict = {}
for key, value in self.__dict__.items():
# Drop these two fields. `_doc_index` is not serializable. `_all_names` is
@@ -223,7 +255,7 @@ class ReferenceResolver(object):
json_dict[key.lstrip('_')] = value
with open(filepath, 'w') as f:
- json.dump(json_dict, f)
+ json.dump(json_dict, f, indent=2, sort_keys=True)
def replace_references(self, string, relative_path_to_root):
"""Replace "@{symbol}" references with links to symbol's documentation page.
@@ -339,19 +371,7 @@ class ReferenceResolver(object):
raise TFDocsError(
'Cannot make link to "%s": Not in index.' % master_name)
- # If this is a member of a class, link to the class page with an anchor.
- ref_path = None
- if not (self._is_class[master_name] or self._is_module[master_name]):
- idents = master_name.split('.')
- if len(idents) > 1:
- class_name = '.'.join(idents[:-1])
- assert class_name in self._all_names
- if self._is_class[class_name]:
- ref_path = documentation_path(class_name) + '#%s' % idents[-1]
-
- if not ref_path:
- ref_path = documentation_path(master_name)
-
+ ref_path = documentation_path(master_name, self._is_fragment[master_name])
return os.path.join(relative_path_to_root, ref_path)
def _one_ref(self, match, relative_path_to_root):