Use implicit namespace plugins for import and export (#1216)

* behavior outline

* FIrst pass at allow external plugins

* remove template exporter

* Add listing of active plugins to '--version' output

* Documentation for plugins

* [Docs] add custom imports and exporters to site TOC

* [Docs] better linewrapping

* enforce positive initial linewrap

Check column widths

update gitignore

throw error when linewrap too small

simply check for large enough linewrap value

* delete unused error message

* PR feedback

make exception more informative

update check_linewrap signature in src and test

make check_linewrap a free function

* delete unused function

* delete else..pass block

* newline for make format

* Include dates_exporter

* Use Base classes for importer and exporters.

* [Docs] improve documentation of custom Importers and Exporters

* [Testing] separate run with external plugin!

* basic behavior test

* prototype unittest for JSON Exporter

test for unimplemented method

* make format

delete unused imports

* Remove 'importer' or 'exporter' from filenames where not needed

* [Test] run different tests with or without the external plugins installed

* [Test] move test rot13 plugin into git tree

from 0dc912af82

* consolidate demo plugins to common package

* [Docs] name page for plugins

* [Docs] include the sample plug in code files directly

* style fixes

* [test] determine whether to run external plug in tests based on installed packages

* improved code documentation

* style fixes for GitHub actions

* Convert "short" and "pretty" (and "default") formaters to plugins

further to https://github.com/jrnl-org/jrnl/pull/1177

* more code clean up

tests pass locally...now for GitHub...

* [tests] dynamically determine jrnl version for plugin tests

* [GitHub Actions] direct install of testing plugins

* Remove template code

* [plugins] meta --> collector

* [Docs] create scripted entries using an custom importer

* (closer to) being able to run behave tests outside project root directory

* We already know when exporter to use
Don't re-calculate it!

* [Tests] don't name test plugin 'testing"
If so named, pip won't install it.

* [Test] run behave tests with test plugins outside project root

* [Test] behave tests pass locally

* [Docs] fix typo

* [GitHub Actions] run test commands from poetry's shell

* black-ify code

* [GitHub Actions] move downstream (rather than up) to run tests

* [GitHub Actions] set shell to poetry

* [GitHub Workflows] Manually activate virtual environment

* [GitHub Actions] Skip Windows & Python 3.8
Can't seem to find Python exe?

* [GiotHub Actions] explicitly use virtual env

* [GitHub Actions] create virutal env directly

* [GitHub Actions] better activate of Windows virtual env

* [GitHub Actions] create virtual env on Mac

* [Github Actions] install wheel and upgrade pip

* [GitHub Actions] skip virtual environments altogether

* [GitHub Actions] change directory for behave test

* Remove Windows exclusions from CI as per note -- they should be working now

Co-authored-by: Suhas <sugas182@gmail.com>
Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>
This commit is contained in:
MinchinWeb 2021-05-29 18:21:45 -06:00 committed by GitHub
parent 104fa2caca
commit 1a7e8d8ea2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 1025 additions and 409 deletions

View file

@ -0,0 +1,9 @@
# Rot13 Custom Exporter for Jrnl
This is a custom exporter to demostrate how to write customer exporters for
[jrnl](https://github.com/jrnl-org/jrnl). It is also used by *jrnl* in its
tests to ensure the feature works as expected.
This plugin applies a [Caeser
cipher](https://en.wikipedia.org/wiki/Caesar_cipher) (specifically the
[ROT13](https://en.wikipedia.org/wiki/ROT13)) to output text.

View file

@ -0,0 +1,37 @@
# pelican\contrib\exporter\custom_json.py
import json
from jrnl.plugins.base import BaseExporter
__version__ = "v1.0.0"
class Exporter(BaseExporter):
"""
This basic Exporter can convert entries and journals into JSON.
"""
names = ["json"]
extension = "json"
version = __version__
@classmethod
def entry_to_dict(cls, entry):
return {
"title": entry.title,
"body": entry.body,
"date": entry.date.strftime("%Y-%m-%d"),
}
@classmethod
def export_entry(cls, entry):
"""Returns a json representation of a single entry."""
return json.dumps(cls.entry_to_dict(entry), indent=2) + "\n"
@classmethod
def export_journal(cls, journal):
"""Returns a json representation of an entire journal."""
result = {
"entries": [cls.entry_to_dict(e) for e in journal.entries],
}
return json.dumps(result, indent=2)

View file

@ -0,0 +1,25 @@
#!/usr/bin/env python
# encoding: utf-8
# Copyright (C) 2012-2021 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html
"""
Exporter for testing and experimentation purposes.
It is not called "testing" because then it's not installed.
The presence of this plugin is also used as a "switch" by the test suite to
decide on whether or not to run the "vanilla" test suite, or the test suite
for external plugins.
The `export_entry` and `export_journal` methods are both purposely not
implemented to confirm behavior on plugins that don't implement them.
"""
from jrnl.plugins.base import BaseExporter
class Exporter(BaseExporter):
names = ["testing", "test"]
version = "v0.0.1"
extension = "test"

View file

@ -0,0 +1,15 @@
import codecs
from jrnl.plugins.base import BaseExporter
__version__ = "v1.0.0"
class Exporter(BaseExporter):
names = ["rot13", "txt"]
extension = "txt"
version = __version__
@classmethod
def export_entry(cls, entry):
return codecs.encode(str(entry), "rot_13")

View file

@ -0,0 +1,50 @@
# pelican\contrib\importer\sample_json.py
import json
import sys
from jrnl import Entry
from jrnl.plugins.base import BaseImporter
__version__ = "v1.0.0"
class Importer(BaseImporter):
"""JSON Importer for jrnl."""
names = ["json"]
version = __version__
@staticmethod
def import_(journal, input=None):
"""
Given a nicely formatted JSON file, will add the
contained Entries to the journal.
"""
old_cnt = len(journal.entries)
if input:
with open(input, "r", encoding="utf-8") as f:
data = json.loads(f)
else:
try:
data = sys.stdin.read()
except KeyboardInterrupt:
print(
"[Entries NOT imported into journal.]",
file=sys.stderr,
)
sys.exit(0)
for json_entry in data:
raw = json_entry["title"] + "/n" + json_entry["body"]
date = json_entry["date"]
entry = Entry.Entry(journal, date, raw)
journal.entries.append(entry)
new_cnt = len(journal.entries)
print(
"[{} entries imported to '{}' journal]".format(
new_cnt - old_cnt, journal.name
),
file=sys.stderr,
)

View file

@ -0,0 +1,35 @@
import os
import re
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
base_dir = os.path.dirname(os.path.abspath(__file__))
def get_version(filename="jrnl/contrib/exporter/rot13.py"):
with open(os.path.join(base_dir, filename), encoding="utf-8") as initfile:
for line in initfile.readlines():
m = re.match("__version__ *= *['\"](.*)['\"]", line)
if m:
return m.group(1)
setup(
name="jrnl-demo-plugins",
version=get_version(),
description="Demonstration custom plugins for jrnl",
long_description="\n\n".join([open(os.path.join(base_dir, "README.md")).read()]),
long_description_content_type="text/markdown",
author="W. Minchin",
author_email="w_minchin@hotmail.com",
url="https://github.com/jrnl-org/jrnl/tree/develop/tests/external_plugins_src",
packages=["jrnl", "jrnl.contrib", "jrnl.contrib.exporter", "jrnl.contrib.importer"],
include_package_data=True,
install_requires=[
"jrnl",
],
zip_safe=False, # use wheels instead
)