-
Notifications
You must be signed in to change notification settings - Fork 654
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
Create guide on how to create plugins #1429
Create guide on how to create plugins #1429
Conversation
a5197a4
to
1e5e3ce
Compare
different for a :class:`~trinity.extensibility.plugin.BaseMainProcessPlugin` but fairly similar | ||
for the other types of plugins which we'll be focussing on for now. | ||
|
||
Plugins need to implement the :meth:`~trinity.extensibility.plugin.BasePlugin._start` method |
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.
@pipermerriam remember when we talked about the _start
/ start
pair where start
is calling _start
and _start
is meant to be implemented whereas start
is meant to be called because it does some work and then delegates to _start
behind the scenes. #1331 (comment)
The naming of _start
is proving to be problematic from a documentation standpoint because it is considered a private API and those are by default not being considered for the docs (rightfully so). This also means that linking to them won't work.
I wonder if we can find a generic pattern for this where we derive a name similar to the public API name but without making it private. I think this is not only good from a documentation standpoint but it also strikes me as the right thing to do. We use the same pattern in the BaseService
so it would be nice if we can find a generic naming convention. E.g.
start
-> do_start
stop
-> do_stop
...
I'm usually bad at naming but I kinda like the do
prefix. Thoughts? /cc @carver
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.
Btw, no need to review the rest of the PR. I just put it out for transparency but the whole text, structure is still very rough, incomplete and in flux.
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.
do_start
seems fine. You could also invert these and make _start
the one that is called internally and start
the one that the user implements.
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.
You could also invert these
That would work for the implementation as of today where Plugins call start
themselves but I would still consider both APIs public. It is more clear for the stop
API that is called from the PluginManager
hence it is definitely public.
But if you are ok with the do
prefix then I'll send a PR for that. Thinking about it, it was strange to have a method that is intended to be overwritten to be private anyway. That wouldn't even work in most languages (e.g. Java, C# etc)
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.
Linking #1440
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.
@cburgdorf as stated in the other PR, I'm fine with the do_
prefix on the plugin API but I'm 👎 on immediately extending it to the rest of the codebase.
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.
but I'm -1 on immediately extending it to the rest of the codebase.
@pipermerriam is this because we need to find a better prefix than do
? Because, from a language theory it strikes me as plain wrong that we have something like BaseService._run
as private and abstract at the same time. In fact, I don't know any statically typed language (which Python isn't but there more we use mypy the more we try to be haha) that would allow this.
In something like Java or C#, if you want subclasses to be able to overwrite a method, or even force them to, then that method can not be private.
And it has real consequences, it means that if we document the BaseService
like this:
.. autoclass:: p2p.service.BaseService
:members:
Then, _run
and _cleanup
, probably the most important methods of this class, those that need to be overwritten, simply fall out of the documentation because they are incorrectly seen as private. Something that would be impossible in most if not all statically typed language that have the concepts of private members and inheritance.
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.
Btw, I would be seam totally reasonable to me if in the future mypy
would raise warnings or even errors for when private members are overwritten in subclasses. On the naming part, here are two alternatives for prefixes:
protected_
(borrowed from the access modifier thatJava
,C#
andTypeScript
use for members that are accessible in subclasses but not from other classes which kinda goes nicely hand in hand with our intend)sealed_
just because it is a little shorter and seems to convey the same as the former
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 think what we're struggling with here is that a bad architectural design is triggering a negative side-effect of some weird OOP practices (this private/protected method that must be implemented by subclasses).
Two types of needs call for two types of solutions:
- Urgent feature: patch the side effect by adding
do_
(I think Christoph feels urgency on the plugin docs, so they are in this category) - Easy maintenance: attack the root architectural problem, probably with converting inheritance to compositional approach. (I think
BaseService
and other instances in the code base
are in this category)
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.
Added my answer in the PR. #1440 (comment)
1e5e3ce
to
ff52f65
Compare
These methods were named so that they appeared private by convention. This convention causes trouble in the documentation where these methods are righfully dropped. Since these methods aren't really private in reality (they need to be overwritten in subclasses), they were renamed, migrating their naming from `_*` to `do_*`.
This enables the plugin to read the status of the four formal states a plugin can be in. Previously even though the four states existed implicitly, it could only be differentiated between the STARTED/STOPPED state based on the `running` bool. This change also has the nice benefit that we can make stronger assumptions about the status inside `start()` and raise an exception if `start()` was called on a plugin that isn't in the correct status to call `start()`
6299f3a
to
b7168be
Compare
Relates to ethereum#1103
88e75f7
to
f4184a5
Compare
Merged this without review as discussed with @pipermerriam in the chat to get the draft guide up online for DEVCON IV. |
What was wrong?
For people to start contributing Trinity plugins or building their own applications with the Trinity + Plugins Model we need to do a good job of teaching them how to use the Plugin API. So we need a detailed guide for the Plugin API. Notice that this PR is a spin off from #1424 to allow #1424 to get merged sooner while I take more time for writing the guide.
How was it fixed?
This is a draft version that we may merge anyway to have something for DEVCON !V
Cute Animal Picture