Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provides caching for the linker #498

Merged
merged 27 commits into from
Mar 6, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pydoctor/astbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ def __init__(self, value: Any, ctx: model.Documentable):
The colorized value as L{ParsedDocstring}.
"""

self._linker = epydoc2stan._EpydocLinker(ctx)
self._linker = ctx.docstringlinker
"""
Linker.
"""
Expand Down
252 changes: 234 additions & 18 deletions pydoctor/epydoc2stan.py

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions pydoctor/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from typing_extensions import Literal
from twisted.web.template import Flattenable
from pydoctor.astbuilder import ASTBuilder
from pydoctor import epydoc2stan
else:
Literal = {True: bool, False: bool}
ASTBuilder = object
Expand Down Expand Up @@ -145,6 +146,7 @@ def doctarget(self) -> 'Documentable':

def setup(self) -> None:
self.contents: Dict[str, Documentable] = {}
self._linker: Optional['epydoc2stan.DocstringLinker'] = None

def setDocstring(self, node: ast.Str) -> None:
doc = node.s
Expand Down Expand Up @@ -373,6 +375,18 @@ def report(self, descr: str, section: str = 'parsing', lineno_offset: int = 0) -
f'{self.description}:{linenumber}: {descr}',
thresh=-1)

@property
def docstringlinker(self) -> 'epydoc2stan.DocstringLinker':
"""
Returns an instance of L{epydoc2stan.DocstringLinker} suitable for resolving names
in the context of the object scope.
"""
if self._linker is not None:
return self._linker
from pydoctor.epydoc2stan import _CachedEpydocLinker
self._linker = _CachedEpydocLinker(self)
return self._linker
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best would be to avoid this workaround cyclic imports.
In order to do that, we should move all code related to the concrete docstring linkers in a new module: docstringlinker.py. I wonder if this change should happen in this PR though ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better for a separate PR, but also add all this info in a code comment :)



class CanContainImportsDocumentable(Documentable):
def setup(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions pydoctor/templatewriter/pages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def format_decorators(obj: Union[model.Function, model.Attribute]) -> Iterator["

# Colorize decorators!
doc = colorize_inline_pyval(dec)
stan = doc.to_stan(epydoc2stan._EpydocLinker(obj))
stan = doc.to_stan(obj.docstringlinker)
# Report eventual warnings. It warns when a regex failed to parse or the html2stan() function fails.
for message in doc.warnings:
obj.report(message)
Expand Down Expand Up @@ -435,7 +435,7 @@ def extras(self) -> List["Flattenable"]:

def classSignature(self) -> "Flattenable":
r: List["Flattenable"] = []
_linker = epydoc2stan._EpydocLinker(self.ob)
_linker = self.ob.docstringlinker
zipped = list(zip(self.ob.rawbases, self.ob.bases))
if zipped:
r.append('(')
Expand Down
12 changes: 11 additions & 1 deletion pydoctor/test/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""PyDoctor's test suite."""

from logging import LogRecord
from typing import Iterable, TYPE_CHECKING, Optional, Sequence
from typing import Any, Iterable, TYPE_CHECKING, Optional, Sequence, Type
import sys
import pytest
from pathlib import Path
import functools

from twisted.web.template import Tag, tags

Expand Down Expand Up @@ -94,3 +95,12 @@ def link_xref(self, target: str, label: "Flattenable", lineno: int) -> Tag:

def resolve_identifier(self, identifier: str) -> Optional[str]:
return None

def partialclass(cls: Type[Any], *args: Any, **kwds: Any) -> Type[Any]:
# mypy gets errors: - Variable "cls" is not valid as a type
# - Invalid base class "cls"
class NewCls(cls): #type: ignore
__init__ = functools.partialmethod(cls.__init__, *args, **kwds) #type: ignore
__class__ = cls
assert isinstance(NewCls, type)
return NewCls
Loading