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_INHERITABLE_HEADER = "_tf_docs_inheritable_header" 36 37 38def inheritable_header(text): 39 40 def _wrapped(cls): 41 setattr(cls, _INHERITABLE_HEADER, text) 42 return cls 43 44 return _wrapped 45 46 47_DO_NOT_DOC = "_tf_docs_do_not_document" 48 49 50def do_not_generate_docs(obj: T) -> T: 51 """A decorator: Do not generate docs for this object. 52 53 For example the following classes: 54 55 ``` 56 class Parent(object): 57 def method1(self): 58 pass 59 def method2(self): 60 pass 61 62 class Child(Parent): 63 def method1(self): 64 pass 65 def method2(self): 66 pass 67 ``` 68 69 Produce the following api_docs: 70 71 ``` 72 /Parent.md 73 # method1 74 # method2 75 /Child.md 76 # method1 77 # method2 78 ``` 79 80 This decorator allows you to skip classes or methods: 81 82 ``` 83 @do_not_generate_docs 84 class Parent(object): 85 def method1(self): 86 pass 87 def method2(self): 88 pass 89 90 class Child(Parent): 91 @do_not_generate_docs 92 def method1(self): 93 pass 94 def method2(self): 95 pass 96 ``` 97 98 This will only produce the following docs: 99 100 ``` 101 /Child.md 102 # method2 103 ``` 104 105 Note: This is implemented by adding a hidden attribute on the object, so it 106 cannot be used on objects which do not allow new attributes to be added. So 107 this decorator must go *below* `@property`, `@classmethod`, 108 or `@staticmethod`: 109 110 ``` 111 class Example(object): 112 @property 113 @do_not_generate_docs 114 def x(self): 115 return self._x 116 ``` 117 118 Args: 119 obj: The object to hide from the generated docs. 120 121 Returns: 122 obj 123 """ 124 setattr(obj, _DO_NOT_DOC, None) 125 return obj 126 127 128_DO_NOT_DOC_INHERITABLE = "_tf_docs_do_not_doc_inheritable" 129 130 131def do_not_doc_inheritable(obj: T) -> T: 132 """A decorator: Do not generate docs for this method. 133 134 This version of the decorator is "inherited" by subclasses. No docs will be 135 generated for the decorated method in any subclass. Even if the sub-class 136 overrides the method. 137 138 For example, to ensure that `method1` is **never documented** use this 139 decorator on the base-class: 140 141 ``` 142 class Parent(object): 143 @do_not_doc_inheritable 144 def method1(self): 145 pass 146 def method2(self): 147 pass 148 149 class Child(Parent): 150 def method1(self): 151 pass 152 def method2(self): 153 pass 154 ``` 155 This will produce the following docs: 156 157 ``` 158 /Parent.md 159 # method2 160 /Child.md 161 # method2 162 ``` 163 164 When generating docs for a class's arributes, the `__mro__` is searched and 165 the attribute will be skipped if this decorator is detected on the attribute 166 on any class in the `__mro__`. 167 168 Note: This is implemented by adding a hidden attribute on the object, so it 169 cannot be used on objects which do not allow new attributes to be added. So 170 this decorator must go *below* `@property`, `@classmethod`, 171 or `@staticmethod`: 172 173 ``` 174 class Example(object): 175 @property 176 @do_not_doc_inheritable 177 def x(self): 178 return self._x 179 ``` 180 181 Args: 182 obj: The class-attribute to hide from the generated docs. 183 184 Returns: 185 obj 186 """ 187 setattr(obj, _DO_NOT_DOC_INHERITABLE, None) 188 return obj 189 190 191_FOR_SUBCLASS_IMPLEMENTERS = "_tf_docs_tools_for_subclass_implementers" 192 193 194def for_subclass_implementers(obj: T) -> T: 195 """A decorator: Only generate docs for this method in the defining class. 196 197 Also group this method's docs with and `@abstractmethod` in the class's docs. 198 199 No docs will generated for this class attribute in sub-classes. 200 201 The canonical use case for this is `tf.keras.layers.Layer.call`: It's a 202 public method, essential for anyone implementing a subclass, but it should 203 never be called directly. 204 205 Works on method, or other class-attributes. 206 207 When generating docs for a class's arributes, the `__mro__` is searched and 208 the attribute will be skipped if this decorator is detected on the attribute 209 on any **parent** class in the `__mro__`. 210 211 For example: 212 213 ``` 214 class Parent(object): 215 @for_subclass_implementers 216 def method1(self): 217 pass 218 def method2(self): 219 pass 220 221 class Child1(Parent): 222 def method1(self): 223 pass 224 def method2(self): 225 pass 226 227 class Child2(Parent): 228 def method1(self): 229 pass 230 def method2(self): 231 pass 232 ``` 233 234 This will produce the following docs: 235 236 ``` 237 /Parent.md 238 # method1 239 # method2 240 /Child1.md 241 # method2 242 /Child2.md 243 # method2 244 ``` 245 246 Note: This is implemented by adding a hidden attribute on the object, so it 247 cannot be used on objects which do not allow new attributes to be added. So 248 this decorator must go *below* `@property`, `@classmethod`, 249 or `@staticmethod`: 250 251 ``` 252 class Example(object): 253 @property 254 @for_subclass_implementers 255 def x(self): 256 return self._x 257 ``` 258 259 Args: 260 obj: The class-attribute to hide from the generated docs. 261 262 Returns: 263 obj 264 """ 265 setattr(obj, _FOR_SUBCLASS_IMPLEMENTERS, None) 266 return obj 267 268 269do_not_doc_in_subclasses = for_subclass_implementers 270 271_DOC_PRIVATE = "_tf_docs_doc_private" 272 273 274def doc_private(obj: T) -> T: 275 """A decorator: Generates docs for private methods/functions. 276 277 For example: 278 279 ``` 280 class Try: 281 282 @doc_controls.doc_private 283 def _private(self): 284 ... 285 ``` 286 287 As a rule of thumb, private(beginning with `_`) methods/functions are 288 not documented. 289 290 This decorator allows to force document a private method/function. 291 292 Args: 293 obj: The class-attribute to hide from the generated docs. 294 295 Returns: 296 obj 297 """ 298 299 setattr(obj, _DOC_PRIVATE, None) 300 return obj 301 302 303_DOC_IN_CURRENT_AND_SUBCLASSES = "_tf_docs_doc_in_current_and_subclasses" 304 305 306def doc_in_current_and_subclasses(obj: T) -> T: 307 """Overrides `do_not_doc_in_subclasses` decorator. 308 309 If this decorator is set on a child class's method whose parent's method 310 contains `do_not_doc_in_subclasses`, then that will be overriden and the 311 child method will get documented. All classes inherting from the child will 312 also document that method. 313 314 For example: 315 316 ``` 317 class Parent: 318 @do_not_doc_in_subclasses 319 def method1(self): 320 pass 321 def method2(self): 322 pass 323 324 class Child1(Parent): 325 @doc_in_current_and_subclasses 326 def method1(self): 327 pass 328 def method2(self): 329 pass 330 331 class Child2(Parent): 332 def method1(self): 333 pass 334 def method2(self): 335 pass 336 337 class Child11(Child1): 338 pass 339 ``` 340 341 This will produce the following docs: 342 343 ``` 344 /Parent.md 345 # method1 346 # method2 347 /Child1.md 348 # method1 349 # method2 350 /Child2.md 351 # method2 352 /Child11.md 353 # method1 354 # method2 355 ``` 356 357 Args: 358 obj: The class-attribute to hide from the generated docs. 359 360 Returns: 361 obj 362 """ 363 364 setattr(obj, _DOC_IN_CURRENT_AND_SUBCLASSES, None) 365 return obj 366