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
[PROPOSAL] Python Plugin System #891
Comments
I agree.
+1 to all of these.
+1. I guess that for now we will allow only "single file" pure-python plugins, so that the config would look like this: <py-config>
plugins = ["http://example.com/mygui.py"]
</py-config> and the semantics is that during the startup we will download the file, put it into a directory which is inside
but that's orthogonal. Once we have a solid way to execute plugins, we can think of ways to discover/install them.
+1
+1
I'm confused about the terminology here. Assuming that the file above is called
+1 for having simple functions which just returns HTML and/or an
I'm not particularly attached to this approach, but just to understand better: what is it that you don't like? The
+1
-0.5. It might work for simple stuff, but it quickly breaks as soon as you have multiple sub-nodes in your widget. Which of them respond to the
yes, happy to leave naming discussions for another time, apart the plugin/component distinction.
no: I can imagine having plugins which want to do both (e.g. a "terminal" plugin which intercepts stdin/stdout and also creates a
I think we are not too far from converging, but there is another open question we should talk about. In your first two examples, the component-registration logic happen at import time. I think I have a solution which might represent the best of both worlds: # mygui.py
from pyscript import Plugin
plugin = Plugin('mygui', priority=1) # priority is optional, of course
@plugin.init
def init():
print('this is executed as soon as the runtime is ready')
@plugin.register_component('my-button')
class MyButton:
...
@plugin.register_component('my-inputbox')
class MyInputBox:
...
# hypotetical hook
@plugin.afterExecution
def afterExecution():
print('this is called e.g. after the execution of <py-script> blocks')
@plugin.another_hook
def another_hook():
... Note the subtle but important difference: all the registration logic is done with the This is basically the same pattern which is used by Flask blueprints: the blueprint decorators are very similar to the |
Yeah, I can see the source of confusion here, and do think we have to agree on terminology. I've been using I'm not too attached to terminology here but do think that
That's fair and I'm +1, if we can define "complex behavior"
Great question. I think it's a combination of factors. Yeah, the above contributes to it and makes it have a more verbose/less clean approach to it but, the fact that users have to know that they need to define attributes like
Could you help me understand, with an example?
That's most true as it is... but nothing prevent us to have the decorator itself to stage all plugins that need registration and for us to make it happen whenever it's more convenient. Not saying it's great or best option but that it's a possibility. (Overall, I'd like to keep it simple whenever possible tbh)
(not focusing on the decorator names) I like the approach 👍 |
Let me answer this first:
I'm using "component" because of web components: in the example above, I was curious to understand the difference between "Web Component" and "Custom Element": according to this answer:
So, we should just call them custom elements, and use decorators such as Maybe @tedpatrick has opinions here.
I think that we are basically aligned here and it's just a matter of terminology. That said, it's better to settle at least the basic terminology to avoid further confusion. In pluggy, a "plugin" is a namespace which contains various functions will well-known names. The first pluggy examples shows that this namespace can also be the one of a class, but in the vast majority of real-world cases, the namespace is the one of the module and the That said, a single plugin/module can register many "things" of course, where each "thing" can be a hook, a custom element, or some other things which will be added in the future (random-ideas-which-are-not-necessarily-good: filesystem providers, error handlers, themes, etc.). Let me write again my latest example: # mygui.py
from pyscript import Plugin
plugin = Plugin('mygui', priority=1) # priority is optional, of course
@plugin.init
def init():
print('this is executed as soon as the runtime is ready')
# maybe just @plugin.custom_element('my-button') ?
@plugin.register_custom_element('my-button')
class MyButton:
...
@plugin.register_custom_element('my-inputbox')
class MyInputBox:
...
@plugin.register_filesystem_provider
class GithubProvider:
... In this example:
Are we on the same page here?
that's perfectly fine. In the example above, it's perfectly reasonable to have a
Let's define "simple behavior" instead: you can implement custom elements with just a single function which returns HTML and/or a Node. That's it.
Sure: @plugin.register_custom_element('my-dialog-box', attributes="message")
class MyDialogBlox:
message: str
def connect(self):
return f"""
<div class="message">{self.message}</div>
<button>OK</button>
<button>Cancel</button>
"""
def click(self):
""" click on WHAT? """
I think that the approach |
"A Plugin is just a set of Python code that is loaded by the main pyscript logic and contains specific functions which will be called at appropriate times by using the hooks" - I rather love this definition. 🍔 Here is the JS to define a Custom Element.
I think we should align around Web Standards naming if we are performing identical actions within plugins. 'Plugin' naming is growing on me. 🧱 |
A Python Plugin is a set of Python code etc. etc.
definitely agree. |
Definitely like it better than
Yes! That capture what I was trying to convey... "A Plugin is a namespace which contains various functions will well-known names." That namespace can be a module or a class.. doesn't matter. +1 on starting with 1 module = 1 plugin [that can register many "things"].
Yes!
Ok. Anything more than this goes under Not sure it'd be that useful if we are limiting users to just that.... maybe. Need some time to digest :)
I fail to see it as "controversial" (and maybe it's on me) but if you attach a click to an object I expect it to represent a click on that object and not on its children. So click would be on the entire I can see how it'd be convenient to find an API that supports defining click events for the
That's it? We are just going to agree like that? Ok, fine.... deal, let's both be ok with it! 👍 😃
+1 on something like the above |
Wow, lots of things we agree on, I'm not used to it 😂 Let me answer only to the last remaining open point:
yes exactly, I'd also expect that. But I also expect that most custom elements will be composed of many DOM nodes, so a
Basically, I claim that there are very few cases in which the I have a counter-proposal: let's start humble and don't add features which might be not needed. Then we start writing plugins for real, and we will see what are the convenience features that we need. So, in the first iteration the example above could be something like this: plugin = Plugin('mygui')
@plugin.register_custom_element('my-hello', attributes=['name'])
def connected(name):
div = document.createElement('div')
div.innerHTML = f"<b>Hello {name}, I'm a custom widget</b>"
div.addEventListener('click', create_proxy(on_my_hello_click))
return div
def on_my_hello_click(evt):
print ("I've been clicked!") (A note about Also, about @plugin.register_custom_element('<my-hello>', attributes=['name'])
... |
Yeah. I think it's a good starting point and nothing prevents us to add it soon after. +1 on actually working on a better API to interact with the DOM and nodes (and add |
I AGREE 😂 |
Ok... as I develop this I realize we didn't talk too much in details about the API for plugins [class] to access the Custom Element (CE) on the page and all it's attributes. In the old extensions that we currently have in We could do this but I'd like to give the To step back a little, the main problem we are trying to solve here is:
.. and we should be intentional about how we solve for that in the API. |
this is a broad question, and I think it's very related to introducing a "Pythonic API" to access/modify the DOM (let's call it
I'm not really sure to understand what you mean here.
see above, this seems to be related to the hypotetical
in my proposal above, you would access it using |
@fpliger is this issue still relevant or did we implemented everything that was needed? |
Closing with the same comment I had for #763 : I think we covered [most of] it and changes should probably come up from a new and cleaner issue (also even just to keep things small and understandable).... Feel free to reopen if you disagree |
Checklist
type-feature
tag)What is the idea?
This is not a new topic but I'm opening a new issue to start a clean and focused discussion on the topic, considering that we already had a lot of preliminary discussions in #763 and #642 (in addition to a few experiments by many of the maintainers...) I'd like to have a clean place for us to converge on a proposal (and we can eventually close all the related issues once we are done).
I'll try to summarize where I think we left and what were the main items we agreed on (anyone, please, correct me here if you don't think it's right).
For starters, I believe that today we are in a much better place to actually converge on a [Python] Plugins design. In fact, in #763 @antocuni mentions a few steps toward that path:
and I'd claim that 1, 2 and 3 basically happened already or are very close.
So, with all that said...
Proposal
General Characteristics
<py-config>
configuration by using a dedicatedplugins
sectionpackages
section of the config (My proposal is that we support that but do not promote it as the primary method)pyscript-cli
or as an extension for other major web frameworks so that, for instance, server side rendering of Custom Elements via Plugin can also be achieved.Higher level API (Python)
Was thinking we might support plugins via a few ways... loosely something like this:
or a class decorator
or simple functions decorator:
or what's in #642 (honestly that's my least favorite...)
Finally, there are a couple of things I intentionally left out and open:
I am probably am missing a bunch of things but seems enough to start a discussion (in hopes we can converge :) )
Why is this needed
The current plugin system is very hacky and unstable
What should happen?
We should converge on a Plugins implementation proposal
Additional Context
No response
The text was updated successfully, but these errors were encountered: