From e25869e9bc66d3698fdc2b5f8f36eb78bd360c01 Mon Sep 17 00:00:00 2001 From: MinchinWeb Date: Sun, 13 Dec 2020 21:28:19 -0700 Subject: [PATCH] FIrst pass at allow external plugins --- features/steps/core.py | 2 +- jrnl/args.py | 4 +- jrnl/commands.py | 2 +- jrnl/contrib/exporter/.gitkeep | 0 jrnl/contrib/importer/.gitkeep | 0 jrnl/jrnl.py | 6 +- jrnl/plugins/__init__.py | 46 +--------- jrnl/plugins/{ => exporter}/fancy_exporter.py | 4 +- jrnl/plugins/{ => exporter}/json_exporter.py | 6 +- .../{ => exporter}/markdown_exporter.py | 5 +- jrnl/plugins/{ => exporter}/tag_exporter.py | 6 +- jrnl/plugins/{ => exporter}/text_exporter.py | 2 +- jrnl/plugins/{ => exporter}/xml_exporter.py | 6 +- jrnl/plugins/{ => exporter}/yaml_exporter.py | 5 +- jrnl/plugins/{ => importer}/jrnl_importer.py | 2 +- jrnl/plugins/meta.py | 84 +++++++++++++++++++ jrnl/plugins/template_exporter.py | 6 +- jrnl/plugins/util.py | 3 +- 18 files changed, 113 insertions(+), 76 deletions(-) create mode 100644 jrnl/contrib/exporter/.gitkeep create mode 100644 jrnl/contrib/importer/.gitkeep rename jrnl/plugins/{ => exporter}/fancy_exporter.py (96%) rename jrnl/plugins/{ => exporter}/json_exporter.py (93%) rename jrnl/plugins/{ => exporter}/markdown_exporter.py (96%) rename jrnl/plugins/{ => exporter}/tag_exporter.py (87%) rename jrnl/plugins/{ => exporter}/text_exporter.py (99%) rename jrnl/plugins/{ => exporter}/xml_exporter.py (93%) rename jrnl/plugins/{ => exporter}/yaml_exporter.py (98%) rename jrnl/plugins/{ => importer}/jrnl_importer.py (98%) create mode 100644 jrnl/plugins/meta.py diff --git a/features/steps/core.py b/features/steps/core.py index ac5d8950..89a00559 100644 --- a/features/steps/core.py +++ b/features/steps/core.py @@ -462,7 +462,7 @@ def run(context, command, text=""): def load_template(context, filename): full_path = os.path.join("features/data/templates", filename) exporter = plugins.template_exporter.__exporter_from_file(full_path) - plugins.__exporter_types[exporter.names[0]] = exporter + plugins.meta.__exporter_types[exporter.names[0]] = exporter @when('we set the keyring password of "{journal}" to "{password}"') diff --git a/jrnl/args.py b/jrnl/args.py index c8bd7743..52656ad5 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -12,9 +12,9 @@ from .commands import postconfig_list from .commands import preconfig_diagnostic from .commands import preconfig_version from .output import deprecated_cmd -from .plugins import EXPORT_FORMATS -from .plugins import IMPORT_FORMATS from .plugins import util +from .plugins.meta import EXPORT_FORMATS +from .plugins.meta import IMPORT_FORMATS class WrappingFormatter(argparse.RawTextHelpFormatter): diff --git a/jrnl/commands.py b/jrnl/commands.py index 8473954e..6017347b 100644 --- a/jrnl/commands.py +++ b/jrnl/commands.py @@ -47,7 +47,7 @@ def postconfig_list(config, **kwargs): def postconfig_import(args, config, **kwargs): from .Journal import open_journal - from .plugins import get_importer + from .plugins.meta import get_importer # Requires opening the journal journal = open_journal(args.journal_name, config) diff --git a/jrnl/contrib/exporter/.gitkeep b/jrnl/contrib/exporter/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/jrnl/contrib/importer/.gitkeep b/jrnl/contrib/importer/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/jrnl/jrnl.py b/jrnl/jrnl.py index cf2b3bbb..f35e3119 100644 --- a/jrnl/jrnl.py +++ b/jrnl/jrnl.py @@ -330,13 +330,13 @@ def _display_search_results(args, journal, **kwargs): print(journal.pprint()) elif args.tags: - print(plugins.get_exporter("tags").export(journal)) + print(plugins.meta.get_exporter("tags").export(journal)) elif args.export: - exporter = plugins.get_exporter(args.export) + exporter = plugins.meta.get_exporter(args.export) print(exporter.export(journal, args.filename)) elif kwargs["config"].get("display_format"): - exporter = plugins.get_exporter(kwargs["config"]["display_format"]) + exporter = plugins.meta.get_exporter(kwargs["config"]["display_format"]) print(exporter.export(journal, args.filename)) else: print(journal.pprint()) diff --git a/jrnl/plugins/__init__.py b/jrnl/plugins/__init__.py index 3eb4d5a2..4c1f6f36 100644 --- a/jrnl/plugins/__init__.py +++ b/jrnl/plugins/__init__.py @@ -1,49 +1,5 @@ #!/usr/bin/env python # encoding: utf-8 + # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html - -from .fancy_exporter import FancyExporter -from .jrnl_importer import JRNLImporter -from .json_exporter import JSONExporter -from .markdown_exporter import MarkdownExporter -from .tag_exporter import TagExporter -from .dates_exporter import DatesExporter -from .template_exporter import __all__ as template_exporters -from .text_exporter import TextExporter -from .xml_exporter import XMLExporter -from .yaml_exporter import YAMLExporter - -__exporters = [ - JSONExporter, - MarkdownExporter, - TagExporter, - DatesExporter, - TextExporter, - XMLExporter, - YAMLExporter, - FancyExporter, -] + template_exporters -__importers = [JRNLImporter] - -__exporter_types = {name: plugin for plugin in __exporters for name in plugin.names} -__exporter_types["pretty"] = None -__exporter_types["short"] = None -__importer_types = {name: plugin for plugin in __importers for name in plugin.names} - -EXPORT_FORMATS = sorted(__exporter_types.keys()) -IMPORT_FORMATS = sorted(__importer_types.keys()) - - -def get_exporter(format): - for exporter in __exporters: - if hasattr(exporter, "names") and format in exporter.names: - return exporter - return None - - -def get_importer(format): - for importer in __importers: - if hasattr(importer, "names") and format in importer.names: - return importer - return None diff --git a/jrnl/plugins/fancy_exporter.py b/jrnl/plugins/exporter/fancy_exporter.py similarity index 96% rename from jrnl/plugins/fancy_exporter.py rename to jrnl/plugins/exporter/fancy_exporter.py index 74cc6958..f5d25ae0 100644 --- a/jrnl/plugins/fancy_exporter.py +++ b/jrnl/plugins/exporter/fancy_exporter.py @@ -5,10 +5,10 @@ from textwrap import TextWrapper -from .text_exporter import TextExporter +from jrnl.plugins.exporter.text_exporter import Exporter as TextExporter -class FancyExporter(TextExporter): +class Exporter(TextExporter): """This Exporter can convert entries and journals into text with unicode box drawing characters.""" names = ["fancy", "boxed"] diff --git a/jrnl/plugins/json_exporter.py b/jrnl/plugins/exporter/json_exporter.py similarity index 93% rename from jrnl/plugins/json_exporter.py rename to jrnl/plugins/exporter/json_exporter.py index dd07b0ce..d4971599 100644 --- a/jrnl/plugins/json_exporter.py +++ b/jrnl/plugins/exporter/json_exporter.py @@ -5,11 +5,11 @@ import json -from .text_exporter import TextExporter -from .util import get_tags_count +from jrnl.plugins.exporter.text_exporter import Exporter as TextExporter +from jrnl.plugins.util import get_tags_count -class JSONExporter(TextExporter): +class Exporter(TextExporter): """This Exporter can convert entries and journals into json.""" names = ["json"] diff --git a/jrnl/plugins/markdown_exporter.py b/jrnl/plugins/exporter/markdown_exporter.py similarity index 96% rename from jrnl/plugins/markdown_exporter.py rename to jrnl/plugins/exporter/markdown_exporter.py index 693f2fa5..113c28e3 100644 --- a/jrnl/plugins/markdown_exporter.py +++ b/jrnl/plugins/exporter/markdown_exporter.py @@ -9,11 +9,10 @@ import sys from jrnl.color import RESET_COLOR from jrnl.color import WARNING_COLOR - -from .text_exporter import TextExporter +from jrnl.plugins.exporter.text_exporter import Exporter as TextExporter -class MarkdownExporter(TextExporter): +class Exporter(TextExporter): """This Exporter can convert entries and journals into Markdown.""" names = ["md", "markdown"] diff --git a/jrnl/plugins/tag_exporter.py b/jrnl/plugins/exporter/tag_exporter.py similarity index 87% rename from jrnl/plugins/tag_exporter.py rename to jrnl/plugins/exporter/tag_exporter.py index bc3736eb..ee360446 100644 --- a/jrnl/plugins/tag_exporter.py +++ b/jrnl/plugins/exporter/tag_exporter.py @@ -3,11 +3,11 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html -from .text_exporter import TextExporter -from .util import get_tags_count +from jrnl.plugins.exporter.text_exporter import Exporter as TextExporter +from jrnl.plugins.util import get_tags_count -class TagExporter(TextExporter): +class Exporter(TextExporter): """This Exporter can lists the tags for entries and journals, exported as a plain text file.""" names = ["tags"] diff --git a/jrnl/plugins/text_exporter.py b/jrnl/plugins/exporter/text_exporter.py similarity index 99% rename from jrnl/plugins/text_exporter.py rename to jrnl/plugins/exporter/text_exporter.py index 7714606c..9ed39916 100644 --- a/jrnl/plugins/text_exporter.py +++ b/jrnl/plugins/exporter/text_exporter.py @@ -11,7 +11,7 @@ from jrnl.color import ERROR_COLOR from jrnl.color import RESET_COLOR -class TextExporter: +class Exporter: """This Exporter can convert entries and journals into text files.""" names = ["text", "txt"] diff --git a/jrnl/plugins/xml_exporter.py b/jrnl/plugins/exporter/xml_exporter.py similarity index 93% rename from jrnl/plugins/xml_exporter.py rename to jrnl/plugins/exporter/xml_exporter.py index b9467912..ec28c337 100644 --- a/jrnl/plugins/xml_exporter.py +++ b/jrnl/plugins/exporter/xml_exporter.py @@ -5,11 +5,11 @@ from xml.dom import minidom -from .json_exporter import JSONExporter -from .util import get_tags_count +from jrnl.plugins.exporter.json_exporter import Exporter as JSONExporter +from jrnl.plugins.util import get_tags_count -class XMLExporter(JSONExporter): +class Exporter(JSONExporter): """This Exporter can convert entries and journals into XML.""" names = ["xml"] diff --git a/jrnl/plugins/yaml_exporter.py b/jrnl/plugins/exporter/yaml_exporter.py similarity index 98% rename from jrnl/plugins/yaml_exporter.py rename to jrnl/plugins/exporter/yaml_exporter.py index 7716c6c1..8cce8dca 100644 --- a/jrnl/plugins/yaml_exporter.py +++ b/jrnl/plugins/exporter/yaml_exporter.py @@ -10,11 +10,10 @@ import sys from jrnl.color import ERROR_COLOR from jrnl.color import RESET_COLOR from jrnl.color import WARNING_COLOR - -from .text_exporter import TextExporter +from jrnl.plugins.exporter.text_exporter import Exporter as TextExporter -class YAMLExporter(TextExporter): +class Exporter(TextExporter): """This Exporter can convert entries and journals into Markdown formatted text with YAML front matter.""" names = ["yaml"] diff --git a/jrnl/plugins/jrnl_importer.py b/jrnl/plugins/importer/jrnl_importer.py similarity index 98% rename from jrnl/plugins/jrnl_importer.py rename to jrnl/plugins/importer/jrnl_importer.py index af5ea6ce..3fe11e32 100644 --- a/jrnl/plugins/jrnl_importer.py +++ b/jrnl/plugins/importer/jrnl_importer.py @@ -6,7 +6,7 @@ import sys -class JRNLImporter: +class Importer: """This plugin imports entries from other jrnl files.""" names = ["jrnl"] diff --git a/jrnl/plugins/meta.py b/jrnl/plugins/meta.py new file mode 100644 index 00000000..3cbff1ec --- /dev/null +++ b/jrnl/plugins/meta.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import importlib +import pkgutil + +import jrnl.contrib.exporter +import jrnl.contrib.importer +import jrnl.plugins.exporter +import jrnl.plugins.importer + +from .template_exporter import __all__ as template_exporters + +__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__ + "." + ) +) + +__exporter_types_builtin = { + name: importlib.import_module(plugin.name) + for plugin in __exporters_builtin + for name in importlib.import_module(plugin.name).Exporter.names +} +__exporter_types_contrib = { + name: importlib.import_module(plugin.name) + for plugin in __exporters_contrib + for name in importlib.import_module(plugin.name).Exporter.names +} +__exporter_types_template = { + name: plugin for plugin in template_exporters for name in plugin.names +} + + +__importer_types_builtin = { + name: importlib.import_module(plugin.name) + for plugin in __importers_builtin + for name in importlib.import_module(plugin.name).Importer.names +} +__importer_types_contrib = { + name: importlib.import_module(plugin.name) + for plugin in __importers_contrib + for name in importlib.import_module(plugin.name).Importer.names +} + +__exporter_types = { + **__exporter_types_builtin, + **__exporter_types_contrib, + **__exporter_types_template, +} +__importer_types = {**__importer_types_builtin, **__importer_types_contrib} + +EXPORT_FORMATS = sorted(__exporter_types.keys()) +IMPORT_FORMATS = sorted(__importer_types.keys()) + + +def get_exporter(format): + for exporter in __exporters: + if hasattr(exporter, "names") and format in exporter.names: + return exporter + return None + + +def get_importer(format): + for importer in __importers: + if hasattr(importer, "names") and format in importer.names: + return importer + return None diff --git a/jrnl/plugins/template_exporter.py b/jrnl/plugins/template_exporter.py index af081f8c..4e6adfc0 100644 --- a/jrnl/plugins/template_exporter.py +++ b/jrnl/plugins/template_exporter.py @@ -6,8 +6,8 @@ from glob import glob import os -from .template import Template -from .text_exporter import TextExporter +from jrnl.plugins.template import Template +from jrnl.plugins.exporter.text_exporter import Exporter as TextExporter class GenericTemplateExporter(TextExporter): @@ -31,7 +31,7 @@ def __exporter_from_file(template_file): name = os.path.basename(template_file).replace(".template", "") template = Template.from_file(template_file) return type( - str(f"{name.title()}Exporter"), + str(f"{name.title()}TemplateExporter"), (GenericTemplateExporter,), {"names": [name], "extension": template.extension, "template": template}, ) diff --git a/jrnl/plugins/util.py b/jrnl/plugins/util.py index 04159ca4..c5d16529 100644 --- a/jrnl/plugins/util.py +++ b/jrnl/plugins/util.py @@ -3,11 +3,10 @@ # Copyright (C) 2012-2021 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html - 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. tags = [tag for entry in journal.entries for tag in set(entry.tags)] # To be read: [for entry in journal.entries: for tag in set(entry.tags): tag] tag_counts = {(tags.count(tag), tag) for tag in tags}