-
Notifications
You must be signed in to change notification settings - Fork 2k
Fast way to implement common interfaces #5169
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
Conversation
Here's my suggested interface, instead of @tk.blanket_implementation(tk.Blanket.cli)
class ExampleBlanketCliPlugin(p.SingletonPlugin):
pass How about: @tk.blanket_cli
class ExampleBlanketCliPlugin(p.SingletonPlugin):
pass Then we just have |
I thought about something similar - after the discussion on Thursday having separate decorators has much more sense for me both in terms of extensibility and unambiguity(and I'm going to remove The only thing I'm concerning about when it comes to registering every blanket as toolkit item - won't there be an overwhelming number of toolkit members if we continue with adding everything there? So, instead of And some thoughts about the future evolution of this decorator. If there will be cases when the interface has few methods and we want to cover all of them, there should be some implementation aligned to single-method interfaces. For example, in the case of Personally, even though it sounds like "cool, they allow us to write less code", I'm leaning to restricted use-cases of blankets - initial idea was to provide a simple mechanism of reducing plain boilerplate. If this mechanism will be hard to get, will have some complex use-cases - we'll just end up with having two equal ways of doing the same thing, what I don't like at all. |
Updated as per @wardi 's suggestion. I've added documentation, and if anyone is too lazy to build it locally, here's how it looks: |
@amercader any comments on this? |
@smotornyuk sorry I let this sit, can you fix up the conflict so we can merge. I like this feature |
No problem, I won't be able to use this feature in production till the official release anyway:) |
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.
@smotornyuk Apologies for the long overdue review. This looks great. I added some minor comments.
And also rewrote the docs 🙃 I think this gives a clearer idea for users on how to use them and removes internal implementation details, but feel free to pick only the bits you think are useful:
https://gist.github.com/amercader/857ee22e9ea1c913bee3133cae81b45f
ckan/plugins/blanket.py
Outdated
blueprint = enum.auto() | ||
cli = enum.auto() | ||
validator = enum.auto() | ||
_all = helper | auth | action | blueprint | cli | validator |
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.
Shall we remove this? I think we agreed that "blanket all the things automatically" was bad so perhaps is best to just not offer the option.
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.
Yep, i'm done with testing so this line doesn't have any value anymore
ckan/plugins/blanket.py
Outdated
result = { | ||
item: getattr(subject, item) | ||
for item in getattr(subject, u"__all__", []) | ||
} |
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.
Does this exclude private functions from modules? eg functions starting with _
I think this would be reasonable, and should be documented
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've added a note about this point and updated logic a bit.
When __all__
attribute is not defined:
- all locally defined members whose name doesn't start with an underscore are exported
When __all__
attribute is defined:
- only items listed there are exported
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.
Sounds good!
ckan/plugins/blanket.py
Outdated
- ``tk.blanket.auth``: implemets ``IAuthFunctions`` | ||
- ``tk.blanket.action``: implemets ``IActions`` |
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.
For consistency with the interface names, should we use tk.blanket.auth_functions
and tk.blanket.actions
?
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.
Good point, updated
45308ac
to
be56844
Compare
Thanks @smotornyuk for the changes! |
Sorry @smotornyuk , not sure why but when merging this PEP8 tests failed in master. Can you have a look? |
Sure |
@amercader , hope you'll be interested in this pr - I just have some spare time and put what you suggested yesterday into code.
TL;DR
It would be cool, to quickly implement
IActions
,ITemplateHelpers
, etc, without using boilerplates in the form:plugin.implemens
Instead, let's just quickly decorate plugin's class(explicitly, so there is no change in existing plugins and no magic - the same as Ian, I believe that magic ruins code);
Usage:
helpers.py
, actions and auth functions inlogic.{action, auth}.py
or submodules, and for blueprints/cli we suggest to useviews.py
andcli.py
respectively. If you are following such structure, just decorate your plugin withtoolkit.blanket_implementation()
and you'll getITemplateHelpers
,IAuthFunctions
,IActions
,IBlueprint
,IClick
as long as corresponding import paths available. These interfaces will use a dictionary(or list in case of blueprint/cli) of items, registered in__all__
attribute of import path. i.eckanext.ext.views.__all__
defines registered blueprints.toolkit.Blanket
enumeration. Available options areall
,helper
,auth
,action
,blueprint
,cli
.all
is used by default.Why "blanket"? Because it "covers" interface, covers implementation, covers the import path. I don't know - it's kind of cute and I'm pretty bad in naming.