mkdocstrings / pytkdocs Goto Github PK
View Code? Open in Web Editor NEWLoad Python objects documentation.
Home Page: https://mkdocstrings.github.io/pytkdocs
License: ISC License
Load Python objects documentation.
Home Page: https://mkdocstrings.github.io/pytkdocs
License: ISC License
Currently the docstrings for inherited classmethods are completely ignored, this forces the user make trivial reimplementation of methods such as __init__
just to show proper documentation.
Original disscutions: mkdocstrings/mkdocstrings#78 (comment)
Describe the bug
Native namespace packages (without __init__.py
modules) trigger the following kind of error when attempting to retrieve the top package's path:
ERROR - mkdocstrings.handlers.python: Collection failed: <module 'bot' (namespace)> is a built-in module
Traceback (most recent call last):
File "/home/dadyarri/projects/bjorn/venv_bjorn/lib/python3.8/site-packages/pytkdocs/cli.py", line 179, in main
print(json.dumps(process_json(line)))
File "/home/dadyarri/projects/bjorn/venv_bjorn/lib/python3.8/site-packages/pytkdocs/cli.py", line 116, in process_json
return process_config(json.loads(json_input))
File "/home/dadyarri/projects/bjorn/venv_bjorn/lib/python3.8/site-packages/pytkdocs/cli.py", line 98, in process_config
serialized_obj = serialize_object(obj)
File "/home/dadyarri/projects/bjorn/venv_bjorn/lib/python3.8/site-packages/pytkdocs/serializer.py", line 143, in serialize_object
relative_file_path=obj.relative_file_path,
File "/home/dadyarri/projects/bjorn/venv_bjorn/lib/python3.8/site-packages/pytkdocs/objects.py", line 185, in relative_file_path
top_package_path = Path(inspect.getabsfile(top_package)).parent
File "/usr/lib/python3.8/inspect.py", line 720, in getabsfile
_filename = getsourcefile(object) or getfile(object)
File "/usr/lib/python3.8/inspect.py", line 696, in getsourcefile
filename = getfile(object)
File "/usr/lib/python3.8/inspect.py", line 659, in getfile
raise TypeError('{!r} is a built-in module'.format(object))
TypeError: <module 'bot' (namespace)> is a built-in module
To Reproduce
Simply try to collect documentation for a native namespace package.
Expected behavior
No exception. We should find another way to determine the top package's path in that case.
Reference: mkdocstrings/mkdocstrings#79 (comment)
Hi! I would like to start by saying this project has made mkdocs
usable for our team and we are SO excited about finally ditching RST! I cannot emphasize this enough: Thank. You.
The only thing we are missing is that, currently, mkdocstrings
doesn't support an Examples
section, which normally include doctest
formatted blocks. For example:
def example_function(arg1, kwarg=None) -> object:
"""
Example function to demonstrate how APIs are rendered
Parameters:
arg1 (dict): Some description for this argument.
This type (in parenthesis) is ignored.
kwarg: Some more descriptions
Returns:
A description for the returned value
Examples:
>>> 2 + 2 == 4
False
"""
pass
gets rendered as:
The style is not bad, but it could be even better! Notice how pytest
is able to parse the block just fine.
I can get what I want by using this other docstring:
def example_function(arg1, kwarg=None) -> object:
"""
Example function to demonstrate how APIs are rendered
Parameters:
arg1 (dict): Some description for this argument.
This type (in parenthesis) is ignored.
kwarg: Some more descriptions
Returns:
A description for the returned value
__Examples__
```python
>>> 2 + 2 == 4
False
```
"""
pass
, but I find it a bit annoying (in order of importance):
Examples
heading stylepytest
can get the doctests correctly.Maybe a good compromise would be to just add Examples
to the recognized headers? That way I could write:
def example_function(arg1, kwarg=None) -> object:
"""
Example function to demonstrate how APIs are rendered
Parameters:
arg1 (dict): Some description for this argument.
This type (in parenthesis) is ignored.
kwarg: Some more descriptions
Returns:
A description for the returned value
Examples:
```python
>>> 2 + 2 == 4
False
```
"""
pass
, which currently does not work as intended:
I'd be happy to help and contribute a PR if needed, but if I understood correctly, you are currently refactoring the backend and I don't know if this is the best moment to add a feature.
Thanks a lot!
Hi @StephenBrown2, @cs01,
I'm creating this repo to move the code of mkdocstrings
responsible for loading the documentation.
Since you were contributors, I want to add you as co-authors on the first commit, following this method: https://stackoverflow.com/questions/7442112/how-to-attribute-a-single-commit-to-multiple-developers
I want to make sure you agree to it ๐
You can react with a thumbs up if you do!
For the "why" I'm moving this part of the code, I'll explain it in the Architecture issue ๐
Describe the bug
If an exception is raised in line-by-line mode, the standard output descriptor is not restored, so the JSON error is not printed, and it makes mkdocstrings hang since there's no output to read.
Expected behavior
stdout should be properly restored when an exception is caught in line-by-line mode.
Additional context
We should move the code responsible for discarding/restoring stdout into the main function of the cli module, so we can restore it in the except handler, and in the finally clause.
Is your feature request related to a problem? Please describe.
Currently descriptions of dataclasses fields will not be picked up.
Describe the solution you'd like
Pick up dataclasses fields descriptions. This will require to parse the code to find either comments or docstrings following the field.
Could be done alongside #30.
Describe the bug
If a pydantic field doesn't have a docstring, the docstring is not set to ""
, making the parser fail.
To Reproduce
Try to build the documentation of pytkdocs. It will hang because of a combination of this issue and #36
Expected behavior
Docstring should always be a string.
Additional context
Maybe we could simply accept None in the parsers and return immediately if it's None, rather than making sure the docstring is always set to "" as default.
I want to try and clarify what is possible, what we want to support for documentation of attributes, and how to implement it. This is mostly me writing my thoughts to try and structure them. I'll update this post gradually.
Attributes can be described
Attributes
section of a module docstring, a class docstring, or an __init__
method doctring (google-style)#:
above the declaration#:
Attributes can be annotated
NAME: TYPE [= VALUE]
# type: TYPE
TYPE: DESCRIPTION
.I'm not sure if a type and a description can be combined in a single comment: #: TYPE: DESCRIPTION
or #: DESCRIPTION # type: TYPE
.
Descriptions and annotations in comment are appealing, but I think comments have zero chance of being accessible via introspection, even in the far future of Python. If we were to only and entirely parse the source code to generate our data, then why not. But it's not the case, so I don't think supporting comments is worth the effort. Annotations will be retrieve from type annotations and docstrings, and descriptions will be retrieved from docstrings sections (like google-style's Attributes
) or individual docstrings below declarations.
typing.get_type_hints(module_or_class)
(it's using module_or_class.__annotations__
internally IIUC). No parsing of the code required ๐__init__
method doesn't store any __annotations__
, and get_type_hints
on a method/function returns type annotations of its signature, not its body.__init__
method docstring, or in individual docstrings.__init__
methods to find documented instance attributes and their annotations__init__
signature while parsing class docstrings__init__
signature while parsing __init__
methods docstrings.get_type_hints(module)
as context)__init__
method code, to find individual docstrings and annotations of instance-attributes (in __init__
)get_type_hints(class)
as context)__init__
methods
As we can see, we will read the same source code several times. This will be done through inspect.getsource
. The source is already read to populate the source
value of objects. Maybe it's possible to do some caching here.
The __init__
methods code will also be parsed more than once. We could cache the found descriptions and annotations.
To find attribute docstrings: search for pairs of ast.Assign
/ ast.AnnAssign
and ast.Expr
, where the value of the expression is ast.Str
, ast.Constant
, then recurse on nodes like ast.If
, ast.IfExp
, ast.Try
, ast.With
or ast.ExceptHandler
, and again on their node.handlers
, node.orelse
and node.finalbody
.
When parsing a docstring, a parser should also be able to accept data like the following:
{
# both description and real-type annotation
"attribute1": {"description": "Some description", "annotation": int},
# or only description
"attribute2": {"description": "Some description"},
# or only parsed-type annotation
"attribute3": {"annotation": "int"},
# additionally, for classes, we would have a level key
# to distinguish class-attributes from instance-attributes
"attribute4": {"annotation": str, "level": "class"},
"attribute4": {"annotation": "str", "level": "instance"},
"attribute4": {
"class": {"annotation": str},
"instance": {"annotation": "str"}
}
}
I wonder if it's really necessary to pass descriptions since a docstring is written to add descriptions. They could be used to record a warning/error though, or the parser configured to use one or the other in priority.
Sometimes, I want to document an entire tree, but not specific modules. It would be nice if you could put something like @pytkdocs-ignore
in the docstring and have pytkdocs, well, ignore it! This would be nice and helpful in situations where I don't want documentation to appear for a specific class at all.
Describe the bug
When collecting type-alias attributes, pytkdocs in some cases incorrectly collects a path under the typing
module. This seems to happen when the type alias is an alias to a type in the typing module, and not for example an alias for a user defined type.
To Reproduce
When defining a type alias in my_module.py
from typing import Union
IntOrStr = Union[str, int]
"""
A type alias that I wish to document with mkdocstrings.
"""
running the following:
$ echo '{"objects": [{"path": "my_module.IntOrStr"}]}' | pytkdocs
Produces
{"loading_errors": [], "parsing_errors": {}, "objects": [{"name": "IntOrStr", "path": "typing.IntOrStr", "category": "attribute", "file_path": "/Users/sune/.pyenv/versions/3.7.5/lib/python3.7/typing.py", "relative_file_path": "python3.7/typing.py", "properties": [], "parent_path": "typing", "has_contents": true, "docstring": "", "docstring_sections": [], "source": {}, "children": {}, "attributes": [], "methods": [], "functions": [], "modules": [], "classes": [], "type": "None"}]}
Expected behavior
Since the type-alias is just a module level attribute, I expect pytkdocs to collect the path as my_module.IntOrStr
, and to collect the appropriate docstring as well in order that I can document it with mkdocstrings
Screenshots
An example from a project using mkdocstrings to document a type alias of Union[...]
System (please complete the following information):
pytkdocs
0.6.0Is your feature request related to a problem? Please describe.
It would be nice to be able to document Django models without adding docstrings, just like pydantic models.
Describe the solution you'd like
Add similar support for Django models
Describe alternatives you've considered
Adding docstrings to every model field, I don't really like it because usually it means duplicating verbose_name value.
Describe the bug
I just thought about the case where the user could have added print
statements that are executed at import time. In that case pytkdocs
JSON output would be broken/corrupted.
To Reproduce
$ echo -e '"""Module docstring."""\n\nprint("finished loading")\n' > corrupt.py
$ echo '{"objects": [{"path": "corrupt"}]}' | poetry run pytkdocs | jq
parse error: Invalid literal at line 1, column 9
Expected behavior
The output of the imported code should be discarded.
System (please complete the following information):
pytkdocs
version 0.3.0Additional context
Possibly related to rdilweb/docs@cc20660 and mkdocstrings/mkdocstrings#91
Depending on the editor used, trailing spaces will be removed upon saving. When they are not removed, and a line at the end of a Parameters section contains 8 spaces, mkdocstrings
will try to split it on :
to get the param name and description, which will throw an exception.
So, lines composed only of spaces in docstrings should be considered empty lines.
For example, if my function declares a return type of MyClass
, then we should detect that it's referencing the class mypackage.mymodule.MyClass
and store that information somewhere. It could allow us to write links to objects instead of just strings!
Describe the bug
Traceback (most recent call last):
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/cli.py", line 193, in main
output = json.dumps(process_json(line))
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/cli.py", line 114, in process_json
return process_config(json.loads(json_input))
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/cli.py", line 91, in process_config
obj = loader.get_object_documentation(path, members)
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/loader.py", line 232, in get_object_documentation
root_object = self.get_class_documentation(leaf, members)
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/loader.py", line 333, in get_class_documentation
merge(attributes_data, get_class_attributes(cls))
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/parsers/attributes.py", line 127, in get_class_attributes
return combine(get_module_or_class_attributes(nodes[0].body), type_hints)
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/parsers/attributes.py", line 85, in get_module_or_class_attributes
names = [target.id for target in assignment.targets]
File "/home/runner/work/integrations-core/integrations-core/.tox/docs/lib/python3.8/site-packages/pytkdocs/parsers/attributes.py", line 85, in <listcomp>
names = [target.id for target in assignment.targets]
AttributeError: 'Tuple' object has no attribute 'id'
Screenshots
https://github.com/DataDog/integrations-core/runs/751798110?check_suite_focus=true
Leading whitespace on class comments is not stripped correctly when the first line of text is on the same line as the triple-quotes.
A class like the following:
class A:
"""This is a class.
More words here.
"""
pass
ends up having whitespace stripped to look like this:
This is a class.
More words here.
whereas this is expected:
This is a class.
More words here.
The intended behaviour is specified in PEP-257: Docstring Conventions > Handling Docstring Indentation and implemented in inspect.cleandoc
(which is called by inspect.getdoc
)
This is only a problem for classes, since elsewhere pytkdocs does use inspect.getdoc
Hi,
I am unable to build docs for one file.
If I understand those errors correct than they might be caused by the following class definition:
class GSS(NamedTuple):
"""
Helper Class to specify the return type of gss
"""
gss: float
nA: float
nB: float
nAB: float
Is there any way to solve this?
poetry run mkdocs build
INFO - Cleaning site directory
INFO - Building documentation to directory: /mnt/c/Users/demo/Documents/repos/myownpackage/site
Traceback (most recent call last):
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/bin/mkdocs", line 8, in <module>
sys.exit(cli())
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/click/core.py", line 764, in __call__
return self.main(*args, **kwargs)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/click/core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/mkdocs/__main__.py", line 163, in build_command
), dirty=not clean)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/mkdocs/commands/build.py", line 270, in build
nav = config['plugins'].run_event('nav', nav, config=config, files=files)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/mkdocs/plugins.py", line 94, in run_event
result = method(item, **kwargs)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/mkdocstrings/plugin.py", line 110, in on_nav
root_object = self.documenter.get_object_documentation(import_string)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/mkdocstrings/documenter.py", line 305, in get_object_documentation
root_object = self.get_module_documentation(obj)
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/mkdocstrings/documenter.py", line 323, in get_module_documentation
root_object.add_child(self.get_class_documentation(member, module))
File "/mnt/c/Users/demo/Documents/repos/myownpackage/.venv/lib/python3.6/site-packages/mkdocstrings/documenter.py", line 362, in get_class_documentation
source = inspect.getsourcelines(actual_member)
File "/usr/lib/python3.6/inspect.py", line 955, in getsourcelines
lines, lnum = findsource(object)
File "/usr/lib/python3.6/inspect.py", line 786, in findsource
raise OSError('could not get source code')
OSError: could not get source code
Makefile:64: recipe for target 'docs' failed
make: *** [docs] Error 1
Describe the bug
When a decorator is used before a function, the function does NOT appear in the documentation:
To reproduce, try placing this as a decorator before any function:
import functools
@functools.lru_cache(maxsize=1024)
def my_function(some_arg):
print()
Screenshots
When this decorator is used, the function does NOT appear in the documentation:
When the decorator is not used, the function DOES appear in the documentation:
System (please complete the following information):
pytkdocs
version: latestI'm using google docstrings format for my docstrings and I'm often getting:
annotation, description = exception_line.split(": ")
ValueError: not enough values to unpack (expected 2, got 1)
It's really difficult to debug when the traceback only says which file is causing the error. Would be nice to include at least an aproximate where the fault actually is.
Could be nice to be able to have this code (note the f-string for the log
object):
import logging
DEFAULT_LOG_LEVEL = "debug"
def get_logger(level: str) -> logging.Logger:
logger = logging.getLogger("my_package")
logger.setLevel(logging.getLevelName(level.upper()))
return logger
log: logging.Logger = get_logger(os.environ.get("MY_PACKAGE_LOG_LEVEL", DEFAULT_LOG_LEVEL))
f"""
The logger used throughout this package.
Initialized with a default level of {DEFAULT_LOG_LEVEL},
or using the environment variable `MY_PACKAGE_LOG_LEVEL`.
"""
We would need to match the f-string nodes as well when parsing attributes and their docstrings.
Is your feature request related to a problem? Please describe.
When documenting Enums, I will usually want to show the value of the enum, rather than just it's reference, to show the valid options.
Describe the solution you'd like
Rather than duplicating the enum in the docstring, I would prefer if a subclass of enum.Enum
is encountered, the value of each attribute is shown next to it. Bonus: the value is color-highlighted with python syntax.
Describe alternatives you've considered
ServiceCancelReasons
An Enum defining the valid Cancellation reasons for a Service
CUSTOMER_REQUEST = "Customer Request" INCORRECT_DATE_OR_TIME = "Incorrect Date Or Time" OTHER = "Other"
class MaintenanceStateIds(IntEnum): """Valid IDs for Maintenance states.""" TEMPORARY = 1 """Temporary: 1""" TENTATIVE = 2 """Tentative: 2""" SCHEDULED = 3 """Scheduled: 3""" CANCELLED = 4 """Canceled: 4""" COMPLETED = 5 """Completed: 5"""
class ServiceCancelReasons(str, Enum): """Valid reasons to cancel a service. ```python CUSTOMER_REQUEST = "Customer Request" INCORRECT_DATE_OR_TIME = "Incorrect Date Or Time" OTHER = "Other" ``` """ CUSTOMER_REQUEST = "Customer Request" INCORRECT_DATE_OR_TIME = "Incorrect Date Or Time" OTHER = "Other"
Additional context
Ideally, I could do something like the following:
class MaintenanceStateIds(IntEnum):
"""Valid IDs for Maintenance states."""
TEMPORARY = 1
"""Maintenance is in a temporary state, before scheduling or confirming any time slots"""
TENTATIVE = 2
"""Maintenance slot is being tentatively held on the calendar"""
SCHEDULED = 3
"""Maintenance has been confirmed for a particular time slot on the calendar to be executed"""
CANCELLED = 4
"""Maintenance was cancelled before execution"""
COMPLETED = 5
"""Maintenance was completed, status is dependent on states of services"""
class MaintenanceStateNames(str, Enum):
"""Valid names for Maintenance states."""
TEMPORARY = "Temporary"
"""Maintenance is in a temporary state, before scheduling or confirming any time slots"""
TENTATIVE = "Tentative"
"""Maintenance slot is being tentatively held on the calendar"""
SCHEDULED = "Scheduled"
"""Maintenance has been confirmed for a particular time slot on the calendar to be executed"""
CANCELLED = "Canceled"
"""Maintenance was cancelled before execution"""
COMPLETED = "Completed"
"""Maintenance was completed, status is dependent on states of services"""
and end up with the results (achieved through some quick HTML hacking):
Describe the bug
It seems pytkdocs
has trouble detecting a class attribute's type when the class is decorated.
To Reproduce
See an example here: copier-org/copier#203 (comment). The description is correctly parsed from the docstring, but the type is not used.
Expected behavior
The type (cli.Flag
in the example) should appear in the Attributes table.
Screenshots
If you are using pytkdocs
through mkdocstrings
and if relevant, please attach a screenshot.
System (please complete the following information):
pytkdocs
version 0.6.0mkdocstrings
version: [0.10.3]Hi ,
I would like do to document a project that makes heavy use of external libraries where I don't have access to the sources. Does mkdocstrings offer something similar to mocks in sphinxs/autodoc
autodoc_mock_imports = ["django","td"]
Thanks in advance
Not everybody uses (or wants to use) type hints in their code. Not supporting setting types in the docstrings limits the user base of mkdocstrings to those that do.
Would you be amenable to adding support for setting the types in the docstring? It would probably make most sense to follow the Google style as done with sections.
Thanks for the consideration and the promising package.
Is your feature request related to a problem? Please describe.
Sometimes it's a bit redundant to add a type annotation. See for example copier-org/copier#203 (comment)
Describe the solution you'd like
Instead of using None
or _empty
, we could make sure to always fallback to the attribute's type with type(attr)
.
Typically done here: https://github.com/pawamoy/pytkdocs/blob/master/src/pytkdocs/loader.py#L699
Usually, editors will not help writing the parameters documentation into the class' docstrings but rather in the __init__
method. But everybody knows that __init__
is used when instantiating an object. We rarely call it directly. So maybe it would make more sense to move the parameters documented in the __init__
docstring into the class' docstring.
Example:
"""
Args:
obj: instance of [HelloWorld][1].
Some text.
[1]: https://url.to.helloworld/documentation
"""
This will not work because obj
's description is isolated from the rest in the structured data, so the [1]
is not available when mkdocstrings renders it, meaning the link will not be rendered.
Maybe we could parse such refs ([1]
, [link id]
, etc.) so mkdocstrings could append them to every Markdown piece it renders.
See mkdocstrings/mkdocstrings#78.
We should change
for member_name, member in class_.__dict__.items():
...to
for member_name, member in inspect.getmembers(class_):
...based on configuration options.
We must also distinguish inherited members from regular ones, to be able to apply different filters.
We'll try to list here to selection option that would be useful.
Is your feature request related to a problem? Please describe.
Pydantic models can be documented via the new Attributes category. However, the default values are missing from the table.
Describe the solution you'd like
For this example,
from pydantic import BaseModel
class M(BaseModel):
number: int = 2
pytkdocs should add 2
as the default for the field number
.
I think it would be quite easy to get an object's annotation with annotation = type(obj)
when it is not annotated.
Describe the bug
Individual attribute docstrings are re-applied to inherited class attributes even when not selecting inherited members. It doesn't feel right when autodocumenting a class and its subclasses in the same module, because then the attribute is documented in each one of them with the same docstring.
To Reproduce
class Base:
VAR = 0
"""My variable."""
class Child(Base):
VAR = 1
Expected behavior
When not selecting inherited members, I'd like the overwritten members to stay docstring-less, so they can be skipped with show_no_doc: false
.
System (please complete the following information):
pytkdocs
0.5.xDescribe the bug
I upgraded to pytkdocs 0.5.1 and got this error:
ERROR - mkdocstrings.handlers.python: Collection failed: ('No route with that name.', '__wrapped__')
Traceback (most recent call last):
File "/venv/lib/python3.8/site-packages/pytkdocs/cli.py", line 193, in main
output = json.dumps(process_json(line))
File "/venv/lib/python3.8/site-packages/pytkdocs/cli.py", line 114, in process_json
return process_config(json.loads(json_input))
File "/venv/lib/python3.8/site-packages/pytkdocs/cli.py", line 91, in process_config
obj = loader.get_object_documentation(path, members)
File "/venv/lib/python3.8/site-packages/pytkdocs/loader.py", line 230, in get_object_documentation
root_object = self.get_module_documentation(leaf, members)
File "/venv/lib/python3.8/site-packages/pytkdocs/loader.py", line 311, in get_module_documentation
root_object.add_child(self.get_module_documentation(leaf))
File "/venv/lib/python3.8/site-packages/pytkdocs/loader.py", line 295, in get_module_documentation
child_node = ObjectNode(member, member_name, parent=node)
File "/venv/lib/python3.8/site-packages/pytkdocs/loader.py", line 43, in __init__
self.obj: Any = inspect.unwrap(obj)
File "/usr/lib/python3.8/inspect.py", line 520, in unwrap
while _is_wrapper(func):
File "/usr/lib/python3.8/inspect.py", line 511, in _is_wrapper
return hasattr(f, '__wrapped__')
File "/venv/lib/python3.8/site-packages/beancount/web/bottle_utils.py", line 25, in __getattr__
return self.mapper_function(name)
File "/venv/bin/bottle.py", line 409, in build
if not builder: raise RouteBuildError("No route with that name.", _name)
bottle.RouteBuildError: ('No route with that name.', '__wrapped__')
ERROR - mkdocstrings.extension: Could not collect 'beancount.web'
ERROR - Error reading page 'api_reference/beancount.web.md': ('No route with that name.', '__wrapped__')
Traceback (most recent call last):
File "build.py", line 52, in <module>
sys.exit(cli())
File "/venv/lib/python3.8/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/venv/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/venv/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/venv/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/venv/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/venv/lib/python3.8/site-packages/mkdocs/__main__.py", line 140, in serve_command
serve.serve(
File "/venv/lib/python3.8/site-packages/mkdocs/commands/serve.py", line 141, in serve
config = builder()
File "/venv/lib/python3.8/site-packages/mkdocs/commands/serve.py", line 136, in builder
build(config, live_server=live_server, dirty=dirty)
File "/venv/lib/python3.8/site-packages/mkdocs/commands/build.py", line 274, in build
_populate_page(file.page, config, files, dirty)
File "/venv/lib/python3.8/site-packages/mkdocs/commands/build.py", line 174, in _populate_page
page.render(config, files)
File "/venv/lib/python3.8/site-packages/mkdocs/structure/pages.py", line 183, in render
self.content = md.convert(self.markdown)
File "/venv/lib/python3.8/site-packages/markdown/core.py", line 263, in convert
root = self.parser.parseDocument(self.lines).getroot()
File "/venv/lib/python3.8/site-packages/markdown/blockparser.py", line 90, in parseDocument
self.parseChunk(self.root, '\n'.join(lines))
File "/venv/lib/python3.8/site-packages/markdown/blockparser.py", line 105, in parseChunk
self.parseBlocks(parent, text.split('\n\n'))
File "/venv/lib/python3.8/site-packages/markdown/blockparser.py", line 123, in parseBlocks
if processor.run(parent, blocks) is not False:
File "/venv/lib/python3.8/site-packages/mkdocstrings/extension.py", line 147, in run
data: Any = handler.collector.collect(identifier, selection)
File "/venv/lib/python3.8/site-packages/mkdocstrings/handlers/python.py", line 204, in collect
raise CollectionError(result["error"])
mkdocstrings.handlers.CollectionError: ('No route with that name.', '__wrapped__')
Here's the relevant source code:
https://github.com/beancount/beancount/blob/2.3.0/beancount/web/bottle_utils.py#L24-L25
System (please complete the following information):
pytkdocs
version: 0.5.1Is your feature request related to a problem? Please describe.
I've noticed when collecting, pytkdocs swallows errors from the module in question. For example if there is an issue importing a module, It returns that:
AttributeError: module 'module.x.y' has no attribute 'z'
However this usually points to something amiss in the module (unmet dependency). If i open up a cli and try to import the module by hand i can see whats going on.
Describe the solution you'd like
It would be nice if pytkdocs could bubble the underlying exception through to CollectionError for easier diagnosis.
Describe the bug
I get the following error when I document **kwargs
parameter in my docstring with the two **
.
line 216, in read_parameters_section
signature_param = self.signature.parameters[name]
KeyError: '**kwargs'
To Reproduce
def function(a, **kwargs):
"""
Args:
a: a parameter.
**kwargs: kwarg parameters
"""
return None
Information (please complete the following information):
mkdocstrings
version: [0.7.0]Additional context
This seems to come from the inspect module as inspect.signature(function).parameters
would return:
mappingproxy({'a': <Parameter "a">, 'kwargs': <Parameter "**kwargs">})
and the **kwargs
key is not present but kwargs
is.
Describe the bug
Dataclasses attributes are picked up twice, because they appear in the direct members, and then we iterate on __dataclass_fields__
again.
To Reproduce
@dataclass
class FrozenPerson:
"""I'm a frozen person."""
say: str = "Oh no"
"""Say attr."""
Expected behavior
Attributes are picked up only once.
System (please complete the following information):
pytkdocs
0.6.0โฌ๏ธ
inspect.is...
Is your feature request related to a problem? Please describe.
Feature asked in mkdocstrings: mkdocstrings/mkdocstrings#102 (comment)
Describe the solution you'd like
Describe alternatives you've considered
It's easier to do it in pytkdocs than re-sorting in mkdocstrings: the renderer and collector options are separated, it would be messy to use the collector options in the renderer, and I don't want to duplicate the members
option in the renderer (nor users want to copy/paste it).
I'm using Pydantic for several models in my code, and I would like mkdocstrings to handle them. The issue is, class attributes get sucked up into a __fields__
attribute with separate __annotations__
, and so they get filtered out by filter_name_out
due to the global_filters
.
Example __dict__.items()
on a Pydantic class with two fields (debugged from just before https://github.com/pawamoy/mkdocstrings/blob/ca82f6964e223b7d8b0a3d0e0fe4d9ea8f4296ce/src/mkdocstrings/documenter.py#L340):
class_.__dict__.items(): (
dict_items(
[
('__config__', <class 'pydantic.main.Config'>),
('__fields__', {
'start': ModelField(name='start', type=DateTime, required=True),
'end': ModelField(name='end', type=DateTime, required=True)
}),
('__field_defaults__', {}),
('__validators__', {
'start': [<pydantic.class_validators.Validator object at 0x10257df10>],
'end': [<pydantic.class_validators.Validator object at 0x10257df10>]
}),
('__pre_root_validators__', []),
('__post_root_validators__', []),
('__schema_cache__', {}),
('__json_encoder__', <staticmethod object at 0x10260e978>),
('__custom_root_type__', False),
('__module__', 'mypackage.models.available_times'),
('__annotations__', {
'start': <class 'pendulum.datetime.DateTime'>,
'end': <class 'pendulum.datetime.DateTime'>
}),
('__doc__', '### TimeSlot\n\n A slot of time in which a maintenance may be scheduled.\n '),
('__lt__', <function TimeSlot.__lt__ at 0x1026152f0>),
('parse_times', <classmethod object at 0x10260e828>),
('__weakref__', <attribute '__weakref__' of 'TimeSlot' objects>),
('__abstractmethods__', frozenset()),
('_abc_registry', <_weakrefset.WeakSet object at 0x10260e908>),
('_abc_cache', <_weakrefset.WeakSet object at 0x10260ea58>),
('_abc_negative_cache', <_weakrefset.WeakSet object at 0x10260eac8>),
('_abc_negative_cache_version', 42)
]
)
)
A crude implementation for an older version of pydantic was put forward here: pydantic/pydantic#638 but not accepted into Pydantic proper. Perhaps mkdocstrings could take some of the logic and parse through the field attributes?
Update: I should probably also note that I started down this path by attempting to add some docstrings to the attributes as suggested by mkdocstrings docs, but then got this error:
File "/Users/step7212/git/rack/emcee/.nox/docs-3-6/lib/python3.6/site-packages/mkdocstrings/documenter.py", line 437, in node_to_annotated_names
name = node.target.attr
AttributeError: 'Name' object has no attribute 'attr'
Changing node.target.attr
to node.target.id
fixed that for me avoided the error, but I'm not sure how relevant it is, just means I can't docstring my pydantic models (yet) since it's filtering the dunder-attrs.
I think it would be quite useful to add an Example/Examples section as we have here.
EDIT: we're not planning on outsourcing anymore.
Candidates/inspiration:
Just like we still select objects with no docstrings, we could also pick attributes without docstrings.
The user can then configure the plugin to render them or not.
...instead of this ugly serializer
module.
Describe the bug
The parser is not picking up methods of enums, only their attributes when told to parse a enum subclass, e.g. Direction
.
However, if instructed to parse a method of that enum directly (e.g. Direction.to_vector
) it will get picked up correctly.
To Reproduce
class Direction(IntEnum):
"""This enum represents a direction in the 2d plane."""
X = 0
"""X direction"""
Y = 1
"""Y direction"""
def to_vector(self) -> np.ndarray:
"""Turns a direction into its corresponding vector.
Returns:
the vector representation
"""
if self == Direction.X:
return np.array([1, 0])
if self == Direction.Y:
return np.array([0, 1])
Expected behavior
I expected to get the attributes as well as the methods.
System (please complete the following information):
pytkdocs
version 0.7Is your feature request related to a problem? Please describe.
The attributes parser code is messy, and not tested. We're currently parsing attributes and their docstrings separately from the rest of the loading, and I think this could be improved to be more integrated in the loading flow, but also more decoupled from it.
Describe the solution you'd like
Several things can be improved:
Attribute
instances to decouple the parser from the objects/loader.inspect
's getsource
methods to parse only attributes for a given object. This could decrease performance though, as inspect
might not cache the contents of a file. Maybe its methods are efficient though.ast
module to parse the code. With this we could maybe even bring support for comments, but I'm still not sure I want to have it.We could have a function that accepts a module or class, and return all its attributes, in the form of a list of dicts.
def get_logger(level: str) -> logging.Logger:
logger = logging.getLogger("my_package")
logger.setLevel(logging.getLevelName(level.upper()))
return logger
log: logging.Logger = get_logger("debug")
"""The logger used throughout this package."""
...though the return type of get_logger
is correctly displayed as Logger
.
Example:
builtin_urls = {
"int": "https://docs.python.org/3/library/functions.html#int",
"str": "https://docs.python.org/3/library/functions.html#func-str",
..., # other builtin types
"OverflowError": "https://docs.python.org/3/library/exceptions.html#OverflowError",
"ImportError": "https://docs.python.org/3/library/exceptions.html#ImportError",
... # other exceptions
}
This data would allow us to use links in the Type
column of parameters, return value and exceptions.
This could also be extended to support:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.