diff options
-rwxr-xr-x | check | 2 | ||||
-rw-r--r-- | lesana/collection.py | 226 | ||||
-rw-r--r-- | lesana/command.py | 267 | ||||
-rwxr-xr-x | scripts/lesana | 24 | ||||
-rwxr-xr-x | scripts/tellico2lesana | 56 | ||||
-rw-r--r-- | setup.py | 16 | ||||
-rw-r--r-- | tests/test_collection.py | 156 |
7 files changed, 372 insertions, 375 deletions
@@ -1,4 +1,4 @@ #!/bin/sh nosetests3 --with-coverage --cover-erase --cover-package=lesana -flake8 . +flake8 --select=E,F,W,C90,E123 . diff --git a/lesana/collection.py b/lesana/collection.py index ca66fcf..b265b4d 100644 --- a/lesana/collection.py +++ b/lesana/collection.py @@ -11,6 +11,7 @@ from pkg_resources import resource_string try: import git + git_available = True except ImportError: git_available = False @@ -52,21 +53,21 @@ class Entry(object): data += "# {name} ({type}): {help}\n".format(**field) t = field['type'] if field.get('default', None): - data += ("{name}: '{default}'\n".format(**field)) + data += "{name}: '{default}'\n".format(**field) elif t == 'string': - data += ("{name}: ''\n".format(**field)) + data += "{name}: ''\n".format(**field) elif t == 'text': - data += ("{name}: |\n .\n".format(**field)) + data += "{name}: |\n .\n".format(**field) elif t == 'integer': - data += ("{name}: 0\n".format(**field)) + data += "{name}: 0\n".format(**field) elif t == 'float': - data += ("{name}: 0.0\n".format(**field)) + data += "{name}: 0.0\n".format(**field) elif t == 'decimal': - data += ("{name}: 0.00\n".format(**field)) + data += "{name}: 0.00\n".format(**field) elif t == 'list': - data += ("{name}: []\n".format(**field)) + data += "{name}: []\n".format(**field) else: - data += ("{name}: \n".format(**field)) + data += "{name}: \n".format(**field) return ruamel.yaml.load(data, Loader=ruamel.yaml.RoundTripLoader) @property @@ -75,7 +76,7 @@ class Entry(object): @property def idterm(self): - return "Q"+self.eid + return "Q" + self.eid @property def short_id(self): @@ -95,43 +96,54 @@ class Entry(object): int(value) except ValueError: valid = False - errors.append({ - 'field': field['name'], - 'error': 'Invalid value for integer field: {}'.format( - value + errors.append( + { + 'field': field['name'], + 'error': + 'Invalid value for integer field: {}'.format( + value ), - }) + } + ) elif t == 'float': try: float(value) except ValueError: valid = False - errors.append({ - 'field': field['name'], - 'error': 'Invalid value for float field: {}'.format( - value + errors.append( + { + 'field': field['name'], + 'error': + 'Invalid value for float field: {}'.format( + value ), - }) + } + ) elif t == 'decimal': try: decimal.Decimal(value) except decimal.InvalidOperation: valid = False - errors.append({ - 'field': field['name'], - 'error': 'Invalid value for decimal field: {}'.format( - value + errors.append( + { + 'field': field['name'], + 'error': + 'Invalid value for decimal field: {}'.format( + value ), - }) + } + ) elif t == 'list': if not hasattr(value, '__iter__'): valid = False - errors.append({ - 'field': field['name'], - 'error': 'Invalid value for list field: {}'.format( - value + errors.append( + { + 'field': field['name'], + 'error': 'Invalid value for list field: {}'.format( + value ), - }) + } + ) return valid, errors def render(self, template, searchpath='.'): @@ -139,18 +151,19 @@ class Entry(object): try: return jtemplate.render(entry=self) except jinja2.exceptions.TemplateSyntaxError as e: - raise TemplatingError('Template Syntax Error: '+str(e)) + raise TemplatingError('Template Syntax Error: ' + str(e)) class Collection(object): """ """ + PARSER_FLAGS = ( - xapian.QueryParser.FLAG_BOOLEAN | - xapian.QueryParser.FLAG_PHRASE | - xapian.QueryParser.FLAG_LOVEHATE | - xapian.QueryParser.FLAG_WILDCARD - ) + xapian.QueryParser.FLAG_BOOLEAN + | xapian.QueryParser.FLAG_PHRASE # noqa: W503 + | xapian.QueryParser.FLAG_LOVEHATE # noqa: W503 + | xapian.QueryParser.FLAG_WILDCARD # noqa: W503 + ) def __init__(self, directory=None, itemdir='items'): self.basedir = directory or os.getcwd() @@ -158,9 +171,8 @@ class Collection(object): try: with open(os.path.join(self.basedir, 'settings.yaml')) as fp: self.settings = ruamel.yaml.load( - fp, - ruamel.yaml.RoundTripLoader - ) + fp, ruamel.yaml.RoundTripLoader + ) except FileNotFoundError: self.settings = ruamel.yaml.safe_load("{}") os.makedirs(os.path.join(self.basedir, '.lesana'), exist_ok=True) @@ -170,8 +182,8 @@ class Collection(object): except xapian.InvalidArgumentError: logging.warning( "Invalid language %s, in settings.yaml: using english.", - self.settings['lang'] - ) + self.settings['lang'], + ) self.stemmer = xapian.Stem('english') else: self.stemmer = xapian.Stem('english') @@ -192,7 +204,7 @@ class Collection(object): if not valid: logging.warning( "Not indexing {fname}: invalid data".format(fname=fname) - ) + ) return False, errors doc = xapian.Document() @@ -208,14 +220,13 @@ class Collection(object): values = [] for v in values: try: - self.indexer.index_text( - str(v), - 1, - field['prefix']) + self.indexer.index_text(str(v), 1, field['prefix']) except ValueError as e: - logging.info("Not indexing empty? value {}: {}".format( - entry.data.get(field['name']), - str(e))) + logging.info( + "Not indexing empty? value {}: {}".format( + entry.data.get(field['name']), str(e) + ) + ) # unprefixed fields, for full text search for field in self.indexed_fields: if field.get('free_search', False): @@ -244,13 +255,15 @@ class Collection(object): fields = [] for field in self.settings['fields']: if field.get('index', '') in ['free', 'field']: - prefix = field.get('prefix', 'X'+field['name'].upper()) - fields.append({ - 'prefix': prefix, - 'name': field['name'], - 'free_search': field['index'] == 'free', - 'multi': field['type'] in ['list'] - }) + prefix = field.get('prefix', 'X' + field['name'].upper()) + fields.append( + { + 'prefix': prefix, + 'name': field['name'], + 'free_search': field['index'] == 'free', + 'multi': field['type'] in ['list'], + } + ) return fields def update_cache(self, fnames=None): @@ -265,8 +278,8 @@ class Collection(object): """ cache = xapian.WritableDatabase( os.path.join(self.basedir, '.lesana/xapian'), - xapian.DB_CREATE_OR_OPEN - ) + xapian.DB_CREATE_OR_OPEN, + ) self.indexer = xapian.TermGenerator() self.indexer.set_stemmer(self.stemmer) if not fnames: @@ -275,55 +288,51 @@ class Collection(object): except FileNotFoundError: logging.warning( "No such file or directory: {}, not updating cache".format( - self.itemdir) + self.itemdir ) + ) return 0 updated = 0 for fname in fnames: try: valid, errors = self._index_file(fname, cache) except IOError as e: - logging.warning("Could not load file {}: {}".format( - fname, - str(e)) - ) + logging.warning( + "Could not load file {}: {}".format(fname, str(e)) + ) else: if valid: updated += 1 else: logging.warning( "File {fname} could not be indexed: {errors}".format( - fname=fname, - errors=errors) + fname=fname, errors=errors ) + ) return updated def save_entries(self, entries=[]): for e in entries: - complete_name = os.path.join( - self.itemdir, - e.fname - ) + complete_name = os.path.join(self.itemdir, e.fname) with open(complete_name, 'w') as fp: fp.write(e.yaml_data) def git_add_files(self, files=[]): if not git_available: logging.warning( - "python3-git not available, could not initalise " + - "the git repository.") + "python3-git not available, could not initalise " + + "the git repository." # noqa: W503 + ) return False if not self.settings.get('git', False): - logging.info( - "This collection is configured not to use git" - ) + logging.info("This collection is configured not to use git") return False try: repo = git.Repo(self.basedir, search_parent_directories=True) except git.exc.InvalidGitRepositoryError: logging.warning( - "Could not find a git repository in {}".format( - self.basedir)) + "Could not find a git repository in {}".format(self.basedir) + ) return False repo.index.add(files) return True @@ -332,13 +341,13 @@ class Collection(object): try: cache = xapian.Database( os.path.join(self.basedir, '.lesana/xapian'), - ) + ) except xapian.DatabaseOpeningError: logging.info("No database found, indexing entries.") self.update_cache() cache = xapian.Database( os.path.join(self.basedir, '.lesana/xapian'), - ) + ) return cache def start_search(self, querystring): @@ -353,9 +362,7 @@ class Collection(object): for field in self.indexed_fields: queryparser.add_prefix(field['name'], field['prefix']) - query = queryparser.parse_query( - querystring, - self.PARSER_FLAGS) + query = queryparser.parse_query(querystring, self.PARSER_FLAGS) self._enquire = xapian.Enquire(cache) self._enquire.set_query(query) @@ -395,19 +402,14 @@ class Collection(object): data = ruamel.yaml.safe_load(doc.get_data()) else: data = ruamel.yaml.load( - doc.get_data(), - ruamel.yaml.RoundTripLoader - ) - entry = self.entry_class( - self, - data=data, - fname=fname, + doc.get_data(), ruamel.yaml.RoundTripLoader ) + entry = self.entry_class(self, data=data, fname=fname,) return entry def entry_from_eid(self, eid): cache = self._get_cache() - postlist = cache.postlist('Q'+eid) + postlist = cache.postlist('Q' + eid) for pitem in postlist: return self._doc_to_entry(cache.get_document(pitem.docid)) return None @@ -421,14 +423,14 @@ class Collection(object): os.path.splitext(f)[0] for f in os.listdir(self.itemdir) if f.startswith(seid) - ] + ] return [self.entry_from_eid(u) for u in potential_eids if u] def remove_entries(self, eids): cache = xapian.WritableDatabase( os.path.join(self.basedir, '.lesana/xapian'), - xapian.DB_CREATE_OR_OPEN - ) + xapian.DB_CREATE_OR_OPEN, + ) for eid in eids: for entry in self.entries_from_short_eid(eid): if entry is not None: @@ -447,7 +449,9 @@ class Collection(object): except git.exc.InvalidGitRepositoryError: logging.warning( "Could not find a git repository in {}".format( - self.basedir)) + self.basedir + ) + ) return False repo.index.remove([f_path]) os.remove(f_path) @@ -459,19 +463,18 @@ class Collection(object): e.data[field] = value changed.append(e) self.save_entries(changed) - self.git_add_files([ - os.path.join(self.itemdir, e.fname) for e in changed - ]) + self.git_add_files( + [os.path.join(self.itemdir, e.fname) for e in changed] + ) self.update_cache([e.fname for e in changed]) def get_template(self, template_fname, searchpath='.'): env = jinja2.Environment( loader=jinja2.FileSystemLoader( - searchpath=searchpath, - followlinks=True, - ), + searchpath=searchpath, followlinks=True, + ), # TODO: add autoescaping settings - ) + ) try: template = env.get_template(template_fname) except jinja2.exceptions.TemplateNotFound as e: @@ -480,12 +483,8 @@ class Collection(object): @classmethod def init( - cls, - directory=None, - git_enabled=True, - edit_file=None, - settings={} - ): + cls, directory=None, git_enabled=True, edit_file=None, settings={} + ): """ Initialize a lesana repository @@ -504,8 +503,9 @@ class Collection(object): repo = git.Repo.init(c_dir, bare=False) else: logging.warning( - "python3-git not available, could not initalise " + - "the git repository.") + "python3-git not available, could not initalise " + + "the git repository." # noqa: W503 + ) repo = None # Add .lesana directory to .gitignore and add it to the # staging @@ -528,18 +528,16 @@ class Collection(object): # then open settings.yaml for editing filepath = os.path.join(c_dir, 'settings.yaml') if not os.path.exists(filepath): - skel = resource_string( - 'lesana', 'data/settings.yaml' - ).decode('utf-8') + skel = resource_string('lesana', 'data/settings.yaml').decode( + 'utf-8' + ) skel_dict = ruamel.yaml.load(skel, ruamel.yaml.RoundTripLoader) skel_dict['git'] = git_enabled skel_dict.update(settings) with open(filepath, 'w') as fp: ruamel.yaml.dump( - skel_dict, - stream=fp, - Dumper=ruamel.yaml.RoundTripDumper - ) + skel_dict, stream=fp, Dumper=ruamel.yaml.RoundTripDumper + ) if edit_file: edit_file(filepath) if git_enabled and repo: diff --git a/lesana/command.py b/lesana/command.py index 3c72e68..407544a 100644 --- a/lesana/command.py +++ b/lesana/command.py @@ -17,10 +17,9 @@ def edit_file_in_external_editor(filepath): if editor in str(e): logging.info( 'Could not open file {} with $EDITOR (currently {})'.format( - filepath, - editor - ) + filepath, editor ) + ) else: logging.warning("Could not open file {}".format(filepath)) return False @@ -35,8 +34,8 @@ def edit_file_in_external_editor(filepath): logging.debug( "Could not open file {} with editor: sensible-editor".format( filepath - ) ) + ) else: logging.warning("Could not open file {}".format(filepath)) return False @@ -50,7 +49,7 @@ def edit_file_in_external_editor(filepath): if 'vi' in e.strerror: logging.warning( "Could not open file {} with any known editor".format(filepath) - ) + ) return False else: logging.warning("Could not open file {}".format(filepath)) @@ -59,7 +58,7 @@ def edit_file_in_external_editor(filepath): return True -class Command(): +class Command: help = '' def __init__(self, collection_class=Collection, entry_class=Entry): @@ -73,24 +72,25 @@ class Command(): class New(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)' - )), - (['--no-git'], dict( - help="Don't add the new entry to git", - action="store_false", - dest='git' - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)'), + ), + ( + ['--no-git'], + dict( + help="Don't add the new entry to git", + action="store_false", + dest='git', + ), + ), + ] def main(self): collection = self.collection_class(self.args.collection) new_entry = self.entry_class(collection) collection.save_entries([new_entry]) - filepath = os.path.join( - collection.itemdir, - new_entry.fname - ) + filepath = os.path.join(collection.itemdir, new_entry.fname) if edit_file_in_external_editor(filepath): collection.update_cache([filepath]) if self.args.git: @@ -101,18 +101,20 @@ class New(Command): class Edit(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)' - )), - (['--no-git'], dict( - help="Don't add the new entry to git", - action="store_false", - dest='git' - )), - (['eid'], dict( - help='eid of an entry to edit', - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)'), + ), + ( + ['--no-git'], + dict( + help="Don't add the new entry to git", + action="store_false", + dest='git', + ), + ), + (['eid'], dict(help='eid of an entry to edit',)), + ] def main(self): collection = self.collection_class(self.args.collection) @@ -122,12 +124,9 @@ class Edit(Command): if not entries: return "Could not find an entry with eid starting with: {}".format( self.args.eid - ) - entry = entries[0] - filepath = os.path.join( - collection.itemdir, - entry.fname ) + entry = entries[0] + filepath = os.path.join(collection.itemdir, entry.fname) if edit_file_in_external_editor(filepath): collection.update_cache([filepath]) if self.args.git: @@ -138,16 +137,16 @@ class Edit(Command): class Show(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)' - )), - (['--template', '-t'], dict( - help='Use the specified template to display results.', - )), - (['eid'], dict( - help='eid of an entry to edit', - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)'), + ), + ( + ['--template', '-t'], + dict(help='Use the specified template to display results.',), + ), + (['eid'], dict(help='eid of an entry to edit',)), + ] def main(self): collection = self.collection_class(self.args.collection) @@ -157,7 +156,7 @@ class Show(Command): if not entries: return "Could not find an entry with eid starting with: {}".format( self.args.eid - ) + ) entry = entries[0] if self.args.template: try: @@ -171,15 +170,19 @@ class Show(Command): class Index(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)' - )), - (['files'], dict( - help='List of files to index (default: everything)', - default=None, - nargs='*', - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)'), + ), + ( + ['files'], + dict( + help='List of files to index (default: everything)', + default=None, + nargs='*', + ), + ), + ] def main(self): collection = self.collection_class(self.args.collection) @@ -193,40 +196,38 @@ class Index(Command): class Search(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)' - )), - (['--template', '-t'], dict( - help='Template to use when displaying results', - )), - (['--offset'], dict( - type=int, - )), - (['--pagesize'], dict( - type=int, - )), - (['--all'], dict( - action='store_true', - help='Return all available results' - )), - (['query'], dict( - help='Xapian query to search in the collection', - nargs='+' - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)'), + ), + ( + ['--template', '-t'], + dict(help='Template to use when displaying results',), + ), + (['--offset'], dict(type=int,)), + (['--pagesize'], dict(type=int,)), + ( + ['--all'], + dict(action='store_true', help='Return all available results'), + ), + ( + ['query'], + dict(help='Xapian query to search in the collection', nargs='+'), + ), + ] def main(self): # TODO: implement "searching" for everything if self.args.offset: logging.warning( - "offset exposes an internal knob and MAY BE" + - " REMOVED from a future release of lesana" - ) + "offset exposes an internal knob and MAY BE REMOVED " + + "from a future release of lesana" # noqa: W503 + ) if self.args.pagesize: logging.warning( - "pagesize exposes an internal knob and MAY BE" + - " REMOVED from a future release of lesana" - ) + "pagesize exposes an internal knob and MAY BE REMOVED " + + "from a future release of lesana" # noqa: W503 + ) offset = self.args.offset or 0 pagesize = self.args.pagesize or 12 collection = self.collection_class(self.args.collection) @@ -237,9 +238,7 @@ class Search(Command): if self.args.all: results = collection.get_all_search_results() else: - results = collection.get_search_results( - offset, - pagesize) + results = collection.get_search_results(offset, pagesize) if self.args.template: try: template = collection.get_template(self.args.template) @@ -249,26 +248,22 @@ class Search(Command): sys.exit(1) else: for entry in results: - print("{entry}".format( - entry=entry, - )) + print("{entry}".format(entry=entry,)) class Export(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)' - )), - (['--query', '-q'], dict( - help='Xapian query to search in the collection', - )), - (['destination'], dict( - help='The collection to export entries to' - )), - (['template'], dict( - help='Template to convert entries', - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)'), + ), + ( + ['--query', '-q'], + dict(help='Xapian query to search in the collection',), + ), + (['destination'], dict(help='The collection to export entries to')), + (['template'], dict(help='Template to convert entries',)), + ] def main(self): collection = self.collection_class(self.args.collection) @@ -298,35 +293,36 @@ class Export(Command): class Init(Command): arguments = [ - (['--collection', '-c'], dict( - help='The directory to work on (default .)', - default='.' - )), - (['--no-git'], dict( - help='Skip setting up git in this directory', - action="store_false", - dest='git' - )), - ] + ( + ['--collection', '-c'], + dict(help='The directory to work on (default .)', default='.'), + ), + ( + ['--no-git'], + dict( + help='Skip setting up git in this directory', + action="store_false", + dest='git', + ), + ), + ] def main(self): self.collection_class.init( self.args.collection, git_enabled=self.args.git, - edit_file=edit_file_in_external_editor - ) + edit_file=edit_file_in_external_editor, + ) class Remove(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)', - )), - (['entries'], dict( - help='List of entries to remove', - nargs='+', - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)',), + ), + (['entries'], dict(help='List of entries to remove', nargs='+',)), + ] def main(self): collection = self.collection_class(self.args.collection) @@ -335,25 +331,22 @@ class Remove(Command): class Update(Command): arguments = [ - (['--collection', '-c'], dict( - help='The collection to work on (default .)', - )), - (['--field', '-f'], dict( - help='The field to change', - )), - (['--value', '-t'], dict( - help='The value to set', - )), - (['query'], dict( - help='Xapian query to search in the collection', - nargs='+' - )), - ] + ( + ['--collection', '-c'], + dict(help='The collection to work on (default .)',), + ), + (['--field', '-f'], dict(help='The field to change',)), + (['--value', '-t'], dict(help='The value to set',)), + ( + ['query'], + dict(help='Xapian query to search in the collection', nargs='+'), + ), + ] def main(self): collection = self.collection_class(self.args.collection) collection.update_field( ' '.join(self.args.query), field=self.args.field, - value=self.args.value + value=self.args.value, ) diff --git a/scripts/lesana b/scripts/lesana index 4b0179b..c8e6b7f 100755 --- a/scripts/lesana +++ b/scripts/lesana @@ -8,22 +8,22 @@ import argparse import lesana.command -class Lesana(): +class Lesana: """ Manage collections """ commands = ( - ('new', lesana.command.New()), - ('edit', lesana.command.Edit()), - ('show', lesana.command.Show()), - ('index', lesana.command.Index()), - ('search', lesana.command.Search()), - ('update', lesana.command.Update()), - ('export', lesana.command.Export()), - ('init', lesana.command.Init()), - ('rm', lesana.command.Remove()), - ) + ("new", lesana.command.New()), + ("edit", lesana.command.Edit()), + ("show", lesana.command.Show()), + ("index", lesana.command.Index()), + ("search", lesana.command.Search()), + ("update", lesana.command.Update()), + ("export", lesana.command.Export()), + ("init", lesana.command.Init()), + ("rm", lesana.command.Remove()), + ) def _main(self, args): self.parser.print_help() @@ -41,5 +41,5 @@ class Lesana(): self.args.func(self.args) -if __name__ == '__main__': +if __name__ == "__main__": Lesana().main() diff --git a/scripts/tellico2lesana b/scripts/tellico2lesana index a24415e..28a1f15 100755 --- a/scripts/tellico2lesana +++ b/scripts/tellico2lesana @@ -12,34 +12,32 @@ NS = {'tellico': 'http://periapsis.org/tellico/'} # https://docs.kde.org/trunk5/en/extragear-office/tellico/field-type-values.html F_TYPE_MAP = { - '0': 'string', # not in the specs, but seen in the wild + '0': 'string', # not in the specs, but seen in the wild '1': 'string', '2': 'text', '3': 'string', '4': 'bool', '6': 'integer', '7': 'url', - '8': 'list', # single column table + '8': 'list', # single column table '10': 'file', '12': 'timestamp', # date - '14': 'integer', # rating + '14': 'integer', # rating +} - } - -class T2L(): +class T2L: """ Manage collections """ + arguments = [ - (['-c', '--collection'], dict( - help='Name of the new lesana collection', - default=None, - )), - (['file'], dict( - help='Tellico file to convert to lesana.', - )), - ] + ( + ['-c', '--collection'], + dict(help='Name of the new lesana collection', default=None,), + ), + (['file'], dict(help='Tellico file to convert to lesana.',)), + ] def _load_args(self): self.parser = argparse.ArgumentParser() @@ -57,11 +55,7 @@ class T2L(): elif 'day' in child.tag: day = child.text try: - data = datetime.date( - int(year), - int(month), - int(day) - ) + data = datetime.date(int(year), int(month), int(day)) except ValueError: data = None elif xfield.iter().__next__(): @@ -88,7 +82,7 @@ class T2L(): if xf.attrib['type'] == '12': self.date_fields.append( '{' + NS['tellico'] + '}' + xf.attrib['name'] - ) + ) f_type = F_TYPE_MAP.get(xf.attrib['type']) # TODO: support fields with the multiple values flag # (they should probably become lists) @@ -107,33 +101,25 @@ class T2L(): 'name': xf.attrib['name'] + plural, 'type': f_type, 'help': xf.attrib['title'], - } + } if l_type: field['list'] = l_type fields.append(field) # Create a collection with the settings we have loaded directory = self.args.collection or self.args.file.replace( - '.tc', - '.lesana' - ) + '.tc', '.lesana' + ) self.collection = lesana.collection.Collection.init( directory=directory, git_enabled=False, - settings={ - 'name': title, - 'fields': fields, - } - ) + settings={'name': title, 'fields': fields,}, + ) # import data for xe in xml_collection.findall('tellico:entry', NS): - data = { - 'eid': xe.attrib['id'] - } + data = {'eid': xe.attrib['id']} for xfield in xe.getchildren(): - field_name = xfield.tag.replace( - '{'+NS['tellico']+'}', - '') + field_name = xfield.tag.replace('{' + NS['tellico'] + '}', '') data[field_name] = self.read_field_data(xfield) new_entry = lesana.collection.Entry(self.collection, data=data) self.collection.save_entries([new_entry]) @@ -12,19 +12,16 @@ setup( version='0.5.1', packages=find_packages(), scripts=['scripts/lesana'], - package_data={ '': ['*.yaml'] - }, + }, test_suite='tests', - install_requires=[ # 'xapian >= 1.4', 'ruamel.yaml', 'jinja2', - ], + ], python_requires='>=3', - # Metadata author="Elena ``of Valhalla'' Grandi", author_email='valhalla@trueelena.org', @@ -39,7 +36,7 @@ setup( 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: End Users/Desktop', - 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', + 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', # noqa: E501 'Operating System :: POSIX', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.5', @@ -48,9 +45,10 @@ setup( 'Programming Language :: Python :: 3.8', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Utilities', - ], + ], project_urls={ 'Source': 'https://git.trueelena.org/cgit.cgi/software/lesana/', - 'Documentation': 'https://git.trueelena.org/cgit.cgi/software/lesana/tree/docs', - } + 'Documentation': + 'https://git.trueelena.org/cgit.cgi/software/lesana/tree/docs', + }, ) diff --git a/tests/test_collection.py b/tests/test_collection.py index 04ec410..832f421 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -26,13 +26,13 @@ class testEntries(unittest.TestCase): with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data, fname=fname) - self.assertEqual(entry.idterm, 'Q'+data['eid']) + self.assertEqual(entry.idterm, 'Q' + data['eid']) fname = '11189ee47ddf4796b718a483b379f976.yaml' eid = '11189ee47ddf4796b718a483b379f976' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data, fname=fname) - self.assertEqual(entry.idterm, 'Q'+eid) + self.assertEqual(entry.idterm, 'Q' + eid) self.assertEqual(entry.short_id, eid[:8]) def test_write_new(self): @@ -51,16 +51,12 @@ class testEntries(unittest.TestCase): def test_entry_representation(self): eid = '11189ee47ddf4796b718a483b379f976' entry = self.collection.entry_from_eid(eid) - self.assertEqual( - str(entry), - eid - ) + self.assertEqual(str(entry), eid) label = '{{ eid }}: {{ name }}' self.collection.settings['entry_label'] = label self.assertEqual( - str(entry), - '{eid}: {name}'.format(eid=eid, name='Another item') - ) + str(entry), '{eid}: {name}'.format(eid=eid, name='Another item') + ) def test_entry_creation_eid_but_no_filename(self): fname = '11189ee47ddf4796b718a483b379f976.yaml' @@ -149,9 +145,8 @@ class testSimpleCollection(unittest.TestCase): def test_loaded(self): self.assertIsNotNone(self.collection.settings) self.assertEqual( - self.collection.settings['name'], - "Simple lesana collection" - ) + self.collection.settings['name'], "Simple lesana collection" + ) self.assertEqual(len(self.collection.settings['fields']), 7) self.assertEqual(len(self.collection.indexed_fields), 3) @@ -204,28 +199,24 @@ class testSimpleCollection(unittest.TestCase): def test_entry_from_eid(self): entry = self.collection.entry_from_eid( '11189ee47ddf4796b718a483b379f976' - ) + ) self.assertEqual(entry.eid, '11189ee47ddf4796b718a483b379f976') self.collection.safe = True entry = self.collection.entry_from_eid( '11189ee47ddf4796b718a483b379f976' - ) + ) self.assertEqual(entry.eid, '11189ee47ddf4796b718a483b379f976') def test_entry_from_short_eid(self): - entries = self.collection.entries_from_short_eid( - '11189ee4' - ) + entries = self.collection.entries_from_short_eid('11189ee4') self.assertEqual(len(entries), 1) self.assertEqual(entries[0].eid, '11189ee47ddf4796b718a483b379f976') entries = self.collection.entries_from_short_eid( '11189ee47ddf4796b718a483b379f976' - ) + ) self.assertEqual(len(entries), 1) self.assertEqual(entries[0].eid, '11189ee47ddf4796b718a483b379f976') - entries = self.collection.entries_from_short_eid( - '12345678' - ) + entries = self.collection.entries_from_short_eid('12345678') self.assertEqual(len(entries), 0) def test_index_missing_file(self): @@ -241,24 +232,26 @@ class testSimpleCollection(unittest.TestCase): def test_render_collection(self): template = self.collection.get_template( 'tests/data/simple/templates/collection_template.txt' - ) + ) res = template.render(entries=self.collection.get_all_documents()) self.assertIn('11189ee4: Another item', res) def test_update(self): self.collection.update_field('Item', field="position", value="new_pos") - with open(os.path.join( - self.collection.basedir, - 'items', - '11189ee47ddf4796b718a483b379f976.yaml' - )) as fp: + with open( + os.path.join( + self.collection.basedir, + 'items', + '11189ee47ddf4796b718a483b379f976.yaml', + ) + ) as fp: self.assertIn("new_pos", fp.read()) pass self.assertEqual( self.collection.entry_from_eid( "11189ee47ddf4796b718a483b379f976" ).data['position'], - "new_pos" + "new_pos", ) self.assertIsNone( @@ -281,8 +274,8 @@ class testComplexCollection(unittest.TestCase): self.assertIsNotNone(self.collection.settings) self.assertEqual( self.collection.settings['name'], - "Fully featured lesana collection" - ) + "Fully featured lesana collection", + ) self.assertEqual(len(self.collection.settings['fields']), 9) self.assertIsNotNone(self.collection.stemmer) self.assertEqual(len(self.collection.indexed_fields), 6) @@ -302,7 +295,7 @@ class testComplexCollection(unittest.TestCase): def test_boolean_field(self): entry = self.collection.entry_from_eid( '73097121f1874a6ea2f927db7dc4f11e' - ) + ) self.assertIsInstance(entry.data['exists'], bool) def test_empty_data(self): @@ -348,8 +341,8 @@ class testCollectionWithErrors(unittest.TestCase): self.assertIsNotNone(self.collection.settings) self.assertEqual( self.collection.settings['name'], - "Lesana collection with certain errors" - ) + "Lesana collection with certain errors", + ) self.assertEqual(len(self.collection.settings['fields']), 7) self.assertIsNotNone(self.collection.stemmer) self.assertEqual(len(self.collection.indexed_fields), 3) @@ -371,15 +364,23 @@ class testCollectionCreation(unittest.TestCase): self.assertIsInstance(collection, lesana.Collection) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.lesana'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, '.gitignore'))) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml')) + ) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, '.gitignore')) + ) # and then run it twice on the same directory, nothing should break collection = lesana.Collection.init(self.tmpdir) self.assertIsInstance(collection, lesana.Collection) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.lesana'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, '.gitignore'))) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml')) + ) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, '.gitignore')) + ) created = lesana.Collection(self.tmpdir) self.assertTrue(created.settings['git']) @@ -388,36 +389,49 @@ class testCollectionCreation(unittest.TestCase): pass def test_init_edit_file(self): - collection = lesana.Collection.init(self.tmpdir, edit_file=self._do_nothing) + collection = lesana.Collection.init( + self.tmpdir, edit_file=self._do_nothing + ) self.assertIsInstance(collection, lesana.Collection) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.lesana'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, '.gitignore'))) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml')) + ) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, '.gitignore')) + ) def test_init_no_git(self): collection = lesana.Collection.init(self.tmpdir, git_enabled=False) self.assertIsInstance(collection, lesana.Collection) self.assertFalse(os.path.isdir(os.path.join(self.tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.lesana'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml'))) - self.assertFalse(os.path.isfile(os.path.join(self.tmpdir, '.gitignore'))) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml')) + ) + self.assertFalse( + os.path.isfile(os.path.join(self.tmpdir, '.gitignore')) + ) # and then run it twice on the same directory, nothing should break collection = lesana.Collection.init(self.tmpdir, git_enabled=False) self.assertIsInstance(collection, lesana.Collection) self.assertFalse(os.path.isdir(os.path.join(self.tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(self.tmpdir, '.lesana'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml'))) - self.assertFalse(os.path.isfile(os.path.join(self.tmpdir, '.gitignore'))) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml')) + ) + self.assertFalse( + os.path.isfile(os.path.join(self.tmpdir, '.gitignore')) + ) created = lesana.Collection(self.tmpdir) self.assertFalse(created.settings['git']) def test_deletion(self): shutil.copy('tests/data/simple/settings.yaml', self.tmpdir) shutil.copytree( - 'tests/data/simple/items', - os.path.join(self.tmpdir, 'items'), - ) + 'tests/data/simple/items', os.path.join(self.tmpdir, 'items'), + ) collection = lesana.Collection.init(self.tmpdir) # We start with one item indexed with the term "another" collection.start_search('another') @@ -426,11 +440,15 @@ class testCollectionCreation(unittest.TestCase): # Then delete it collection.remove_entries(['11189ee47ddf4796b718a483b379f976']) # An now we should have none - self.assertFalse(os.path.exists(os.path.join( - self.tmpdir, - 'items', - '11189ee47ddf4796b718a483b379f976.yaml' - ))) + self.assertFalse( + os.path.exists( + os.path.join( + self.tmpdir, + 'items', + '11189ee47ddf4796b718a483b379f976.yaml', + ) + ) + ) collection.start_search('another') mset = collection._enquire.get_mset(0, 10) self.assertEqual(mset.get_matches_estimated(), 0) @@ -438,9 +456,8 @@ class testCollectionCreation(unittest.TestCase): def test_partial_eid_deletion(self): shutil.copy('tests/data/simple/settings.yaml', self.tmpdir) shutil.copytree( - 'tests/data/simple/items', - os.path.join(self.tmpdir, 'items'), - ) + 'tests/data/simple/items', os.path.join(self.tmpdir, 'items'), + ) collection = lesana.Collection.init(self.tmpdir) # We start with one item indexed with the term "another" collection.start_search('another') @@ -449,11 +466,15 @@ class testCollectionCreation(unittest.TestCase): # Then delete it, using the short id collection.remove_entries(['11189ee4']) # An now we should have none - self.assertFalse(os.path.exists(os.path.join( - self.tmpdir, - 'items', - '11189ee47ddf4796b718a483b379f976.yaml' - ))) + self.assertFalse( + os.path.exists( + os.path.join( + self.tmpdir, + 'items', + '11189ee47ddf4796b718a483b379f976.yaml', + ) + ) + ) collection.start_search('another') mset = collection._enquire.get_mset(0, 10) self.assertEqual(mset.get_matches_estimated(), 0) @@ -469,9 +490,8 @@ class testCollectionCreation(unittest.TestCase): def test_git_adding(self): shutil.copy('tests/data/simple/settings.yaml', self.tmpdir) shutil.copytree( - 'tests/data/simple/items', - os.path.join(self.tmpdir, 'items'), - ) + 'tests/data/simple/items', os.path.join(self.tmpdir, 'items'), + ) collection = lesana.Collection.init(self.tmpdir) fname = '11189ee47ddf4796b718a483b379f976.yaml' repo = git.Repo(self.tmpdir) @@ -498,11 +518,13 @@ class testCollectionCreation(unittest.TestCase): 'fields': [ {'name': 'title', 'type': 'string'}, {'name': 'author', 'type': 'string'}, - ], - }, - ) + ], + }, + ) self.assertIsInstance(collection, lesana.Collection) - self.assertTrue(os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml'))) + self.assertTrue( + os.path.isfile(os.path.join(self.tmpdir, 'settings.yaml')) + ) self.assertEqual(collection.settings['name'], 'A different name') self.assertEqual(len(collection.settings['fields']), 2) |