1# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Documentation control decorators."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21from typing import TypeVar
22
23T = TypeVar("T")
24
25
26_DEPRECATED = "_tf_docs_deprecated"
27
28
29def set_deprecated(obj: T) -> T:
30  """Explicitly tag an object as deprecated for the doc generator."""
31  setattr(obj, _DEPRECATED, None)
32  return obj
33
34
35_DO_NOT_DOC = "_tf_docs_do_not_document"
36
37
38def do_not_generate_docs(obj: T) -> T:
39  """A decorator: Do not generate docs for this object.
40
41  For example the following classes:
42
43  ```
44  class Parent(object):
45    def method1(self):
46      pass
47    def method2(self):
48      pass
49
50  class Child(Parent):
51    def method1(self):
52      pass
53    def method2(self):
54      pass
55  ```
56
57  Produce the following api_docs:
58
59  ```
60  /Parent.md
61    # method1
62    # method2
63  /Child.md
64    # method1
65    # method2
66  ```
67
68  This decorator allows you to skip classes or methods:
69
70  ```
71  @do_not_generate_docs
72  class Parent(object):
73    def method1(self):
74      pass
75    def method2(self):
76      pass
77
78  class Child(Parent):
79    @do_not_generate_docs
80    def method1(self):
81      pass
82    def method2(self):
83      pass
84  ```
85
86  This will only produce the following docs:
87
88  ```
89  /Child.md
90    # method2
91  ```
92
93  Note: This is implemented by adding a hidden attribute on the object, so it
94  cannot be used on objects which do not allow new attributes to be added. So
95  this decorator must go *below* `@property`, `@classmethod`,
96  or `@staticmethod`:
97
98  ```
99  class Example(object):
100    @property
101    @do_not_generate_docs
102    def x(self):
103      return self._x
104  ```
105
106  Args:
107    obj: The object to hide from the generated docs.
108
109  Returns:
110    obj
111  """
112  setattr(obj, _DO_NOT_DOC, None)
113  return obj
114
115
116_DO_NOT_DOC_INHERITABLE = "_tf_docs_do_not_doc_inheritable"
117
118
119def do_not_doc_inheritable(obj: T) -> T:
120  """A decorator: Do not generate docs for this method.
121
122  This version of the decorator is "inherited" by subclasses. No docs will be
123  generated for the decorated method in any subclass. Even if the sub-class
124  overrides the method.
125
126  For example, to ensure that `method1` is **never documented** use this
127  decorator on the base-class:
128
129  ```
130  class Parent(object):
131    @do_not_doc_inheritable
132    def method1(self):
133      pass
134    def method2(self):
135      pass
136
137  class Child(Parent):
138    def method1(self):
139      pass
140    def method2(self):
141      pass
142  ```
143  This will produce the following docs:
144
145  ```
146  /Parent.md
147    # method2
148  /Child.md
149    # method2
150  ```
151
152  When generating docs for a class's arributes, the `__mro__` is searched and
153  the attribute will be skipped if this decorator is detected on the attribute
154  on any class in the `__mro__`.
155
156  Note: This is implemented by adding a hidden attribute on the object, so it
157  cannot be used on objects which do not allow new attributes to be added. So
158  this decorator must go *below* `@property`, `@classmethod`,
159  or `@staticmethod`:
160
161  ```
162  class Example(object):
163    @property
164    @do_not_doc_inheritable
165    def x(self):
166      return self._x
167  ```
168
169  Args:
170    obj: The class-attribute to hide from the generated docs.
171
172  Returns:
173    obj
174  """
175  setattr(obj, _DO_NOT_DOC_INHERITABLE, None)
176  return obj
177
178
179_FOR_SUBCLASS_IMPLEMENTERS = "_tf_docs_tools_for_subclass_implementers"
180
181
182def for_subclass_implementers(obj: T) -> T:
183  """A decorator: Only generate docs for this method in the defining class.
184
185  Also group this method's docs with and `@abstractmethod` in the class's docs.
186
187  No docs will generated for this class attribute in sub-classes.
188
189  The canonical use case for this is `tf.keras.layers.Layer.call`: It's a
190  public method, essential for anyone implementing a subclass, but it should
191  never be called directly.
192
193  Works on method, or other class-attributes.
194
195  When generating docs for a class's arributes, the `__mro__` is searched and
196  the attribute will be skipped if this decorator is detected on the attribute
197  on any **parent** class in the `__mro__`.
198
199  For example:
200
201  ```
202  class Parent(object):
203    @for_subclass_implementers
204    def method1(self):
205      pass
206    def method2(self):
207      pass
208
209  class Child1(Parent):
210    def method1(self):
211      pass
212    def method2(self):
213      pass
214
215  class Child2(Parent):
216    def method1(self):
217      pass
218    def method2(self):
219      pass
220  ```
221
222  This will produce the following docs:
223
224  ```
225  /Parent.md
226    # method1
227    # method2
228  /Child1.md
229    # method2
230  /Child2.md
231    # method2
232  ```
233
234  Note: This is implemented by adding a hidden attribute on the object, so it
235  cannot be used on objects which do not allow new attributes to be added. So
236  this decorator must go *below* `@property`, `@classmethod`,
237  or `@staticmethod`:
238
239  ```
240  class Example(object):
241    @property
242    @for_subclass_implementers
243    def x(self):
244      return self._x
245  ```
246
247  Args:
248    obj: The class-attribute to hide from the generated docs.
249
250  Returns:
251    obj
252  """
253  setattr(obj, _FOR_SUBCLASS_IMPLEMENTERS, None)
254  return obj
255
256
257do_not_doc_in_subclasses = for_subclass_implementers
258
259_DOC_PRIVATE = "_tf_docs_doc_private"
260
261
262def doc_private(obj: T) -> T:
263  """A decorator: Generates docs for private methods/functions.
264
265  For example:
266
267  ```
268  class Try:
269
270    @doc_controls.doc_private
271    def _private(self):
272      ...
273  ```
274
275  As a rule of thumb, private(beginning with `_`) methods/functions are
276  not documented.
277
278  This decorator allows to force document a private method/function.
279
280  Args:
281    obj: The class-attribute to hide from the generated docs.
282
283  Returns:
284    obj
285  """
286
287  setattr(obj, _DOC_PRIVATE, None)
288  return obj
289
290
291_DOC_IN_CURRENT_AND_SUBCLASSES = "_tf_docs_doc_in_current_and_subclasses"
292
293
294def doc_in_current_and_subclasses(obj: T) -> T:
295  """Overrides `do_not_doc_in_subclasses` decorator.
296
297  If this decorator is set on a child class's method whose parent's method
298  contains `do_not_doc_in_subclasses`, then that will be overriden and the
299  child method will get documented. All classes inherting from the child will
300  also document that method.
301
302  For example:
303
304  ```
305  class Parent:
306    @do_not_doc_in_subclasses
307    def method1(self):
308      pass
309    def method2(self):
310      pass
311
312  class Child1(Parent):
313    @doc_in_current_and_subclasses
314    def method1(self):
315      pass
316    def method2(self):
317      pass
318
319  class Child2(Parent):
320    def method1(self):
321      pass
322    def method2(self):
323      pass
324
325  class Child11(Child1):
326    pass
327  ```
328
329  This will produce the following docs:
330
331  ```
332  /Parent.md
333    # method1
334    # method2
335  /Child1.md
336    # method1
337    # method2
338  /Child2.md
339    # method2
340  /Child11.md
341    # method1
342    # method2
343  ```
344
345  Args:
346    obj: The class-attribute to hide from the generated docs.
347
348  Returns:
349    obj
350  """
351
352  setattr(obj, _DOC_IN_CURRENT_AND_SUBCLASSES, None)
353  return obj
354