From ff195c0859a475f5a873a1714c77f6c169d88564 Mon Sep 17 00:00:00 2001 From: jgrizou Date: Tue, 25 Jun 2013 19:45:00 +0200 Subject: [PATCH] Plugins class created and handle for the parse. Next step is to code the event messages. Next one is to code the setup extension. --- papers/papers | 9 ++- papers/plugins.py | 72 +++++++++++++++++++ papers/{plugins => plugs}/__init__.py | 0 papers/{plugins => plugs}/texnote/__init__.py | 0 .../texnote/note_sample.tex | 0 .../texnote/texnote.py} | 60 +++++++--------- setup.py | 2 +- 7 files changed, 107 insertions(+), 36 deletions(-) create mode 100644 papers/plugins.py rename papers/{plugins => plugs}/__init__.py (100%) rename papers/{plugins => plugs}/texnote/__init__.py (100%) rename papers/{plugins => plugs}/texnote/note_sample.tex (100%) rename papers/{plugins/texnote/texnote_cmd.py => plugs/texnote/texnote.py} (72%) diff --git a/papers/papers b/papers/papers index 55281b8..659bbfb 100755 --- a/papers/papers +++ b/papers/papers @@ -8,6 +8,7 @@ import collections from papers.ui import UI from papers import configs from papers import commands +from papers import plugins cmds = collections.OrderedDict([ ('init', commands.init_cmd), @@ -30,11 +31,17 @@ ui = UI(config) # Extend with plugin commands plugs = configs.get_plugins(config) for plugname in plugs: - module_name = 'papers.plugins.' + plugname + '.' + plugname + '_cmd' + module_name = 'papers.plugs.' + plugname + '.' + plugname + '_cmd' plug = __import__(module_name, globals(), locals(), ['parser', 'command'], -1) cmds.update(collections.OrderedDict([(plugname, plug)])) +plugins.load_plugins(config, ui, plugs) +for p in plugins.get_plugins().values(): + cmds.update(collections.OrderedDict([(p.name, p)])) + +##### + parser = argparse.ArgumentParser(description="research papers repository") subparsers = parser.add_subparsers(title="valid commands", dest="command") diff --git a/papers/plugins.py b/papers/plugins.py new file mode 100644 index 0000000..7626ddb --- /dev/null +++ b/papers/plugins.py @@ -0,0 +1,72 @@ +import importlib + +PLUGIN_NAMESPACE = 'plugs' + +_classes = [] +_instances = {} + + +class PapersPlugin(object): + """The base class for all plugins. Plugins provide + functionality by defining a subclass of PapersPlugin and overriding + the abstract methods defined here. + """ + def __init__(self, config, ui): + """Perform one-time plugin setup. + """ + self.name = self.__module__.split('.')[-1] + self.config = config + self.ui = ui + + #config and ui and given again to stay consistent with the core papers cmd. + #two options: + #- create specific cases in script papers/papers + #- do not store self.config and self.ui and use them if needed when command is called + #this may end up a lot of function with config/ui in argument + #or just keep it this way... + def parser(self, subparsers, config): + """ Should retrun the parser with plugins specific command. + This is a basic example + """ + parser = subparsers.add_parser(self.name, help="echo string in argument") + parser.add_argument('strings', nargs='*', help='the strings') + return parser + + def command(self, config, ui, strings): + """This function will be called with argument defined in the parser above + This is a basic example + """ + for s in strings: + print s + + +def load_plugins(config, ui, names): + """Imports the modules for a sequence of plugin names. Each name + must be the name of a Python module under the "PLUGIN_NAMESPACE" namespace + package in sys.path; the module indicated should contain the + PapersPlugin subclasses desired. + """ + for name in names: + modname = '%s.%s.%s.%s' % ('papers', PLUGIN_NAMESPACE, name, name) + try: + try: + namespace = importlib.import_module(modname) + except ImportError as exc: + # Again, this is hacky: + if exc.args[0].endswith(' ' + name): + ui.warning('** plugin %s not found' % name) + else: + raise + else: + for obj in namespace.__dict__.values(): + if isinstance(obj, type) and issubclass(obj, PapersPlugin) \ + and obj != PapersPlugin: + _classes.append(obj) + _instances[obj] = obj(config, ui) + + except: + ui.warning('** error loading plugin %s' % name) + + +def get_plugins(): + return _instances diff --git a/papers/plugins/__init__.py b/papers/plugs/__init__.py similarity index 100% rename from papers/plugins/__init__.py rename to papers/plugs/__init__.py diff --git a/papers/plugins/texnote/__init__.py b/papers/plugs/texnote/__init__.py similarity index 100% rename from papers/plugins/texnote/__init__.py rename to papers/plugs/texnote/__init__.py diff --git a/papers/plugins/texnote/note_sample.tex b/papers/plugs/texnote/note_sample.tex similarity index 100% rename from papers/plugins/texnote/note_sample.tex rename to papers/plugs/texnote/note_sample.tex diff --git a/papers/plugins/texnote/texnote_cmd.py b/papers/plugs/texnote/texnote.py similarity index 72% rename from papers/plugins/texnote/texnote_cmd.py rename to papers/plugs/texnote/texnote.py index d838153..7ef9b0c 100644 --- a/papers/plugins/texnote/texnote_cmd.py +++ b/papers/plugs/texnote/texnote.py @@ -1,42 +1,33 @@ -#import ConfigParser - -#from ... import configs -#cfg = configs.read_config() - -#TEXNOTE_SECTION = 'texnote' -#DEFAULT_EDIT_CMD = cfg.get(configs.MAIN_SECTION, 'edit-cmd') - -#TODO file should not be created before the end of the process to ensure everything went ok -#TODO add subparser to have more feature -#TODO add clean command to wipe out any compilation file -#TODO add function to merge several texnote in one based on a research result - import os import shutil import subprocess from ... import repo -from ...paper import NoDocumentFile from ... import configs from ... import files +from ...plugins import PapersPlugin from ...commands.helpers import add_references_argument, parse_reference TEXNOTE_SECTION = 'texnote' TEXNOTE_SAMPLE_FILE = os.path.join(os.path.dirname(__file__), 'note_sample.tex') TEXNOTE_DIR = 'texnote' -def parser(subparsers, config): - parser = subparsers.add_parser('texnote', help="edit advance note in latex") - add_references_argument(parser, single=True) - parser.add_argument('-v', '--view', action='store_true', help='open the paper in a pdf viewer', default=None) - return parser +class TexnotePlugin(PapersPlugin): + + def parser(self, subparsers, config): + parser = subparsers.add_parser(self.name, help="edit advance note in latex") + add_references_argument(parser, single=True) + parser.add_argument('-v', '--view', action='store_true', help='open the paper in a pdf viewer', default=None) + return parser -def command(config, ui, reference, view): - if view is not None: - subprocess.Popen(['papers', 'open', reference]) - # check if citekey exist - open_texnote(config, ui, reference) + def command(self, config, ui, reference, view): + if view is not None: + subprocess.Popen(['papers', 'open', reference]) + open_texnote(config, ui, reference) + + +# temporary def callback(config, ui, name, ref): @@ -44,7 +35,7 @@ def callback(config, ui, name, ref): rp = repo.Repository.from_directory(config) paper = rp.get_paper(parse_reference(ui, rp, ref)) - if paper.metadata.has_key('texnote'): + if 'texnote' in paper.metadata: os.remove(paper.metadata['texnote']) paper.metadata.pop('texnote') metapath = rp.path_to_paper_file(paper.citekey, 'meta') @@ -55,13 +46,14 @@ def open_texnote(config, ui, ref): rp = repo.Repository.from_directory(config) paper = rp.get_paper(parse_reference(ui, rp, ref)) - if not paper.metadata.has_key('texnote'): + #ugly to recode like for the doc field + if not 'texnote' in paper.metadata: texnote_dir = os.path.join(rp.papersdir, TEXNOTE_DIR) # if folder does not exist create it, this should be relative if not os.path.exists(texnote_dir): os.mkdir(texnote_dir) texnote_path = os.path.join(texnote_dir, paper.citekey + '.tex') - paper.metadata['texnote'] = files.clean_path(texnote_path) + paper.metadata['texnote'] = files.clean_path(texnote_path) # save path in metadata metapath = rp.path_to_paper_file(paper.citekey, 'meta') files.save_meta(paper.metadata, metapath) @@ -82,7 +74,6 @@ def open_texnote(config, ui, ref): subprocess.Popen([config.get(configs.MAIN_SECTION, 'edit-cmd'), texnote_path]) - ##### ugly replace by proper ##### def format_author(author): first = author.first() @@ -97,13 +88,14 @@ def format_author(author): formatted += ' ' + last[0] return formatted + def concatenate_authors(authors): concatenated = '' for a in range(len(authors)): if len(authors) > 1 and a > 0: if a == len(authors) - 1: concatenated += 'and ' - else : + else: concatenated += ', ' concatenated += authors[a] return concatenated @@ -120,23 +112,23 @@ def autofill_texnote(texnote_path, bibentry): fields = bibentry.fields persons = bibentry.persons - if fields.has_key('title'): + if 'title' in fields: title_str = fields['title'] text = text.replace("TITLE", title_str) - if fields.has_key('year'): + if 'year' in fields: year_str = fields['year'] text = text.replace("YEAR", year_str) - if fields.has_key('abstract'): + if 'abstract' in fields: abstract_str = fields['abstract'] text = text.replace("ABSTRACT", abstract_str) - if persons.has_key('author'): + if 'author' in persons: authors = [] for author in persons['author']: authors.append(format_author(author)) - author_str = concatenate_authors(authors) + author_str = concatenate_authors(authors) text = text.replace("AUTHOR", author_str) # write file diff --git a/setup.py b/setup.py index 461cdc8..e0c3119 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup(name='papers', description='research papers manager', requires=['pybtex'], packages=find_packages(), - #package_data={'': ['*.tex']}, + package_data={'': ['*.tex']}, scripts=['papers/papers'] )