-
-
Notifications
You must be signed in to change notification settings - Fork 526
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
[WIP] External Plugins #1115
[WIP] External Plugins #1115
Conversation
Unit Test Results 16 files 16 suites 11s ⏱️ results for commit f35cea7 |
Awesome, thank you! I'll take a look at it by this weekend. |
def get_tags_count(journal): | ||
"""Returns a set of tuples (count, tag) for all tags present in the journal.""" | ||
# Astute reader: should the following line leave you as puzzled as me the first time | ||
# I came across this construction, worry not and embrace the ensuing moment of enlightment. | ||
# I came across this construction, worry not and embrace the ensuing moment of enlightenment. |
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.
haha, nice
__exporter_types = { | ||
**__exporter_types_builtin, | ||
**__exporter_types_contrib, | ||
**__exporter_types_template, | ||
} |
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.
So, this would override builtin plugins with contrib plugins of the same type, right? Does that behavior get communicated to the user in any way? If somebody runs jrnl --format markdown
, do they have any way to know if that's a builtin, or some random plugin they forgot they installed?
This would also be relevant for users reporting bugs. We need a way for us to know which version of which plugin they are using, I think.
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.
My first thought was to add the list of plugins (with versions) to the information displayed by jrnl --version
. But nothing has been implemented quite yet.
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.
(Trying to do this from my phone wasn't working... so now I'm at the computer)
this would override builtin plugins with contrib plugins of the same type, right?
Yes, that is what is supposed to happen. I haven't tested it yet....
Does that behavior get communicated to the user in any way?
No, not currently. My thought was to extend jrnl --version
to list the installed plugins, but to note the plugin used at the start of the export would be good too. In any case, the version of the plugin should be printed as well.
@minchinweb From a user standpoint, what does this look like? If I want to install a new plugin, what are the steps to do that? It seems like putting a file in the new contrib directory would work. Is that right? Are there other steps? |
__exporters_builtin = list( | ||
pkgutil.iter_modules( | ||
jrnl.plugins.exporter.__path__, jrnl.plugins.exporter.__name__ + "." | ||
) | ||
) | ||
__exporters_contrib = list( | ||
pkgutil.iter_modules( | ||
jrnl.contrib.exporter.__path__, jrnl.contrib.exporter.__name__ + "." | ||
) | ||
) | ||
|
||
__importers_builtin = list( | ||
pkgutil.iter_modules( | ||
jrnl.plugins.importer.__path__, jrnl.plugins.importer.__name__ + "." | ||
) | ||
) | ||
__importers_contrib = list( | ||
pkgutil.iter_modules( | ||
jrnl.contrib.importer.__path__, jrnl.contrib.importer.__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.
Instead of duplicating each of these (one for builtin, and one for contrib), can we have a function that will do all of this work given a path? Then we could run that function once for each path (builtin, and contrib).
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.
A standalone function would also be easier to add tests for.
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.
Can be done!
I've done this using namespace plugins. So to develop a new plugin, you would create a new Python project, with a layout something like:
(Note, no
You would then package it like any other Python library. The user would then install it like any other Python library (via In theory, putting a file into |
In that case, why are we including an empty contrib directory in jrnl? If we don't want users touching it, then I think we should not include it to discourage its use, right? |
To make sure the namespace exists, even if it's empty. If it doesn't exist, we can't import it, and we can't iterate over the contained packages. |
b6f03d3
to
3fb9fe5
Compare
I think this is looking okay. What this still needs:
|
Also:
|
355cf2f
to
c73d0ff
Compare
8bd89b7
to
7bacf4a
Compare
@wren: I updated this with an output that shows the active plugins and their versions, and added documentation. Testing is more complicated, as I need a way to create a new "testing environment" to install the sample plugins as python packages. Maybe that's simple, but I haven't figured it out yet and I wanted to share what I have done. I created a new branch because I gave up on trying to figure out how to cleanly push here, so the code is now at #1216. Thank you for all you do to keep the program moving forward! |
@wren This one's for you! This has been rattling around in my brain for soooooo long, but sometimes a little push at the right time is all that is needed to make the magic happen. So here we are. :)
This is a first pass at allowing external, namespace plugins.
Existing plugins are now in
jrnl.plugins.importer
andjrnl.plugins.exporter
. "Private" plugins are to be in thejrnl.contrib.importer
andjrnl.contrib.exporter
namespaces (so I might have my exporter atjrnl.contrib.exporter.minchinwebexporter
).Some other code was moved around to avoid circular imports and other weird import issues. The code hasn't been extensively tested, but
jrnl
appears to still be working locally, including listing all the export formats.No documentation has been added.
I also haven't run the tests (but the CI pipeline will soon tell me if I broken anything).
In the future, backends could probably also be added as/converted to plugins, but this doesn't try to do that.
c.f. #1006