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