From 225ea927a40b9c4f1035ed2d86c5e8bc9f01f1f4 Mon Sep 17 00:00:00 2001 From: Gaetan Delannay Date: Fri, 2 Jan 2015 16:16:48 +0100 Subject: [PATCH] [gen] Bugfixes in the search machinery. --- fields/computed.py | 6 +++--- fields/pod.py | 14 +++++++------- gen/indexer.py | 18 +----------------- gen/installer.py | 6 +++--- gen/mixins/__init__.py | 1 + gen/tr/Appy.pot | 4 ++++ gen/tr/ar.po | 4 ++++ gen/tr/de.po | 4 ++++ gen/tr/en.po | 4 ++++ gen/tr/es.po | 4 ++++ gen/tr/fr.po | 4 ++++ gen/tr/it.po | 4 ++++ gen/tr/nl.po | 4 ++++ gen/utils.py | 23 ++++++++++++++++++++--- gen/wrappers/__init__.py | 22 +++++++++++++--------- shared/utils.py | 2 +- 16 files changed, 81 insertions(+), 43 deletions(-) diff --git a/fields/computed.py b/fields/computed.py index a4ee3d1..e1bd0c8 100644 --- a/fields/computed.py +++ b/fields/computed.py @@ -39,7 +39,7 @@ class Computed(Field): masterValue=None, focus=False, historized=False, mapping=None, label=None, sdefault='', scolspan=1, swidth=None, sheight=None, context=None, view=None, xml=None): - # The Python method used for computing the field value, or a PX. + # The Python method used for computing the field value, or a PX self.method = method # A specific method for producing the formatted value of this field. # This way, if, for example, the value is a DateTime instance which is @@ -53,7 +53,7 @@ class Computed(Field): # Does field computation produce plain text or XHTML? self.plainText = plainText if isinstance(method, Px): - # When field computation is done with a PX, the result is XHTML. + # When field computation is done with a PX, the result is XHTML self.plainText = False # Determine default value for "show" if show == None: @@ -62,7 +62,7 @@ class Computed(Field): # in the xml layout. show = self.plainText and ('view', 'result', 'xml') or \ ('view', 'result') - # If method is a PX, its context can be given in p_context. + # If method is a PX, its context can be given in p_context self.context = context Field.__init__(self, None, multiplicity, default, show, page, group, layouts, move, indexed, mustIndex, searchable, diff --git a/fields/pod.py b/fields/pod.py index fb57888..dfa5ae8 100644 --- a/fields/pod.py +++ b/fields/pod.py @@ -275,9 +275,9 @@ class Pod(Field): move, False, True, False, specificReadPermission, specificWritePermission, width, height, None, colspan, master, masterValue, focus, historized, mapping, label, - None, None, None, None, True, view, xml) - # Param "persist" is set to True but actually, persistence for a pod - # field is determined by freezing. + None, None, None, None, False, view, xml) + # Param "persist" is False, but actual persistence for this field is + # determined by freezing. self.validable = False def getExtension(self, template): @@ -603,7 +603,7 @@ class Pod(Field): when no p_upload file is specified), if the freezing fails we try to freeze the odt version, which is more robust because it does not require calling LibreOffice.''' - # Security check. + # Security check if not noSecurity and \ (format not in self.getFreezeFormats(obj, template)): raise Exception(self.UNAUTHORIZED) @@ -613,10 +613,10 @@ class Pod(Field): fileName = self.getFreezeName(template, format) result = os.path.join(dbFolder, folder, fileName) if os.path.exists(result): - prefix = upload and 'Freeze (upload)' or 'Freeze' + prefix = upload and 'freeze (upload)' or 'freeze' obj.log('%s: overwriting %s...' % (prefix, result)) if not upload: - # Generate the document. + # Generate the document doc = self.getValue(obj, template=template, format=format, result=result) if isinstance(doc, basestring): @@ -640,7 +640,7 @@ class Pod(Field): raise Exception(self.FREEZE_FATAL_ERROR) obj.log('freezed at %s.' % result) else: - # Store the uploaded file in the database. + # Store the uploaded file in the database f = file(result, 'wb') doc = FileInfo(result, inDb=False) doc.replicateFile(upload, f) diff --git a/gen/indexer.py b/gen/indexer.py index 6c8a84d..05436a2 100644 --- a/gen/indexer.py +++ b/gen/indexer.py @@ -2,6 +2,7 @@ indexed.''' # ------------------------------------------------------------------------------ +from appy.gen.utils import splitIntoWords from appy.shared.xml_parser import XmlParser from appy.shared.utils import normalizeText @@ -68,23 +69,6 @@ def updateIndexes(installer, indexInfo): catalog.reindexIndex(indexName, installer.app.REQUEST) logger.info('Done.') -# ------------------------------------------------------------------------------ -def splitIntoWords(text, ignore=2): - '''Split the cleaned index value p_text into words (returns a list of - words). Words whose length is below p_ignore are ignored, excepted digits - which are always kept. Duplicate words are removed (result is a set and - not a list).''' - # Split p_text into words - res = text.split() - # Remove shorter words not being figures - i = len(res) - 1 - while i > -1: - if (len(res[i]) <= ignore) and not res[i].isdigit(): - del res[i] - i -= 1 - # Remove duplicates - return set(res) - # ------------------------------------------------------------------------------ class XhtmlTextExtractor(XmlParser): '''Extracts text from XHTML.''' diff --git a/gen/installer.py b/gen/installer.py index 91720c9..9901d0d 100644 --- a/gen/installer.py +++ b/gen/installer.py @@ -141,7 +141,7 @@ class ZopeInstaller: wrapperClass = tool.getAppyClass(className, wrapper=True) indexInfo.update(wrapperClass.getIndexes(includeDefaults=False)) updateIndexes(self, indexInfo) - # Re-index index "SearchableText", wrongly defined for Appy < 0.8.3. + # Re-index index "SearchableText", wrongly defined for Appy < 0.8.3 stIndex = catalog.Indexes['SearchableText'] if stIndex.indexSize() == 0: self.logger.info('reindexing SearchableText...') @@ -283,13 +283,13 @@ class ZopeInstaller: # "select" field, because it will be necessary for displaying the # translated state name. state = gen.String(validator=gen.Selection('listStates'), - show='result') + show='result', persist=False, indexed=True) state.init('state', None, 'workflow') setattr(wrapperClass, 'state', state) # Special field "SearchableText" must be added fot every class and # will allow to display a search widget for entering keywords for # searhing in index "SearchableText". - searchable = gen.String(show=False) + searchable = gen.String(show=False, persist=False, indexed=True) searchable.init('SearchableText', None, 'appy') setattr(wrapperClass, 'SearchableText', searchable) # Set field "__fields__" on the wrapper class diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py index 8e14d6d..6b3903b 100644 --- a/gen/mixins/__init__.py +++ b/gen/mixins/__init__.py @@ -1037,6 +1037,7 @@ class BaseMixin: '''Gets the i18n label for p_name (which can denote a state or a transition), or for the current object state if p_name is None.''' name = name or self.State() + if name == 'create_from_predecessor': return name return '%s_%s' % (self.getWorkflow(name=True), name) def getTransitions(self, includeFake=True, includeNotShowable=False, diff --git a/gen/tr/Appy.pot b/gen/tr/Appy.pot index 0e82f61..d7d78a8 100644 --- a/gen/tr/Appy.pot +++ b/gen/tr/Appy.pot @@ -515,6 +515,10 @@ msgstr "" msgid "action_comment" msgstr "" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "" + #. Default: "Mon" msgid "day_Mon_short" msgstr "" diff --git a/gen/tr/ar.po b/gen/tr/ar.po index d424b1c..89316a8 100644 --- a/gen/tr/ar.po +++ b/gen/tr/ar.po @@ -515,6 +515,10 @@ msgstr "" msgid "action_comment" msgstr "" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "" + #. Default: "Mon" msgid "day_Mon_short" msgstr "" diff --git a/gen/tr/de.po b/gen/tr/de.po index 445b2fb..54987ff 100644 --- a/gen/tr/de.po +++ b/gen/tr/de.po @@ -515,6 +515,10 @@ msgstr "" msgid "action_comment" msgstr "" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "" + #. Default: "Mon" msgid "day_Mon_short" msgstr "" diff --git a/gen/tr/en.po b/gen/tr/en.po index 4253e3d..aca4ca0 100644 --- a/gen/tr/en.po +++ b/gen/tr/en.po @@ -516,6 +516,10 @@ msgstr "Date" msgid "action_comment" msgstr "Comment" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "Create from a delayed item" + #. Default: "Mon" msgid "day_Mon_short" msgstr "Mon" diff --git a/gen/tr/es.po b/gen/tr/es.po index 5adf075..eca13d7 100644 --- a/gen/tr/es.po +++ b/gen/tr/es.po @@ -515,6 +515,10 @@ msgstr "" msgid "action_comment" msgstr "" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "" + #. Default: "Mon" msgid "day_Mon_short" msgstr "" diff --git a/gen/tr/fr.po b/gen/tr/fr.po index ef37fc6..613bd01 100644 --- a/gen/tr/fr.po +++ b/gen/tr/fr.po @@ -516,6 +516,10 @@ msgstr "Date" msgid "action_comment" msgstr "Commentaire" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "Créer depuis un point reporté" + #. Default: "Mon" msgid "day_Mon_short" msgstr "Lun" diff --git a/gen/tr/it.po b/gen/tr/it.po index e195df5..8ae6b7b 100644 --- a/gen/tr/it.po +++ b/gen/tr/it.po @@ -515,6 +515,10 @@ msgstr "" msgid "action_comment" msgstr "" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "" + #. Default: "Mon" msgid "day_Mon_short" msgstr "" diff --git a/gen/tr/nl.po b/gen/tr/nl.po index 8f60da1..5da864e 100644 --- a/gen/tr/nl.po +++ b/gen/tr/nl.po @@ -515,6 +515,10 @@ msgstr "Datum" msgid "action_comment" msgstr "Commentaar" +#. Default: "Create from a delayed item" +msgid "create_from_predecessor" +msgstr "" + #. Default: "Mon" msgid "day_Mon_short" msgstr "Maa" diff --git a/gen/utils.py b/gen/utils.py index 4992f6d..6329890 100644 --- a/gen/utils.py +++ b/gen/utils.py @@ -91,18 +91,35 @@ class SomeObjects: else: getMethod = 'getObject' self.objects = [getattr(b, getMethod)() for b in brains] +# ------------------------------------------------------------------------------ +def splitIntoWords(text, ignore=2): + '''Split the cleaned index value p_text into words (returns a list of + words). Words whose length is below p_ignore are ignored, excepted digits + which are always kept. Duplicate words are removed (result is a set and + not a list).''' + # Split p_text into words + res = text.split() + # Remove shorter words not being figures + i = len(res) - 1 + while i > -1: + if (len(res[i]) <= ignore) and not res[i].isdigit(): + del res[i] + i -= 1 + # Remove duplicates + return set(res) + # ------------------------------------------------------------------------------ class Keywords: '''This class allows to handle keywords that a user enters and that will be used as basis for performing requests in a TextIndex/XhtmlIndex.''' toRemove = '?-+*()' - def __init__(self, keywords, operator='AND'): - # Clean the p_keywords that the user has entered. + def __init__(self, keywords, operator='AND', ignore=2): + # Clean the p_keywords that the user has entered words = sutils.normalizeText(keywords) if words == '*': words = '' for c in self.toRemove: words = words.replace(c, ' ') - self.keywords = words.split() + self.keywords = splitIntoWords(words, ignore=ignore) # Store the operator to apply to the keywords (AND or OR) self.operator = operator diff --git a/gen/wrappers/__init__.py b/gen/wrappers/__init__.py index fef45fd..0054582 100644 --- a/gen/wrappers/__init__.py +++ b/gen/wrappers/__init__.py @@ -302,7 +302,7 @@ class AbstractWrapper(object): # PXs for rendering graphical elements tied to a given object # -------------------------------------------------------------------------- - # This PX displays an object's history. + # This PX displays an object's history pxHistory = Px(''' {}[]|\t\\°' +charsIgnore = u'.,:;*+=~?%^\'’"<>{}[]|\t\\°-' fileNameIgnore = charsIgnore + u' $£€/' extractIgnore = charsIgnore + '()' alphaRex = re.compile('[a-zA-Z]')