-
Notifications
You must be signed in to change notification settings - Fork 49
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
Extension system #576
Extension system #576
Conversation
Get rid of attributes currAttr and newAttr and use builder.currentAttr intsead.
This means the extension system is now based on composition of several visitor intead of rely on subclassing. We cannot test the TwistedSystem anymore because it's not compatible with the new system. It should not be an issue because we now support all the Twisted customizations.
The new extension system is now 100% installed.
Codecov Report
@@ Coverage Diff @@
## master #576 +/- ##
==========================================
- Coverage 90.96% 90.92% -0.05%
==========================================
Files 42 45 +3
Lines 7383 7699 +316
Branches 1606 1668 +62
==========================================
+ Hits 6716 7000 +284
- Misses 403 435 +32
Partials 264 264
Continue to review full report at Codecov.
|
…ons package. Use pydoctor.model.System by default.
def _handleZopeInterfaceAssignment(self, node: Union[ast.Assign, ast.AnnAssign]) -> None: | ||
for target in node.targets if isinstance(node, ast.Assign) else [node.target]: | ||
dottedname = astutils.node2dottedname(target) | ||
if dottedname and len(dottedname)==1: | ||
# Here, we consider single name assignment only | ||
current = self.visitor.builder.current | ||
if isinstance(current, model.Class): | ||
self._handleZopeInterfaceAssignmentInClass( | ||
dottedname[0], node.value, node.lineno | ||
) | ||
elif isinstance(current, model.Module): | ||
self._handleZopeInterfaceAssignmentInModule( | ||
dottedname[0], node.value, node.lineno | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new code is needed because we don't subclass the ASTBuilder
class anymore, the only entry point we have now is visit_*
and depart_*
methods. So we need to re-do some semantical analysis job in order to redirect to the correct _handle*
method. But it's OK, it's always better than subclassing.
… a single object inside one extension. This also improves coverage.
Fix an issue in the visitor extension logic that would prevent to the depart() method from beeing called if an SkipNode() exception was raised inside the main visitor.
This PR is ready for a final review @adiroiban :) |
return None | ||
assert isinstance(cls, ZopeInterfaceClass) | ||
def depart_ClassDef(self, node: ast.ClassDef) -> None: | ||
cls = self.visitor.builder.current.contents.get(node.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to edit the builder to have something like this instead:
cls = self.visitor.builder.current.contents.get(node.name) | |
cls = self.visitor.builder.last |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll merge this PR as is create a follow-up PR to refactor this, it might more complicated than expected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, I am busy these days and will not have time to do a proper review for this one.
I think that we can merge.
if there are any issues, we can fix them later.
overall this looks a big step in the right direction.
Many thanks!
…re. The older visitor relied on generic_visit() to be recursive. Where the provided generic_visit() is not recursive anymore, and moreover not called automatically when visiting unknow nodes! So what I'm saying here is that since #576 have been merged, we're not visiting the statements inside the 'orelse' field of Try and If nodes, same goes for 'finalbody' and 'handlers'. This commit fixes that issue. The rationale is now the following: All statements in the 'orelse' block of IF nodes and statements in the except handlers of TRY nodes that would override a name already defined in the main 'body' (or TRY 'orelse' or 'finalbody') are ignored. Meaning that in the context of the code below, 'ssl' would resolve to 'twisted.internet.ssl': try: from twisted.internet import ssl as _ssl except ImportError: ssl = None else: ssl = _ssl
Provide a better extension system for pydoctor.
This new extension system breaks some compatibility with the old way of customizing pydoctor with option
--system-class
because we don't need to subclass the ASTBuilder to include custom AST visitor code. This is why the Twisted build is crashing with this new version. If everything works correctly, the Twisted customizations can be completely removed except the part that adds a link to the latest version of the document we're viewing if it's not the latest version.The extension system currently support 3 types of customizations:
Documentable
subclassesIt does not support support customizing renderers, so the code in
ZopeInterfaceClassPage
is not part of the extension system, but still built in with pydoctor. This point can probably be taken care of in a later PR.The extension system rely on composition of multiple visitors into one.
We do not not need to subclass the
System
class to define an extension, we just need to add a new module underpydoctor.extensions
(to be packaged to pydoctor). Though, we currently need to define a system class if we want to add a custom extension.It now much easier to add more extensions and properly isolate each feature in a different module.
Add a new CLI argument:Since it's still possible to add extensions with a custom system like the following:--extension
to load a custom extension.It think I wont add this new argument right now. Also because this change does not mean pydoctor have now a stable API, more changes will come down the road, so I'de suggest we keep the customization system rather "private".