misc

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

This is the size

var_with_default_obj = <object object>

this shouldn't render the object address

def var_with_default_func():
32def default_func():
33    pass

this just renders like a normal function

def func_with_defaults(a=<object object>, b=<function default_func>):
44def func_with_defaults(a=default_obj, b=default_func):
45    """this shouldn't render object or function addresses"""
46    pass

this shouldn't render object or function addresses

class GenericParent(typing.Generic[~T]):
76class GenericParent(Generic[T]):
77    """GenericParent"""

GenericParent

class NonGenericChild(misc.GenericParent[str]):
80class NonGenericChild(GenericParent[str]):
81    """NonGenericChild"""

NonGenericChild

class Child(Base):
120class Child(Base):
121    def __init__(self):
122        super().__init__()
123
124    def foo(self):
125        pass
126
127    @classmethod
128    def bar(cls):
129        pass
130
131    @staticmethod
132    def baz():
133        pass
134
135    @property
136    def qux(self):
137        return
138
139    @cached_property
140    def quux(self):
141        return
142
143    quuux: int = 42
Child()
121    def __init__(self):
122        super().__init__()

init

def foo(self):
124    def foo(self):
125        pass

foo

@classmethod
def bar(cls):
127    @classmethod
128    def bar(cls):
129        pass

bar

@staticmethod
def baz():
131    @staticmethod
132    def baz():
133        pass

baz

qux
135    @property
136    def qux(self):
137        return

qux

quux
139    @cached_property
140    def quux(self):
141        return

quux

quuux: int = 42

quuux

only_annotated: int
class _Private:
154class _Private:
155    """private class"""
156
157    pass
158
159    def _do(self):
160        """private method"""

private class

class LambdaAttr:
166class LambdaAttr:
167    # not really supported, but also shouldn't crash.
168    attr = lambda x: 42  # noqa
def attr(x):
168    attr = lambda x: 42  # noqa
def foo():
175def foo():
176    """no indents"""

no indents

def bar():
179def bar():
180    """no
181indents"""

no indents

def baz():
184def baz():
185    """one
186    indent"""

one indent

def qux():
189def qux():
190    """
191    two
192    indents
193    """

two indents

class Indented:
196class Indented:
197    def foo(self):
198        """no indents"""
199
200    def bar(self):
201        """no
202indents"""
203
204    def baz(self):
205        """one
206        indent"""
207
208    def qux(self):
209        """
210        two
211        indents
212        """
213
214    @lru_cache()
215    def foo_decorated(self):
216        """no indents"""
217
218    @lru_cache()
219    # comment
220    def foo_commented(self):
221        """no indents"""
222
223    @lru_cache()
224    def bar_decorated(self):
225        """no
226indents"""
227
228    @lru_cache()
229    def baz_decorated(self):
230        """one
231        indent"""
232
233    @lru_cache()
234    def qux_decorated(self):
235        """
236        two
237        indents
238        """
239
240    @lru_cache(
241        maxsize=42
242    )
243    def quux_decorated(self):
244        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
def foo(self):
197    def foo(self):
198        """no indents"""

no indents

def bar(self):
200    def bar(self):
201        """no
202indents"""

no indents

def baz(self):
204    def baz(self):
205        """one
206        indent"""

one indent

def qux(self):
208    def qux(self):
209        """
210        two
211        indents
212        """

two indents

@lru_cache()
def foo_decorated(self):
214    @lru_cache()
215    def foo_decorated(self):
216        """no indents"""

no indents

@lru_cache()
def foo_commented(self):
218    @lru_cache()
219    # comment
220    def foo_commented(self):
221        """no indents"""

no indents

@lru_cache()
def bar_decorated(self):
223    @lru_cache()
224    def bar_decorated(self):
225        """no
226indents"""

no indents

@lru_cache()
def baz_decorated(self):
228    @lru_cache()
229    def baz_decorated(self):
230        """one
231        indent"""

one indent

@lru_cache()
def qux_decorated(self):
233    @lru_cache()
234    def qux_decorated(self):
235        """
236        two
237        indents
238        """

two indents

@lru_cache(maxsize=42)
def quux_decorated(self):
240    @lru_cache(
241        maxsize=42
242    )
243    def quux_decorated(self):
244        """multi-line decorator, https://github.com/mitmproxy/pdoc/issues/246"""
def fun_with_protected_decorator():
251@_protected_decorator
252def fun_with_protected_decorator():
253    """This function has a protected decorator (name starting with a single `_`)."""

This function has a protected decorator (name starting with a single _).

def unhashable(unknown):
class AbstractClass:
265class AbstractClass(metaclass=abc.ABCMeta):
266    """This class shouldn't show a constructor as it's abstract."""
267    @abc.abstractmethod
268    def foo(self):
269        pass

This class shouldn't show a constructor as it's abstract.

@abc.abstractmethod
def foo(self):
267    @abc.abstractmethod
268    def foo(self):
269        pass
def add_four(b: int) -> int:
275    def add_func(b: int) -> int:
276        """This function adds two numbers."""
277        return a + b

This function adds two numbers.

def add_five(b: int) -> int:
275    def add_func(b: int) -> int:
276        """This function adds two numbers."""
277        return a + b

This function adds five.

def add_six(b: int) -> int:
275    def add_func(b: int) -> int:
276        """This function adds two numbers."""
277        return a + b

This function adds six.

class Issue352a:
307class Issue352a(metaclass=Issue352aMeta):
308    def __init__(self):
309        """Issue352.__init__ should be preferred over Meta.__call__."""
Issue352a()
308    def __init__(self):
309        """Issue352.__init__ should be preferred over Meta.__call__."""

Issue352.__init__ should be preferred over Meta.__call__.

class Issue352b:
317class Issue352b(metaclass=Issue352bMeta):
318    """No docstrings for the constructor here."""

No docstrings for the constructor here.

class CustomCall:
326class CustomCall(metaclass=CustomCallMeta):
327    """A class where the constructor is defined by its metaclass."""

A class where the constructor is defined by its metaclass.

CustomCall(*args, **kwargs)
322    def __call__(cls, *args, **kwargs):
323        """Custom docstring in metaclass.`__call__`"""

Custom docstring in metaclass.__call__

class Headings:
330class Headings:
331    """
332    # Heading 1
333
334    Here is some text.
335
336    ## Heading 2
337
338    Here is some text.
339
340    ### Heading 3
341
342    Here is some text.
343
344    #### Heading 4
345
346    Here is some text.
347
348    ##### Heading 5
349
350    Here is some text.
351
352    ###### Heading 6
353
354    Here is some text.
355
356    """

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.

def repr_not_syntax_highlightable(x=°<script>alert(1)</script>):
364def repr_not_syntax_highlightable(x=CustomRepr()):
365    """The default value for x fails to highlight with pygments."""

The default value for x fails to highlight with pygments.

class ClassDecorator:
368class ClassDecorator:
369    """This is a class that wraps a function. It will be documented correctly."""
370    def __init__(self, func):
371        self._func = func

This is a class that wraps a function. It will be documented correctly.

ClassDecorator(func)
370    def __init__(self, func):
371        self._func = func
another_decorated_function = <ClassDecorator object>

This is another decorated function. It will not be documented correctly.

class SubclassRef:
380class SubclassRef:
381    class SubClass:
382        pass
383
384    def __init__(self, x: "SubClass"):
385        print(x)
SubclassRef(x: SubclassRef.SubClass)
384    def __init__(self, x: "SubClass"):
385        print(x)
class SubclassRef.SubClass:
381    class SubClass:
382        pass
class ClassAsAttribute:
388class ClassAsAttribute:
389    static_attr_to_class = ClassDecorator
390    """this is a static attribute that point to a Class (not an instance)"""
391
392    static_attr_to_instance = ClassDecorator(None)
393    """this is a static attribute that point to an instance"""
static_attr_to_class = <class 'ClassDecorator'>

this is a static attribute that point to a Class (not an instance)

static_attr_to_instance = <ClassDecorator object>

this is a static attribute that point to an instance

class scheduler(sched.scheduler):
396class scheduler(sched.scheduler):
397    """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

Inherited Members
sched.scheduler
scheduler
timefunc
delayfunc
enterabs
enter
cancel
empty
run
queue
class __init__:
400class __init__:
401    """https://github.com/mitmproxy/pdoc/issues/519"""
def dynamically_modify_docstring1():
404def dynamically_modify_docstring1():
405    """this should **not** be the docstring."""
def dynamically_modify_docstring2():
408def dynamically_modify_docstring2():
409    pass
def dynamically_modify_docstring3():
421@_docstring_modifier
422def dynamically_modify_docstring3():
423    """This should **not** be the docstring."""
def dynamically_modify_docstring4():
426@_docstring_modifier
427def dynamically_modify_docstring4():
428    pass
class MyDict(builtins.dict):
431class MyDict(dict):
432    pass
Inherited Members
builtins.dict
get
setdefault
pop
popitem
keys
items
values
update
fromkeys
clear
copy
class DocstringFromNew:
435class DocstringFromNew:
436    def __new__(cls, *args, **kwargs):
437        """This is a class with a docstring inferred from `__new__`."""
DocstringFromNew(*args, **kwargs)
436    def __new__(cls, *args, **kwargs):
437        """This is a class with a docstring inferred from `__new__`."""

This is a class with a docstring inferred from __new__.