From 1e42ddaf08e180013e439b4ac9a69c3d8414b96c Mon Sep 17 00:00:00 2001 From: mfrasca Date: Tue, 10 Oct 2017 07:33:43 -0500 Subject: [PATCH 01/10] files altered while the JBQ was offering board and lodging. --- bauble/__init__.py | 3 ++- bauble/connmgr.py | 3 ++- bauble/db.py | 3 ++- bauble/editor.py | 3 ++- bauble/i18n.py | 3 ++- bauble/pluginmgr.py | 1 + bauble/plugins/abcd/__init__.py | 1 + bauble/plugins/garden/__init__.py | 1 + bauble/plugins/garden/accession.py | 1 + bauble/plugins/garden/aggregateclient.py | 1 + bauble/plugins/garden/exporttopocket.py | 1 + bauble/plugins/garden/institution.py | 1 + bauble/plugins/garden/plant.py | 1 + bauble/plugins/garden/source.py | 1 + bauble/plugins/garden/test.py | 1 + bauble/plugins/imex/csv_.py | 1 + bauble/plugins/plants/family.py | 1 + bauble/plugins/plants/genus.py | 1 + bauble/plugins/plants/species.py | 1 + bauble/plugins/plants/species_model.py | 1 + bauble/plugins/plants/test.py | 1 + bauble/plugins/report/__init__.py | 1 + bauble/plugins/report/mako/__init__.py | 1 + bauble/plugins/report/mako/test.py | 1 + bauble/plugins/report/test.py | 1 + bauble/plugins/users/__init__.py | 1 + bauble/search.py | 1 + bauble/test/__init__.py | 1 + bauble/test/test_pluginmgr.py | 1 + bauble/utils/__init__.py | 1 + bauble/utils/test.py | 1 + bauble/version.py | 1 + scripts/importgenera.py | 1 + scripts/importodk.py | 1 + scripts/importpictures.py | 1 + scripts/importpocketlog.py | 1 + scripts/lab-csv2json.py | 1 + 37 files changed, 42 insertions(+), 5 deletions(-) diff --git a/bauble/__init__.py b/bauble/__init__.py index 27d073896..97eaf094e 100755 --- a/bauble/__init__.py +++ b/bauble/__init__.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams -# Copyright (c) 2012-2016 Mario Frasca +# Copyright (c) 2012-2017 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/connmgr.py b/bauble/connmgr.py index c8f7e0acd..8479b9b30 100755 --- a/bauble/connmgr.py +++ b/bauble/connmgr.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # # Copyright 2008-2010 Brett Adams -# Copyright 2015-2016 Mario Frasca . +# Copyright 2015-2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/db.py b/bauble/db.py index defe1cea6..b86404d4d 100644 --- a/bauble/db.py +++ b/bauble/db.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # # Copyright 2005-2010 Brett Adams -# Copyright 2015 Mario Frasca . +# Copyright 2015-2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/editor.py b/bauble/editor.py index 581456a0f..93bf664a0 100755 --- a/bauble/editor.py +++ b/bauble/editor.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # # Copyright 2008-2010 Brett Adams -# Copyright 2015 Mario Frasca . +# Copyright 2015-2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/i18n.py b/bauble/i18n.py index 0b2d588fd..f50637171 100755 --- a/bauble/i18n.py +++ b/bauble/i18n.py @@ -3,7 +3,8 @@ # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2006 Mark Mruss http://www.learningpython.com # Copyright (c) 2007 Kopfgeldjaeger -# Copyright (c) 2012-2015 Mario Frasca +# Copyright (c) 2012-2017 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/pluginmgr.py b/bauble/pluginmgr.py index 7a78aad36..06e52b379 100755 --- a/bauble/pluginmgr.py +++ b/bauble/pluginmgr.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2012-2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/abcd/__init__.py b/bauble/plugins/abcd/__init__.py index 443cdadbd..6a382aa2a 100755 --- a/bauble/plugins/abcd/__init__.py +++ b/bauble/plugins/abcd/__init__.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2012-2016 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/__init__.py b/bauble/plugins/garden/__init__.py index 4135889ae..b2620ebbd 100755 --- a/bauble/plugins/garden/__init__.py +++ b/bauble/plugins/garden/__init__.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/accession.py b/bauble/plugins/garden/accession.py index 36a554b8f..7ce1ee79f 100755 --- a/bauble/plugins/garden/accession.py +++ b/bauble/plugins/garden/accession.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015-2016 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/aggregateclient.py b/bauble/plugins/garden/aggregateclient.py index 8c02a635f..d5282b5e3 100644 --- a/bauble/plugins/garden/aggregateclient.py +++ b/bauble/plugins/garden/aggregateclient.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # Copyright 2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/exporttopocket.py b/bauble/plugins/garden/exporttopocket.py index de39a7e3b..389b60f14 100644 --- a/bauble/plugins/garden/exporttopocket.py +++ b/bauble/plugins/garden/exporttopocket.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # Copyright 2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/institution.py b/bauble/plugins/garden/institution.py index 9e59f88e0..0b175457e 100755 --- a/bauble/plugins/garden/institution.py +++ b/bauble/plugins/garden/institution.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/plant.py b/bauble/plugins/garden/plant.py index a724f9e09..554db935f 100755 --- a/bauble/plugins/garden/plant.py +++ b/bauble/plugins/garden/plant.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015-2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/source.py b/bauble/plugins/garden/source.py index d5997f78b..0ea978e32 100755 --- a/bauble/plugins/garden/source.py +++ b/bauble/plugins/garden/source.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015-2016 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/garden/test.py b/bauble/plugins/garden/test.py index d5cfcb16b..c8f4a8698 100644 --- a/bauble/plugins/garden/test.py +++ b/bauble/plugins/garden/test.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015,2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/imex/csv_.py b/bauble/plugins/imex/csv_.py index 7b6e66756..ac9e28c3c 100755 --- a/bauble/plugins/imex/csv_.py +++ b/bauble/plugins/imex/csv_.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2012-2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/plants/family.py b/bauble/plugins/plants/family.py index d96d61eab..a35e170e0 100755 --- a/bauble/plugins/plants/family.py +++ b/bauble/plugins/plants/family.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2014-2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/plants/genus.py b/bauble/plugins/plants/genus.py index 4f737332a..35bcca555 100755 --- a/bauble/plugins/plants/genus.py +++ b/bauble/plugins/plants/genus.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/plants/species.py b/bauble/plugins/plants/species.py index 35232a452..27b64872a 100755 --- a/bauble/plugins/plants/species.py +++ b/bauble/plugins/plants/species.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2012-2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/plants/species_model.py b/bauble/plugins/plants/species_model.py index 25cfa84df..7024a5d40 100755 --- a/bauble/plugins/plants/species_model.py +++ b/bauble/plugins/plants/species_model.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2012-2016 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/plants/test.py b/bauble/plugins/plants/test.py index 4285e47f5..0676a088f 100644 --- a/bauble/plugins/plants/test.py +++ b/bauble/plugins/plants/test.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/report/__init__.py b/bauble/plugins/report/__init__.py index dce56ed32..85d57c0c5 100755 --- a/bauble/plugins/report/__init__.py +++ b/bauble/plugins/report/__init__.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2012-2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # Copyright 2017 Ross Demuth # # This file is part of ghini.desktop. diff --git a/bauble/plugins/report/mako/__init__.py b/bauble/plugins/report/mako/__init__.py index ff481a3e7..71018c474 100644 --- a/bauble/plugins/report/mako/__init__.py +++ b/bauble/plugins/report/mako/__init__.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2012-2016 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/report/mako/test.py b/bauble/plugins/report/mako/test.py index 91f557584..a576bfc13 100644 --- a/bauble/plugins/report/mako/test.py +++ b/bauble/plugins/report/mako/test.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2012-2015 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/plugins/report/test.py b/bauble/plugins/report/test.py index 710bcc1c3..1c479a8cb 100644 --- a/bauble/plugins/report/test.py +++ b/bauble/plugins/report/test.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2012-2017 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # Copyright (c) 2017 Ross Demuth # # This file is part of ghini.desktop. diff --git a/bauble/plugins/users/__init__.py b/bauble/plugins/users/__init__.py index 79d6d46de..be9119406 100644 --- a/bauble/plugins/users/__init__.py +++ b/bauble/plugins/users/__init__.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2012-2017 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/search.py b/bauble/search.py index 6d62bc00c..dca0c3dba 100644 --- a/bauble/search.py +++ b/bauble/search.py @@ -2,6 +2,7 @@ # # Copyright 2008, 2009, 2010 Brett Adams # Copyright 2014-2015 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/test/__init__.py b/bauble/test/__init__.py index 663dee52d..fa10d3646 100644 --- a/bauble/test/__init__.py +++ b/bauble/test/__init__.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2012-2015 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/test/test_pluginmgr.py b/bauble/test/test_pluginmgr.py index a3b3bed08..ff0427a60 100644 --- a/bauble/test/test_pluginmgr.py +++ b/bauble/test/test_pluginmgr.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2012-2015 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/utils/__init__.py b/bauble/utils/__init__.py index 6a1f6cc5b..5290eaed3 100755 --- a/bauble/utils/__init__.py +++ b/bauble/utils/__init__.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2015-2016 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/utils/test.py b/bauble/utils/test.py index 6220c449f..14f62003f 100644 --- a/bauble/utils/test.py +++ b/bauble/utils/test.py @@ -2,6 +2,7 @@ # # Copyright (c) 2005,2006,2007,2008,2009 Brett Adams # Copyright (c) 2012-2015 Mario Frasca +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/bauble/version.py b/bauble/version.py index b124822ee..3f62c0e36 100644 --- a/bauble/version.py +++ b/bauble/version.py @@ -2,6 +2,7 @@ # # Copyright 2008-2010 Brett Adams # Copyright 2014-2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/scripts/importgenera.py b/scripts/importgenera.py index 07a83ba87..d2450d54a 100755 --- a/scripts/importgenera.py +++ b/scripts/importgenera.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # Copyright 2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/scripts/importodk.py b/scripts/importodk.py index 7edc0cf0b..e0815c936 100644 --- a/scripts/importodk.py +++ b/scripts/importodk.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # Copyright 2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/scripts/importpictures.py b/scripts/importpictures.py index 6ae4febf7..5dadd6879 100755 --- a/scripts/importpictures.py +++ b/scripts/importpictures.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # Copyright 2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/scripts/importpocketlog.py b/scripts/importpocketlog.py index 0234a621b..5ea84604d 100755 --- a/scripts/importpocketlog.py +++ b/scripts/importpocketlog.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # Copyright 2016,2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # diff --git a/scripts/lab-csv2json.py b/scripts/lab-csv2json.py index 899a89c8b..05543ef82 100755 --- a/scripts/lab-csv2json.py +++ b/scripts/lab-csv2json.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # Copyright 2016,2017 Mario Frasca . +# Copyright 2017 Jardín Botánico de Quito # # This file is part of ghini.desktop. # From d2cb72e1e67da6ed6923fdba1dd45b36e9cbe3d3 Mon Sep 17 00:00:00 2001 From: mfrasca Date: Tue, 10 Oct 2017 12:56:26 -0500 Subject: [PATCH 02/10] honour options --- .../mako/templates/accession-label-qr.ps | Bin 604591 -> 605620 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bauble/plugins/report/mako/templates/accession-label-qr.ps b/bauble/plugins/report/mako/templates/accession-label-qr.ps index 4e4a1d47477bfdac11eae4e507f7ce32c04262d5..b2f827441065252e257735c73f8c690a6fa77caa 100644 GIT binary patch delta 1321 zcmZuxJ#Q015LF<2+%<>>MIwknw%I$yIoSzr9HpQ}qM{3jv$iMp!ujrUyCy*hxuBp6 z1;zagD3J0uXla1IfGBC0**!aniKUhIX6LgZ z@qD_~YV}1Egb3fC)IOZlR%l(Jb(PjCt!uQd)4DvaKNb0rcikxY9b76 z9u;+|vj@8syQ{?2hH9h?n@upS7(&>zPZs1TF6eS(8z35uR%196(5P6Pd_@9?Po*YU zaxk-I`CP<~7t`qk3&|}a$X=kR^Z_R{=WS?!YQobj#gHSQh!+Z(j>xXdyQB`6Nu;d; z8_*789}|sTf5tZcE7^oRTHHm%og`3@yB&2*v<1j?2qF@6P{m0K4Z;Pe6Bv-(JY<#g zLKuwD^k|OK^2N5dHj90~2K)0<(z*{yQw30lTG3Asj+7aLndY>`1Sgo%1tsbg0+X{q z8ms=xut_{eV=S;sZIK0n#=|KkE16iq?w+K9){aGS88d#2z*>wA?JyBcv9D>R0nFadg_bo52+kMZeIm4XuP0mhVZ+mxFX2|ofm<2pGh3pyn6EVLK zXm}cFbH>8$MiW^Bn!6E*w<5HrD2(Z_3ceGen`E>jydZFcNOz7yg9d39(KI?Glu9K j2MW(?UbKmtVb7w9R8+ligY}@YdQg+OfUd^S0CawFfx6Z7L<>%d?Y}KKcQOM2 Dr%PrC From 0063fcea6cdb80829b8492b06fa0df3ada2c6760 Mon Sep 17 00:00:00 2001 From: mfrasca Date: Wed, 11 Oct 2017 20:28:39 -0500 Subject: [PATCH 03/10] adding filter-matching, close #263 --- bauble/search.py | 91 ++++++++++++++++++++++++++++++++------ bauble/test/test_search.py | 64 ++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 15 deletions(-) diff --git a/bauble/search.py b/bauble/search.py index dca0c3dba..ece28663f 100644 --- a/bauble/search.py +++ b/bauble/search.py @@ -167,13 +167,14 @@ def __repr__(self): return "%s" % (self.value) -class IdentifierToken(object): +class IdentifierAction(object): def __init__(self, t): - logger.debug('IdentifierToken::__init__(%s)' % t) - self.value = t[0] + logger.debug('IdentifierAction::__init__(%s)' % t) + self.steps = t[0][:-2:2] + self.leaf = t[0][-1] def __repr__(self): - return '.'.join(self.value) + return '.'.join(self.steps + [self.leaf]) def evaluate(self, env): """return pair (query, attribute) @@ -182,22 +183,79 @@ def evaluate(self, env): joinpoint is the one relative to the attribute, and the attribute itself. """ + query = env.session.query(env.domain) + if len(self.steps) == 0: + # identifier is an attribute of the table being queried + cls = env.domain + else: + # identifier is an attribute of a joined table + query = query.join(*self.steps, aliased=True) + cls = query._joinpoint['_joinpoint_entity'] + attr = getattr(cls, self.leaf) + logger.debug('IdentifierToken for %s, %s evaluates to %s' + % (cls, self.leaf, attr)) + return (query, attr) + + def needs_join(self, env): + return self.steps + +class FilteredIdentifierAction(object): + def __init__(self, t): + logger.debug('FilteredIdentifierAction::__init__(%s)' % t) + self.steps = t[0][:-7:2] + self.filter_attr = t[0][-6] + self.filter_op = t[0][-5] + self.filter_value = t[0][-4] + self.leaf = t[0][-1] + + # cfr: SearchParser.binop + # = == != <> < <= > >= not like contains has ilike icontains ihas is + self.operation = { + '=': lambda x, y: x == y, + '==': lambda x, y: x == y, + 'is': lambda x, y: x == y, + '!=': lambda x, y: x != y, + '<>': lambda x, y: x != y, + 'not': lambda x, y: x != y, + '<': lambda x, y: x < y, + '<=': lambda x, y: x <= y, + '>': lambda x, y: x > y, + '>=': lambda x, y: x >= y, + 'like': lambda x, y: utils.ilike(x, '%s' % y), + 'contains': lambda x, y: utils.ilike(x, '%%%s%%' % y), + 'has': lambda x, y: utils.ilike(x, '%%%s%%' % y), + 'ilike': lambda x, y: utils.ilike(x, '%s' % y), + 'icontains': lambda x, y: utils.ilike(x, '%%%s%%' % y), + 'ihas': lambda x, y: utils.ilike(x, '%%%s%%' % y), + }.get(self.filter_op) + + def __repr__(self): + return "%s[%s%s%s].%s" % ('.'.join(self.steps), + self.filter_attr, self.filter_op, self.filter_value, + self.leaf) + + def evaluate(self, env): + """return pair (query, attribute)""" query = env.session.query(env.domain) - if len(self.value) == 1: + if len(self.steps) == 0: # identifier is an attribute of the table being queried cls = env.domain - elif len(self.value) > 1: + else: # identifier is an attribute of a joined table - query = query.join(*self.value[:-1], aliased=True) + query = query.join(*self.steps, aliased=True) cls = query._joinpoint['_joinpoint_entity'] - attr = getattr(cls, self.value[-1]) + attr = getattr(cls, self.filter_attr) + clause = lambda x: self.operation(attr, x) + logger.debug('filtering on %s(%s)' % (type(attr), attr)) + query = query.filter(clause(self.filter_value.express())) + attr = getattr(cls, self.leaf) logger.debug('IdentifierToken for %s, %s evaluates to %s' - % (cls, self.value[-1], attr)) - return query, attr + % (cls, self.leaf, attr)) + return (query, attr) def needs_join(self, env): - return self.value[:-1] + return self.steps class IdentExpression(object): @@ -611,7 +669,7 @@ def replace(i): from pyparsing import ( Word, alphas8bit, removeQuotes, delimitedList, Regex, - OneOrMore, oneOf, alphas, alphanums, Group, Literal, + ZeroOrMore, OneOrMore, oneOf, alphas, alphanums, Group, Literal, CaselessLiteral, WordStart, WordEnd, srange, stringEnd, Keyword, quotedString, infixNotation, opAssoc, Forward) @@ -678,8 +736,13 @@ class SearchParser(object): | Literal('count')) query_expression = Forward()('filter') - identifier = Group(delimitedList(Word(alphas+'_', alphanums+'_'), - '.')).setParseAction(IdentifierToken) + + atomic_identifier = Word(alphas+'_', alphanums+'_') + identifier = ( + Group(atomic_identifier + ZeroOrMore('.' + atomic_identifier) + '[' + atomic_identifier + binop + value + ']' + '.' + atomic_identifier).setParseAction(FilteredIdentifierAction) + | Group(atomic_identifier + ZeroOrMore('.' + atomic_identifier)).setParseAction(IdentifierAction) + ) + aggregated = (aggregating_func + Literal('(') + identifier + Literal(')') ).setParseAction(AggregatingAction) ident_expression = (Group(identifier + binop + value diff --git a/bauble/test/test_search.py b/bauble/test/test_search.py index 533966550..40a22e48d 100644 --- a/bauble/test/test_search.py +++ b/bauble/test/test_search.py @@ -1067,13 +1067,75 @@ def test_notes_is_not_not_es(self): self.assertEqual(str(results.statement), "SELECT * FROM species WHERE (notes.id != 0.0)") - def test_between_just_parse(self): + def test_between_just_parse_0(self): 'use BETWEEN value and value' sp = self.SearchParser() results = sp.parse_string('species where id between 0 and 1') self.assertEqual(str(results.statement), "SELECT * FROM species WHERE (BETWEEN id 0.0 1.0)") + def test_between_just_parse_1(self): + 'use BETWEEN value and value' + sp = self.SearchParser() + results = sp.parse_string('species where step.id between 0 and 1') + self.assertEqual(str(results.statement), + "SELECT * FROM species WHERE (BETWEEN step.id 0.0 1.0)") + + def test_between_just_parse_2(self): + 'use BETWEEN value and value' + sp = self.SearchParser() + results = sp.parse_string('species where step.step.step.step[a=1].id between 0 and 1') + self.assertEqual(str(results.statement), + "SELECT * FROM species WHERE (BETWEEN step.step.step.step[a=1.0].id 0.0 1.0)") + + +class FilterThenMatchTests(BaubleTestCase): + def __init__(self, *args): + super(FilterThenMatchTests, self).__init__(*args) + prefs.testing = True + + def setUp(self): + super(FilterThenMatchTests, self).setUp() + db.engine.execute('delete from genus') + db.engine.execute('delete from family') + db.engine.execute('delete from genus_note') + from bauble.plugins.plants.family import Family + from bauble.plugins.plants.genus import Genus, GenusNote + self.family = Family(family=u'family1', qualifier=u's. lat.') + self.genus1 = Genus(family=self.family, genus=u'genus1') + self.genus2 = Genus(family=self.family, genus=u'genus2') + self.genus3 = Genus(family=self.family, genus=u'genus3') + n1 = GenusNote(category=u'commentarii', note=u'olim', genus=self.genus1) + n2 = GenusNote(category=u'commentarii', note=u'erat', genus=self.genus1) + n3 = GenusNote(category=u'commentarii', note=u'verbum', genus=self.genus2) + n4 = GenusNote(category=u'test', note=u'olim', genus=self.genus3) + n5 = GenusNote(category=u'test', note=u'verbum', genus=self.genus3) + self.session.add_all([self.family, self.genus1, self.genus2, self.genus3, n1, n2, n3, n4, n5]) + self.session.commit() + + def tearDown(self): + super(FilterThenMatchTests, self).tearDown() + + def test_can_filter_match_notes(self): + mapper_search = search.get_strategy('MapperSearch') + self.assertTrue(isinstance(mapper_search, search.MapperSearch)) + + s = "genus where notes.note='olim'" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus1, self.genus3])) + + s = "genus where notes[category='test'].note='olim'" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus3])) + + s = "genus where notes.category='commentarii'" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus1, self.genus2])) + + s = "genus where notes[note='verbum'].category='commentarii'" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus2])) + class ParseTypedValue(BaubleTestCase): def test_parse_typed_value_floats(self): From 9da4485467284c38ba9a3ba71f62e364dfa3f2f6 Mon Sep 17 00:00:00 2001 From: mfrasca Date: Wed, 11 Oct 2017 23:15:49 -0500 Subject: [PATCH 04/10] removed dead code, testing set operations. --- bauble/search.py | 14 +++----------- bauble/test/test_search.py | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/bauble/search.py b/bauble/search.py index ece28663f..8ba4846b5 100644 --- a/bauble/search.py +++ b/bauble/search.py @@ -238,13 +238,9 @@ def __repr__(self): def evaluate(self, env): """return pair (query, attribute)""" query = env.session.query(env.domain) - if len(self.steps) == 0: - # identifier is an attribute of the table being queried - cls = env.domain - else: - # identifier is an attribute of a joined table - query = query.join(*self.steps, aliased=True) - cls = query._joinpoint['_joinpoint_entity'] + # identifier is an attribute of a joined table + query = query.join(*self.steps, aliased=True) + cls = query._joinpoint['_joinpoint_entity'] attr = getattr(cls, self.filter_attr) clause = lambda x: self.operation(attr, x) logger.debug('filtering on %s(%s)' % (type(attr), attr)) @@ -263,10 +259,6 @@ def __init__(self, t): logger.debug('IdentExpression::__init__(%s)' % t) self.op = t[0][1] - def not_implemented_yet(x, y): - # raise an exception - raise NotImplementedError - # cfr: SearchParser.binop # = == != <> < <= > >= not like contains has ilike icontains ihas is self.operation = { diff --git a/bauble/test/test_search.py b/bauble/test/test_search.py index 40a22e48d..96180624a 100644 --- a/bauble/test/test_search.py +++ b/bauble/test/test_search.py @@ -1105,12 +1105,13 @@ def setUp(self): self.genus1 = Genus(family=self.family, genus=u'genus1') self.genus2 = Genus(family=self.family, genus=u'genus2') self.genus3 = Genus(family=self.family, genus=u'genus3') + self.genus4 = Genus(family=self.family, genus=u'genus4') n1 = GenusNote(category=u'commentarii', note=u'olim', genus=self.genus1) n2 = GenusNote(category=u'commentarii', note=u'erat', genus=self.genus1) n3 = GenusNote(category=u'commentarii', note=u'verbum', genus=self.genus2) n4 = GenusNote(category=u'test', note=u'olim', genus=self.genus3) n5 = GenusNote(category=u'test', note=u'verbum', genus=self.genus3) - self.session.add_all([self.family, self.genus1, self.genus2, self.genus3, n1, n2, n3, n4, n5]) + self.session.add_all([self.family, self.genus1, self.genus2, self.genus3, self.genus4, n1, n2, n3, n4, n5]) self.session.commit() def tearDown(self): @@ -1136,6 +1137,26 @@ def test_can_filter_match_notes(self): results = mapper_search.search(s, self.session) self.assertEqual(results, set([self.genus2])) + def test_can_find_empty_set(self): + mapper_search = search.get_strategy('MapperSearch') + self.assertTrue(isinstance(mapper_search, search.MapperSearch)) + + s = "genus where notes=Empty" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus4])) + + def test_can_match_list_of_values(self): + mapper_search = search.get_strategy('MapperSearch') + self.assertTrue(isinstance(mapper_search, search.MapperSearch)) + + s = "genus where notes.note in 'olim', 'erat', 'verbum'" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus1, self.genus2, self.genus3])) + + s = "genus where notes[category='test'].note in 'olim', 'erat', 'verbum'" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus3])) + class ParseTypedValue(BaubleTestCase): def test_parse_typed_value_floats(self): From 477da6c6d6ba5ddbc75f9380518dec496aee992e Mon Sep 17 00:00:00 2001 From: mfrasca Date: Thu, 12 Oct 2017 02:53:18 -0500 Subject: [PATCH 05/10] null edit, just consistency in use of names --- bauble/search.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bauble/search.py b/bauble/search.py index 8ba4846b5..7d7cbcbd3 100644 --- a/bauble/search.py +++ b/bauble/search.py @@ -413,16 +413,16 @@ def evaluate(self, env): class ParenthesisedQuery(object): def __init__(self, t): - self.query = t[1] + self.content = t[1] def __repr__(self): - return "(%s)" % self.query.__repr__() + return "(%s)" % self.content.__repr__() def evaluate(self, env): - return self.query.evaluate(env) + return self.content.evaluate(env) def needs_join(self, env): - return self.query.needs_join(env) + return self.content.needs_join(env) class QueryAction(object): From 2e899342f652ed076113801340bcf872b0dbd538 Mon Sep 17 00:00:00 2001 From: mfrasca Date: Thu, 12 Oct 2017 02:53:36 -0500 Subject: [PATCH 06/10] describing a couple of untested lines --- bauble/test/test_search.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/bauble/test/test_search.py b/bauble/test/test_search.py index 96180624a..c254998cf 100644 --- a/bauble/test/test_search.py +++ b/bauble/test/test_search.py @@ -342,6 +342,14 @@ def test_search_by_expression_genus_eq_nomatch(self): results = mapper_search.search('genus=g', self.session) self.assertEquals(len(results), 0) + def test_search_by_expression_genus_eq_everything(self): + mapper_search = search.get_strategy('MapperSearch') + self.assertTrue(isinstance(mapper_search, search.MapperSearch)) + + # search for genus by domain + results = mapper_search.search('genus=*', self.session) + self.assertEquals(len(results), 1) + def test_search_by_expression_genus_like_nomatch(self): mapper_search = search.get_strategy('MapperSearch') self.assertTrue(isinstance(mapper_search, search.MapperSearch)) @@ -1145,6 +1153,14 @@ def test_can_find_empty_set(self): results = mapper_search.search(s, self.session) self.assertEqual(results, set([self.genus4])) + def test_can_find_non_empty_set(self): + mapper_search = search.get_strategy('MapperSearch') + self.assertTrue(isinstance(mapper_search, search.MapperSearch)) + + s = "genus where notes!=Empty" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set([self.genus1, self.genus2, self.genus3])) + def test_can_match_list_of_values(self): mapper_search = search.get_strategy('MapperSearch') self.assertTrue(isinstance(mapper_search, search.MapperSearch)) @@ -1157,6 +1173,14 @@ def test_can_match_list_of_values(self): results = mapper_search.search(s, self.session) self.assertEqual(results, set([self.genus3])) + def test_parenthesised_search(self): + mapper_search = search.get_strategy('MapperSearch') + self.assertTrue(isinstance(mapper_search, search.MapperSearch)) + + s = "genus where (notes!=Empty) and (notes=Empty)" + results = mapper_search.search(s, self.session) + self.assertEqual(results, set()) + class ParseTypedValue(BaubleTestCase): def test_parse_typed_value_floats(self): From 6e97d66cee81119bf4ac3e649f24944898429a30 Mon Sep 17 00:00:00 2001 From: mfrasca Date: Thu, 12 Oct 2017 11:10:15 -0500 Subject: [PATCH 07/10] close #290 --- bauble/plugins/abcd/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bauble/plugins/abcd/__init__.py b/bauble/plugins/abcd/__init__.py index 6a382aa2a..9f2ce8035 100755 --- a/bauble/plugins/abcd/__init__.py +++ b/bauble/plugins/abcd/__init__.py @@ -340,7 +340,8 @@ def start(self, filename=None, plants=None): if d.run() == gtk.RESPONSE_ACCEPT: filename = d.get_filename() d.destroy() - return filename + if not filename: + return if plants: nplants = len(plants) From a96b337a18d0049274392d7053239029dc9fe723 Mon Sep 17 00:00:00 2001 From: mfrasca Date: Thu, 12 Oct 2017 18:16:58 -0500 Subject: [PATCH 08/10] add progressbar and set gui busy during export. close #240 --- bauble/__init__.py | 10 +++++++++ bauble/plugins/garden/exporttopocket.py | 28 +++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/bauble/__init__.py b/bauble/__init__.py index 97eaf094e..50564f3a3 100755 --- a/bauble/__init__.py +++ b/bauble/__init__.py @@ -48,6 +48,16 @@ def pb_set_fraction(fraction): if gui is not None and gui.progressbar is not None: gui.progressbar.set_fraction(fraction) +def pb_grab(): + if gui is not None and gui.progressbar is not None: + gui.set_busy(True) + gui.progressbar.show() + gui.progressbar.set_fraction(0) + +def pb_release(): + if gui is not None and gui.progressbar is not None: + gui.progressbar.hide() + gui.set_busy(False) def main_is_frozen(): """ diff --git a/bauble/plugins/garden/exporttopocket.py b/bauble/plugins/garden/exporttopocket.py index 389b60f14..9186d04a7 100644 --- a/bauble/plugins/garden/exporttopocket.py +++ b/bauble/plugins/garden/exporttopocket.py @@ -29,7 +29,7 @@ from bauble import pluginmgr -import gtk +import gtk, gobject import os @@ -81,6 +81,8 @@ def create_pocket(filename): def export_to_pocket(filename, include_private=True): from bauble.plugins.plants import Species + from bauble import pb_set_fraction, pb_grab, pb_release + gobject.idle_add(pb_grab) session = db.Session() plant_query = (session.query(Plant) .order_by(Plant.code) @@ -99,6 +101,7 @@ def export_to_pocket(filename, include_private=True): import sqlite3 cn = sqlite3.connect(filename) cr = cn.cursor() + count = 1 for i in species: try: cr.execute('INSERT INTO "species" ' @@ -109,6 +112,9 @@ def export_to_pocket(filename, include_private=True): i.infraspecific_author or i.sp_author or '')) except Exception, e: logger.info("error exporting species %s: %s %s" % (i.id, type(e), e)) + gobject.idle_add(pb_set_fraction, 0.05 * count / len(species)) + count += 1 + count = 1 for i in accessions: try: try: @@ -121,6 +127,9 @@ def export_to_pocket(filename, include_private=True): (i.id, i.code, i.species_id, source_name, i.date_accd)) except Exception, e: logger.info("error exporting accession %s: %s %s" % (i.id, type(e), e)) + gobject.idle_add(pb_set_fraction, 0.05 + 0.4 * count / len(accessions)) + count += 1 + count = 1 for i in plants: try: cr.execute('INSERT INTO "plant" ' @@ -129,8 +138,11 @@ def export_to_pocket(filename, include_private=True): (i.id, i.accession_id, "." + i.code, i.location.code, i.date_of_death, len(i.pictures))) except Exception, e: logger.info("error exporting plant %s: %s %s" % (i.id, type(e), e)) + gobject.idle_add(pb_set_fraction, 0.45 + 0.55 * count / len(plants)) + count += 1 cn.commit() session.close() + gobject.idle_add(pb_release) return True @@ -146,8 +158,16 @@ def start(self): gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)) if d.run() == gtk.RESPONSE_ACCEPT: pocket = d.get_filename() - if os.path.isfile(pocket): + try: os.unlink(pocket) - create_pocket(pocket) - export_to_pocket(pocket) + except: + pass + else: + pocket = None d.destroy() + if pocket: + create_pocket(pocket) + from threading import Thread + thread = Thread(target=export_to_pocket, + args=[pocket]) + thread.start() From 95c5df6c16c7a4bc39d316e6cde87e8604c24850 Mon Sep 17 00:00:00 2001 From: Mario Frasca Date: Thu, 12 Oct 2017 20:39:08 -0500 Subject: [PATCH 09/10] Create issue_template.md --- .github/issue_template.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/issue_template.md diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 000000000..75da4fa53 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,13 @@ +### Expected behaviour + +### Actual behaviour + +### Steps to reproduce the behaviour + +##### How to set up the same initial situation + +##### Which actions to take in sequence, which contribute to create the critical situation + +##### Last step, with the unexpected result + +##### Opinions and suggestions From 721107c982c075132d57d211afa173963ea6c9b5 Mon Sep 17 00:00:00 2001 From: mfrasca Date: Thu, 12 Oct 2017 21:16:19 -0500 Subject: [PATCH 10/10] bumping to 1.0.75 --- bauble/version.py | 2 +- data/ghini.desktop | 2 +- doc/conf.py | 2 +- packages/builddeb.sh | 2 +- scripts/build.nsi | 2 +- scripts/installer.cfg | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bauble/version.py b/bauble/version.py index 3f62c0e36..a321c6fd1 100644 --- a/bauble/version.py +++ b/bauble/version.py @@ -22,4 +22,4 @@ # The Ghini version. # major, minor, revision version tuple -version = "1.0.74" # :bump +version = "1.0.75" # :bump diff --git a/data/ghini.desktop b/data/ghini.desktop index 226be3a63..5cd4bc9fc 100644 --- a/data/ghini.desktop +++ b/data/ghini.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Encoding=UTF-8 Name=Ghini -Version=1.0.74 # :bump +Version=1.0.75 # :bump Comment=An application for managing botanical collections Terminal=False Icon=ghini diff --git a/doc/conf.py b/doc/conf.py index 4cb162798..a3a80fb71 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -70,7 +70,7 @@ # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. -release = '1.0.74' # :bump +release = '1.0.75' # :bump # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/packages/builddeb.sh b/packages/builddeb.sh index 4cc35966d..881eac66a 100755 --- a/packages/builddeb.sh +++ b/packages/builddeb.sh @@ -3,7 +3,7 @@ # Requires bzr, devscripts, debhelper packages TOPLEVEL=`pwd` -VERSION="1.0.74" # :bump +VERSION="1.0.75" # :bump TARBALL="bauble-$VERSION.tar.gz" ORIG_TARBALL="bauble_$VERSION.orig.tar.gz" diff --git a/scripts/build.nsi b/scripts/build.nsi index 38d0bc9e5..f64f074ff 100755 --- a/scripts/build.nsi +++ b/scripts/build.nsi @@ -12,7 +12,7 @@ ; general Name "Bauble" -!define version "1.0.74" ; :bump +!define version "1.0.75" ; :bump !define src_dir "../dist" Outfile "bauble-${version}-setup.exe" diff --git a/scripts/installer.cfg b/scripts/installer.cfg index 808d4ff99..b45dc412d 100644 --- a/scripts/installer.cfg +++ b/scripts/installer.cfg @@ -1,6 +1,6 @@ [Application] name=Bauble -version=1.0.74 # :bump +version=1.0.75 # :bump entry_point=bauble:main icon=images/icon.ico