misc
1import abc 2from ctypes import Structure 3from dataclasses import dataclass 4import functools 5from functools import cached_property 6from functools import lru_cache 7import sched 8from typing import Generic 9from typing import TypeVar 10 11# https://github.com/mitmproxy/pdoc/issues/226 12 13 14class Descriptor: 15 def __init__(self, func): 16 self.__doc__ = func.__doc__ 17 18 def __get__(self, instance, owner): 19 return self if instance is None else getattr(instance, "_x", 0) 20 21 def __set__(self, instance, value): 22 instance._x = value 23 24 25class Issue226: 26 @Descriptor 27 def size(self): 28 """This is the size""" 29 30 31# Testing function and object default values 32 33 34def default_func(): 35 pass 36 37 38default_obj = object() 39 40var_with_default_obj = default_obj 41"""this shouldn't render the object address""" 42var_with_default_func = default_func 43"""this just renders like a normal function""" 44 45 46def func_with_defaults(a=default_obj, b=default_func): 47 """this shouldn't render object or function addresses""" 48 pass 49 50 51# Testing classmethod links in code 52class ClassmethodLink: 53 """ 54 You can either do 55 56 >>> ClassmethodLink.bar() 57 42 58 59 or 60 61 ```python 62 ClassmethodLink.bar() 63 ``` 64 65 neither will be linked. 66 """ 67 68 @classmethod 69 def bar(cls): 70 return 42 71 72 73# Testing generic bases 74 75T = TypeVar("T") 76 77 78class GenericParent(Generic[T]): 79 """GenericParent""" 80 81 82class NonGenericChild(GenericParent[str]): 83 """NonGenericChild""" 84 85 86# Testing docstring inheritance 87 88 89class Base: 90 def __init__(self): 91 """init""" 92 super().__init__() 93 94 def foo(self): 95 """foo""" 96 pass 97 98 @classmethod 99 def bar(cls): 100 """bar""" 101 pass 102 103 @staticmethod 104 def baz(): 105 """baz""" 106 pass 107 108 @property 109 def qux(self): 110 """qux""" 111 return 112 113 @cached_property 114 def quux(self): 115 """quux""" 116 return 117 118 quuux: int = 42 119 """quuux""" 120 121 122class Child(Base): 123 def __init__(self): 124 super().__init__() 125 126 def foo(self): 127 pass 128 129 @classmethod 130 def bar(cls): 131 pass 132 133 @staticmethod 134 def baz(): 135 pass 136 137 @property 138 def qux(self): 139 return 140 141 @cached_property 142 def quux(self): 143 return 144 145 quuux: int = 42 146 147 148# Testing that an attribute that is only annotated does not trigger a "submodule not found" warning. 149 150only_annotated: int 151 152 153# Testing that a private class in __all__ is displayed 154 155 156class _Private: 157 """private class""" 158 159 pass 160 161 def _do(self): 162 """private method""" 163 164 165# Testing a class attribute that is a lambda (which generates quirky sources) 166 167 168class LambdaAttr: 169 # not really supported, but also shouldn't crash. 170 attr = lambda x: 42 # noqa 171 172 173# Testing different docstring annotations 174# fmt: off 175 176 177def foo(): 178 """no indents""" 179 180 181def bar(): 182 """no 183indents""" 184 185 186def baz(): 187 """one 188 indent""" 189 190 191def qux(): 192 """ 193 two 194 indents 195 """ 196 197 198class Indented: 199 def foo(self): 200 """no indents""" 201 202 def bar(self): 203 """no 204indents""" 205 206 def baz(self): 207 """one 208 indent""" 209 210 def qux(self): 211 """ 212 two 213 indents 214 """ 215 216 @lru_cache() 217 def foo_decorated(self): 218 """no indents""" 219 220 @lru_cache() 221 # comment 222 def foo_commented(self): 223 """no indents""" 224 225 @lru_cache() 226 def bar_decorated(self): 227 """no 228indents""" 229 230 @lru_cache() 231 def baz_decorated(self): 232 """one 233 indent""" 234 235 @lru_cache() 236 def qux_decorated(self): 237 """ 238 two 239 indents 240 """ 241 242 @lru_cache( 243 maxsize=42 244 ) 245 def quux_decorated(self): 246 """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246""" 247 248 249def _protected_decorator(f): 250 return f 251 252 253@_protected_decorator 254def fun_with_protected_decorator(): 255 """This function has a protected decorator (name starting with a single `_`).""" 256 257 258class UnhashableDataDescriptor: 259 def __get__(self): 260 pass 261 __hash__ = None # type: ignore 262 263 264unhashable = UnhashableDataDescriptor() 265 266 267class AbstractClass(metaclass=abc.ABCMeta): 268 """This class shouldn't show a constructor as it's abstract.""" 269 @abc.abstractmethod 270 def foo(self): 271 pass 272 273 274# Adapted from https://github.com/mitmproxy/pdoc/issues/320 275 276def make_adder(a: int): 277 def add_func(b: int) -> int: 278 """This function adds two numbers.""" 279 return a + b 280 return add_func 281 282 283add_four = make_adder(4) 284add_five = make_adder(5) 285"""This function adds five.""" 286add_six = make_adder(6) 287add_six.__doc__ = "This function adds six." 288 289 290# Adapted from https://github.com/mitmproxy/pdoc/issues/335 291def linkify_links(): 292 """ 293 This docstring contains links that are also identifiers: 294 295 - [`linkify_links`](https://example.com/) 296 - [misc.linkify_links](https://example.com/) 297 - [`linkify_links()`](https://example.com/) 298 - [misc.linkify_links()](https://example.com/) 299 - [link in target](https://example.com/misc.linkify_links) 300 - [explicit linking](#AbstractClass.foo) 301 """ 302 303 304class Issue352aMeta(type): 305 def __call__(cls, *args, **kwargs): 306 """Meta.__call__""" 307 308 309class Issue352a(metaclass=Issue352aMeta): 310 def __init__(self): 311 """Issue352.__init__ should be preferred over Meta.__call__.""" 312 313 314class Issue352bMeta(type): 315 def __call__(cls, *args, **kwargs): 316 pass 317 318 319class Issue352b(metaclass=Issue352bMeta): 320 """No docstrings for the constructor here.""" 321 322 323class CustomCallMeta(type): 324 def __call__(cls, *args, **kwargs): 325 """Custom docstring in metaclass.`__call__`""" 326 327 328class CustomCall(metaclass=CustomCallMeta): 329 """A class where the constructor is defined by its metaclass.""" 330 331 332class Headings: 333 """ 334 # Heading 1 335 336 Here is some text. 337 338 ## Heading 2 339 340 Here is some text. 341 342 ### Heading 3 343 344 Here is some text. 345 346 #### Heading 4 347 348 Here is some text. 349 350 ##### Heading 5 351 352 Here is some text. 353 354 ###### Heading 6 355 356 Here is some text. 357 358 """ 359 360 361class CustomRepr: 362 def __repr__(self): 363 return "°<script>alert(1)</script>" 364 365 366def repr_not_syntax_highlightable(x=CustomRepr()): 367 """The default value for x fails to highlight with pygments.""" 368 369 370class ClassDecorator: 371 """This is a class that wraps a function. It will be documented correctly.""" 372 def __init__(self, func): 373 self._func = func 374 375 376@ClassDecorator 377def another_decorated_function(arg: str) -> str: 378 """This is another decorated function. It will not be documented correctly.""" 379 raise NotImplementedError 380 381 382class SubclassRef: 383 class SubClass: 384 pass 385 386 def __init__(self, x: "SubClass"): 387 print(x) 388 389 390class ClassAsAttribute: 391 static_attr_to_class = ClassDecorator 392 """this is a static attribute that point to a Class (not an instance)""" 393 394 static_attr_to_instance = ClassDecorator(None) 395 """this is a static attribute that point to an instance""" 396 397 398class scheduler(sched.scheduler): 399 """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490""" 400 401 402class __init__: 403 """https://github.com/mitmproxy/pdoc/issues/519""" 404 405 406def dynamically_modify_docstring1(): 407 """this should **not** be the docstring.""" 408 409 410def dynamically_modify_docstring2(): 411 pass 412 413 414dynamically_modify_docstring1.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536" 415dynamically_modify_docstring2.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536" 416 417 418def _docstring_modifier(fn): 419 fn.__doc__ = "https://github.com/mitmproxy/pdoc/issues/536" 420 return fn 421 422 423@_docstring_modifier 424def dynamically_modify_docstring3(): 425 """This should **not** be the docstring.""" 426 427 428@_docstring_modifier 429def dynamically_modify_docstring4(): 430 pass 431 432 433class DocstringFromNew: 434 def __new__(cls, *args, **kwargs): 435 """This is a class with a docstring inferred from `__new__`.""" 436 437 438 439 440 441 442class SingleDispatchMethodExample: 443 @functools.singledispatchmethod 444 def fancymethod(self, str_or_int: str | int): 445 """A fancy method which is capable of handling either `str` or `int`. 446 447 :param str_or_int: string or integer to handle 448 """ 449 raise NotImplementedError(f"{type(str_or_int)=} not implemented!") 450 451 @fancymethod.register 452 def fancymethod_handle_str(self, str_to_handle: str): 453 """Fancy method handles a string. 454 455 :param str_to_handle: string which will be handled 456 """ 457 print(f"{type(str_to_handle)} = '{str_to_handle}") 458 459 @fancymethod.register 460 def _fancymethod_handle_int(self, int_to_handle: int): 461 """Fancy method handles int (not shown in doc). 462 463 :param int_to_handle: int which will be handled 464 """ 465 print(f"{type(int_to_handle)} = '{int_to_handle:x}'") 466 467 468@dataclass(init=False) 469class DataclassStructure(Structure): 470 """DataclassStructure raises for `inspect.signature`.""" 471 472 473class MötörCrüe: 474 "A fictional band with Unicode-characters in its name." 475 476 def créer_naïveté(self): 477 "A function with Unicode-characters in its name." 478 479 480def link_to_unicode(): 481 """The following link should be created properly: 482 483 - `MötörCrüe.créer_naïveté` 484 """ 485 486 487__all__ = [ 488 "Issue226", 489 "var_with_default_obj", 490 "var_with_default_func", 491 "func_with_defaults", 492 "ClassmethodLink", 493 "GenericParent", 494 "NonGenericChild", 495 "Child", 496 "only_annotated", 497 "_Private", 498 "LambdaAttr", 499 "foo", 500 "bar", 501 "baz", 502 "qux", 503 "Indented", 504 "fun_with_protected_decorator", 505 "unhashable", 506 "AbstractClass", 507 "add_four", 508 "add_five", 509 "add_six", 510 "linkify_links", 511 "Issue352a", 512 "Issue352b", 513 "CustomCall", 514 "Headings", 515 "repr_not_syntax_highlightable", 516 "ClassDecorator", 517 "another_decorated_function", 518 "SubclassRef", 519 "ClassAsAttribute", 520 "scheduler", 521 "__init__", 522 "dynamically_modify_docstring1", 523 "dynamically_modify_docstring2", 524 "dynamically_modify_docstring3", 525 "dynamically_modify_docstring4", 526 "DocstringFromNew", 527 "SingleDispatchMethodExample", 528 "DataclassStructure", 529 "MötörCrüe", 530 "link_to_unicode", 531]
this shouldn't render the object address
this just renders like a normal function
47def func_with_defaults(a=default_obj, b=default_func): 48 """this shouldn't render object or function addresses""" 49 pass
this shouldn't render object or function addresses
GenericParent
NonGenericChild
123class Child(Base): 124 def __init__(self): 125 super().__init__() 126 127 def foo(self): 128 pass 129 130 @classmethod 131 def bar(cls): 132 pass 133 134 @staticmethod 135 def baz(): 136 pass 137 138 @property 139 def qux(self): 140 return 141 142 @cached_property 143 def quux(self): 144 return 145 146 quuux: int = 42
157class _Private: 158 """private class""" 159 160 pass 161 162 def _do(self): 163 """private method"""
private class
no indents
no indents
one indent
two indents
199class Indented: 200 def foo(self): 201 """no indents""" 202 203 def bar(self): 204 """no 205indents""" 206 207 def baz(self): 208 """one 209 indent""" 210 211 def qux(self): 212 """ 213 two 214 indents 215 """ 216 217 @lru_cache() 218 def foo_decorated(self): 219 """no indents""" 220 221 @lru_cache() 222 # comment 223 def foo_commented(self): 224 """no indents""" 225 226 @lru_cache() 227 def bar_decorated(self): 228 """no 229indents""" 230 231 @lru_cache() 232 def baz_decorated(self): 233 """one 234 indent""" 235 236 @lru_cache() 237 def qux_decorated(self): 238 """ 239 two 240 indents 241 """ 242 243 @lru_cache( 244 maxsize=42 245 ) 246 def quux_decorated(self): 247 """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
254@_protected_decorator 255def fun_with_protected_decorator(): 256 """This function has a protected decorator (name starting with a single `_`)."""
This function has a protected decorator (name starting with a single _).
268class AbstractClass(metaclass=abc.ABCMeta): 269 """This class shouldn't show a constructor as it's abstract.""" 270 @abc.abstractmethod 271 def foo(self): 272 pass
This class shouldn't show a constructor as it's abstract.
This function adds two numbers.
This function adds five.
This function adds six.
292def linkify_links(): 293 """ 294 This docstring contains links that are also identifiers: 295 296 - [`linkify_links`](https://example.com/) 297 - [misc.linkify_links](https://example.com/) 298 - [`linkify_links()`](https://example.com/) 299 - [misc.linkify_links()](https://example.com/) 300 - [link in target](https://example.com/misc.linkify_links) 301 - [explicit linking](#AbstractClass.foo) 302 """
This docstring contains links that are also identifiers:
No docstrings for the constructor here.
329class CustomCall(metaclass=CustomCallMeta): 330 """A class where the constructor is defined by its metaclass."""
A class where the constructor is defined by its metaclass.
333class Headings: 334 """ 335 # Heading 1 336 337 Here is some text. 338 339 ## Heading 2 340 341 Here is some text. 342 343 ### Heading 3 344 345 Here is some text. 346 347 #### Heading 4 348 349 Here is some text. 350 351 ##### Heading 5 352 353 Here is some text. 354 355 ###### Heading 6 356 357 Here is some text. 358 359 """
Heading 1
Here is some text.
Heading 2
Here is some text.
Heading 3
Here is some text.
Heading 4
Here is some text.
Heading 5
Here is some text.
Heading 6
Here is some text.
367def repr_not_syntax_highlightable(x=CustomRepr()): 368 """The default value for x fails to highlight with pygments."""
The default value for x fails to highlight with pygments.
371class ClassDecorator: 372 """This is a class that wraps a function. It will be documented correctly.""" 373 def __init__(self, func): 374 self._func = func
This is a class that wraps a function. It will be documented correctly.
This is another decorated function. It will not be documented correctly.
391class ClassAsAttribute: 392 static_attr_to_class = ClassDecorator 393 """this is a static attribute that point to a Class (not an instance)""" 394 395 static_attr_to_instance = ClassDecorator(None) 396 """this is a static attribute that point to an instance"""
this is a static attribute that point to a Class (not an instance)
this is a static attribute that point to an instance
399class scheduler(sched.scheduler): 400 """Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490"""
Test for broken links for inherited methods, https://github.com/mitmproxy/pdoc/issues/490
443class SingleDispatchMethodExample: 444 @functools.singledispatchmethod 445 def fancymethod(self, str_or_int: str | int): 446 """A fancy method which is capable of handling either `str` or `int`. 447 448 :param str_or_int: string or integer to handle 449 """ 450 raise NotImplementedError(f"{type(str_or_int)=} not implemented!") 451 452 @fancymethod.register 453 def fancymethod_handle_str(self, str_to_handle: str): 454 """Fancy method handles a string. 455 456 :param str_to_handle: string which will be handled 457 """ 458 print(f"{type(str_to_handle)} = '{str_to_handle}") 459 460 @fancymethod.register 461 def _fancymethod_handle_int(self, int_to_handle: int): 462 """Fancy method handles int (not shown in doc). 463 464 :param int_to_handle: int which will be handled 465 """ 466 print(f"{type(int_to_handle)} = '{int_to_handle:x}'")
444 @functools.singledispatchmethod 445 def fancymethod(self, str_or_int: str | int): 446 """A fancy method which is capable of handling either `str` or `int`. 447 448 :param str_or_int: string or integer to handle 449 """ 450 raise NotImplementedError(f"{type(str_or_int)=} not implemented!")
A fancy method which is capable of handling either str or int.
Parameters
- str_or_int: string or integer to handle
452 @fancymethod.register 453 def fancymethod_handle_str(self, str_to_handle: str): 454 """Fancy method handles a string. 455 456 :param str_to_handle: string which will be handled 457 """ 458 print(f"{type(str_to_handle)} = '{str_to_handle}")
Fancy method handles a string.
Parameters
- str_to_handle: string which will be handled
469@dataclass(init=False) 470class DataclassStructure(Structure): 471 """DataclassStructure raises for `inspect.signature`."""
DataclassStructure raises for inspect.signature.
474class MötörCrüe: 475 "A fictional band with Unicode-characters in its name." 476 477 def créer_naïveté(self): 478 "A function with Unicode-characters in its name."
A fictional band with Unicode-characters in its name.
481def link_to_unicode(): 482 """The following link should be created properly: 483 484 - `MötörCrüe.créer_naïveté` 485 """
The following link should be created properly: