From e1691830b1c9a6b424a4340f98233c84f174316f Mon Sep 17 00:00:00 2001 From: Luke Murphy Date: Mon, 7 Oct 2019 22:22:22 +0200 Subject: [PATCH] Add the experimentation API Closes https://git.vvvvvvaria.org/varia/etherpump/issues/2. --- README.md | 22 ++++++++++++++++-- etherpump/__init__.py | 2 +- etherpump/api/__init__.py | 1 + etherpump/api/_utils.py | 23 +++++++++++++++++++ etherpump/api/magicword.py | 37 +++++++++++++++++++++++++++++++ etherpump/commands/init.py | 4 +--- etherpump/commands/publication.py | 7 +++--- etherpump/examples/magicword.py | 25 +++++++++++++++++++++ 8 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 etherpump/api/__init__.py create mode 100644 etherpump/api/_utils.py create mode 100644 etherpump/api/magicword.py create mode 100644 etherpump/examples/magicword.py diff --git a/README.md b/README.md index f8d7522..d4b3004 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ Added the `python-dateutil` and `pypandoc` dependencies Added a fancy progress bar with `tqdm` for long running `etherpump pull --all` calls +Started with the experimental library API. + **September 2019** Forking *etherpump* into *etherpump*. @@ -97,8 +99,8 @@ Install etherpump Etherpump only supports Python 3. -Example -------- +Command-line example +-------------------- ``` $ mkdir mydump @@ -118,6 +120,22 @@ The APIKEY is the contents of the file APIKEY.txt in the etherpad folder. The settings are placed in a file called `.etherpump/settings.json` and are used (by default) by future commands. +Library API Example +------------------- + +Etherpump can be used as a library. See [etherpump/examples](https://git.vvvvvvaria.org/varia/etherpump/src/branch/master/etherpump/examples) +or read the short one below: + +```python +from etherpump.api import magicword + +@magicword('__VARIA_PUB_CLUB__') +def maakt_niet_uit_wat_je_hier_schrijft(pads): + print(pads['my-pad-name']['html']) +``` + +This is still a work in progress. + Subcommands ---------- diff --git a/etherpump/__init__.py b/etherpump/__init__.py index b560872..ec923ad 100644 --- a/etherpump/__init__.py +++ b/etherpump/__init__.py @@ -2,4 +2,4 @@ import os DATAPATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") -__VERSION__ = '0.0.4' +__VERSION__ = '0.0.5' diff --git a/etherpump/api/__init__.py b/etherpump/api/__init__.py new file mode 100644 index 0000000..efb7cde --- /dev/null +++ b/etherpump/api/__init__.py @@ -0,0 +1 @@ +from etherpump.api.magicword import magicword # noqa diff --git a/etherpump/api/_utils.py b/etherpump/api/_utils.py new file mode 100644 index 0000000..eb3e026 --- /dev/null +++ b/etherpump/api/_utils.py @@ -0,0 +1,23 @@ +"""Utilities for API functions.""" + +from pathlib import Path +from urllib.parse import urlencode + +from etherpump.commands.common import getjson, loadpadinfo +from etherpump.commands.init import main + + +def ensure_init(): + """Ensure etherpump has already been init'd.""" + try: + main([]) + except SystemExit: + pass + + +def get_pad_ids(): + """Retrieve all available pad ids.""" + info = loadpadinfo(Path('.etherpump/settings.json')) + data = {'apikey': info['apikey']} + url = info['localapiurl'] + 'listAllPads?' + urlencode(data) + return getjson(url)['data']['padIDs'] diff --git a/etherpump/api/magicword.py b/etherpump/api/magicword.py new file mode 100644 index 0000000..8be20e6 --- /dev/null +++ b/etherpump/api/magicword.py @@ -0,0 +1,37 @@ +"""API for programming against pads marked with __MAGIC_WORDS__.""" + +__all__ = ['magicword'] + +import json +from pathlib import Path + +from etherpump.api._utils import ensure_init, get_pad_ids +from etherpump.commands.pull import main as pull + + +def magicword(word): + """Decorator for handling magic words.""" + + ensure_init() + pull(['--all', '--publish-opt-in', '--publish', word]) + + pads = {} + for pad_id in get_pad_ids(): + pads[pad_id] = {} + try: + pads[pad_id]['html'] = open(Path(f'./p/{pad_id}.raw.html')).read() + pads[pad_id]['txt'] = open(Path(f'./p/{pad_id}.raw.txt')).read() + pads[pad_id]['meta'] = json.loads( + open(Path(f'./p/{pad_id}.meta.json')).read() + ) + pads[pad_id]['dhtml'] = open(Path(f'./p/{pad_id}.raw.dhtml')).read() + except FileNotFoundError: + pass + + def wrap(userfunc): + def wrappedf(*args): + userfunc(pads) + + return wrappedf + + return wrap diff --git a/etherpump/commands/init.py b/etherpump/commands/init.py index 4d22937..2953bf6 100644 --- a/etherpump/commands/init.py +++ b/etherpump/commands/init.py @@ -92,9 +92,7 @@ def main(args): with open(padinfopath) as f: padinfo = json.load(f) if not args.reinit: - print( - "Folder is already initialized. Use --reinit to reset settings." - ) + print("Folder already initialized. Use --reinit to reset settings") sys.exit(0) except IOError: pass diff --git a/etherpump/commands/publication.py b/etherpump/commands/publication.py index b939360..cc6830b 100644 --- a/etherpump/commands/publication.py +++ b/etherpump/commands/publication.py @@ -194,8 +194,8 @@ def main(args): ) pg.add_argument( "--generator", - default="https://gitlab.com/activearchives/etherpump", - help="generator, default: https://gitlab.com/activearchives/etherdump", + default="https://git.vvvvvvaria.org/varia/etherpump", + help="generator, default: https://git.vvvvvvaria.org/varia/etherdump", ) pg.add_argument( "--timestamp", @@ -223,6 +223,7 @@ def main(args): inputs = args.input inputs.sort() + # Use "base" to strip (longest) extensions # inputs = group(inputs, base) @@ -253,7 +254,7 @@ def main(args): if p.endswith(".meta.json"): with open(p) as f: return json.load(f) - # # IF there is a .meta.json, load it & MERGE with other files + # if there is a .meta.json, load it & MERGE with other files # if ret: # # TODO: merge with other files # for p in paths: diff --git a/etherpump/examples/magicword.py b/etherpump/examples/magicword.py new file mode 100644 index 0000000..1ebba37 --- /dev/null +++ b/etherpump/examples/magicword.py @@ -0,0 +1,25 @@ +"""How to use the 'magicword' API. + +In this example, we have a pad called "my-pad-name" on our etherpad-lite +instance. Inside the content of that pad is the so-called "magic word" +__WORSE_IS_BETTER__. The "@magicword" takes care of retrieving all the formats +of those pads and returns a dictionary called "pads" ready to go. + +Run this example like so: + +$ python etherdump/examples/magicword.py + +""" + +from etherpump.api import magicword + + +@magicword('__WORSE_IS_BETTER__') +def can_be_called_anything_you_like(pads): + print(pads['foobar']['html']) + print(pads['foobar']['txt']) + print(pads['foobar']['meta']) + + +if __name__ == "__main__": + can_be_called_anything_you_like()