Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added panlf CLI, made ContextImport x-platform
- Loading branch information
kiwi0fruit
committed
Dec 16, 2018
1 parent
8786ffe
commit 3e6d4b9
Showing
4 changed files
with
137 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,166 @@ | ||
""" | ||
Allow Panflute to be run as a command line script | ||
(so it can be used as a Pandoc filter) | ||
main(): | ||
to be used as a Pandoc filter | ||
panfl(): | ||
to be used in Pandoctools shell scripts as | ||
Pandoc filter with arguments | ||
""" | ||
|
||
import os | ||
import os.path as p | ||
import sys | ||
from collections import OrderedDict | ||
import click | ||
|
||
from .io import load, dump | ||
from .tools import debug, run_pandoc | ||
from .tools import debug | ||
from .utils import ContextImport | ||
|
||
|
||
def main(): | ||
def get_filter_dir(hardcoded=False): | ||
if hardcoded: | ||
if os.name == 'nt': | ||
return p.join(os.environ["APPDATA"], "pandoc", "filters") | ||
else: | ||
return p.join(os.environ["HOME"], ".pandoc", "filters") | ||
else: | ||
from .tools import run_pandoc | ||
# Extract $DATADIR | ||
info = run_pandoc(args=['--version']).splitlines() | ||
prefix = "Default user data directory: " | ||
info = [row for row in info if row.startswith(prefix)] | ||
assert len(info) == 1 | ||
data_dir = info[0][len(prefix):] | ||
return p.join(data_dir, 'filters') | ||
|
||
|
||
def _main(filters=None, extra_dirs=None, data_dir=False, sys_path=True): | ||
""" | ||
:param filters: Union[List[str], None] | ||
if not None then it's panfl | ||
instead of panflute | ||
:param extra_dirs: Union[List[str], None] | ||
if not None then it's panfl | ||
instead of panflute | ||
:param data_dir: bool | ||
:param sys_path: bool | ||
:return: json doc | ||
""" | ||
doc = load() | ||
meta = doc.metadata | ||
|
||
# meta = doc.metadata # Local variable 'meta' value is not used | ||
verbose = doc.get_metadata('panflute-verbose', False) | ||
|
||
# extra_path can be a list, a string, or missing | ||
extra_path = doc.get_metadata('panflute-path', []) | ||
if type(extra_path) != list: | ||
extra_path = [extra_path] | ||
if extra_dirs is None: | ||
# metadata 'panflute-path' can be a list, a string, or missing | ||
# `extra_dirs` should be a list of str | ||
extra_dirs = doc.get_metadata('panflute-path', []) | ||
if type(extra_dirs) != list: | ||
extra_dirs = [extra_dirs] | ||
extra_dirs.append('.') | ||
if data_dir: | ||
extra_dirs.append(get_filter_dir()) | ||
elif data_dir: | ||
# panfl case: | ||
extra_dirs.append(get_filter_dir(hardcoded=True)) | ||
|
||
# Display message (tests that everything is working ok) | ||
msg = doc.get_metadata('panflute-echo', False) | ||
if msg: | ||
debug(msg) | ||
|
||
# Run filters sequentially | ||
filters = doc.get_metadata('panflute-filters', []) | ||
|
||
# Allow for a single filter instead of a list | ||
if type(filters) != list: | ||
filters = [filters] | ||
if filters is None: | ||
# metadata 'panflute-filters' can be a list, a string, or missing | ||
# `filters` should be a list of str | ||
filters = doc.get_metadata('panflute-filters', []) | ||
if type(filters) != list: | ||
filters = [filters] | ||
|
||
if filters: | ||
if verbose: | ||
msg = "panflute: will run the following filters:" | ||
debug(msg, ' '.join(filters)) | ||
doc = autorun_filters(filters, doc, extra_path, verbose) | ||
doc = autorun_filters(filters, doc, extra_dirs, verbose, sys_path) | ||
elif verbose: | ||
debug("panflute: no filters found in metadata") | ||
debug("panflute: no filters were provided") | ||
|
||
dump(doc) | ||
|
||
|
||
def autorun_filters(filters, doc, searchpath, verbose): | ||
# Extract $DATADIR | ||
info = run_pandoc(args=['--version']).splitlines() | ||
prefix = "Default user data directory: " | ||
info = [row for row in info if row.startswith(prefix)] | ||
assert len(info) == 1 | ||
datadir = info[0][len(prefix):] | ||
filterdir = os.path.join(datadir, 'filters') | ||
|
||
searchpath = searchpath + ['.', filterdir] + sys.path | ||
filenames = OrderedDict() | ||
|
||
for ff in filters: | ||
for p in searchpath: | ||
|
||
def main(): | ||
_main(data_dir=True) | ||
|
||
|
||
@click.command(help="Filters should have basename only (may be with or without .py extension). " + | ||
"Search preserves directories order (except for --data-dir and `sys.path`).") | ||
@click.argument('filters', nargs=-1) | ||
@click.option('-w', '-t', '--write', '--to', 'to', type=str, default='html', | ||
help='Pandoc writer option.') | ||
@click.option('--dir', '-d', 'extra_dirs', multiple=True, | ||
help="Search filters in provided directories: `-d dir1 -d dir2`.") | ||
@click.option('--data-dir', is_flag=True, default=False, | ||
help="Search filters in default user data directory listed in `pandoc --version` " + | ||
"(in it's `filters` subfolder actually). It's appended to the search list.") | ||
@click.option('--no-sys-path', 'not_sys_path', is_flag=True, default=False, | ||
help="Disable search filters in python's `sys.path` " + | ||
"(I tried to remove current working directory either way) " + | ||
"that is appended to the search list.") | ||
def panfl(filters, to, extra_dirs, data_dir, not_sys_path): | ||
# `load()` in `_main()` needs `to` in the 2nd arg | ||
if len(sys.argv) > 1: | ||
sys.argv[1] = to | ||
elif len(sys.argv) == 1: | ||
sys.argv.append(to) | ||
_main(list(filters), list(extra_dirs), data_dir, sys_path=not not_sys_path) | ||
|
||
|
||
def autorun_filters(filters, doc, extra_dirs, verbose, sys_path=True): | ||
""" | ||
:param filters: list of str | ||
:param doc: panflute.Doc | ||
:param extra_dirs: list of str | ||
:param verbose: bool | ||
:param sys_path: bool | ||
:return: panflute.Doc | ||
""" | ||
search_path = extra_dirs | ||
if sys_path: | ||
search_path += [dir_ for dir_ in sys.path if (dir_ != '') and (dir_ != '.') and p.isdir(dir_)] | ||
|
||
file_names = OrderedDict() | ||
|
||
for file_ in filters: | ||
for path in search_path: | ||
# Allow with and without .py ending | ||
if ff.endswith('.py'): | ||
fn = os.path.join(p, ff) | ||
else: | ||
fn = os.path.join(p, ff + '.py') | ||
filter_path = p.join(path, file_ + ('' if file_.endswith('.py') else '.py')) | ||
|
||
if os.path.isfile(fn): | ||
if p.isfile(filter_path): | ||
if verbose: | ||
debug("panflute: filter <{}> found in {}".format(ff, fn)) | ||
filenames[ff] = fn | ||
debug("panflute: filter <{}> found in {}".format(file_, filter_path)) | ||
file_names[file_] = filter_path | ||
break | ||
elif verbose: | ||
debug(" filter <{}> NOT found in {}".format(ff, fn)) | ||
debug(" filter <{}> NOT found in {}".format(file_, filter_path)) | ||
else: | ||
raise Exception("filter not found: " + ff) | ||
raise Exception("filter not found: " + file_) | ||
|
||
for ff, fn in filenames.items(): | ||
_ = dict() | ||
for file_, filter_path in file_names.items(): | ||
if verbose: | ||
debug("panflute: running filter <{}>".format(ff)) | ||
with ContextImport(fn) as module: | ||
debug("panflute: running filter <{}>".format(file_)) | ||
with ContextImport(filter_path) as module: | ||
try: | ||
module.main(doc) | ||
except: | ||
debug("Failed to run filter: " + ff) | ||
except Exception as e: | ||
debug("Failed to run filter: " + file_) | ||
if not hasattr(module, 'main'): | ||
debug(' - Possible cause: filter lacks a main() function') | ||
debug('Filter code:') | ||
debug('-' * 64) | ||
debug(code) | ||
with open(filter_path) as fp: | ||
debug(fp.read()) | ||
debug('-' * 64) | ||
raise | ||
raise Exception(e) | ||
if verbose: | ||
debug("panflute: filter <{}> completed".format(ff)) | ||
debug("panflute: filter <{}> completed".format(file_)) | ||
|
||
return doc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters