From f8a7103c7a7c723789f82906d9005629f8dd4efd Mon Sep 17 00:00:00 2001 From: Gaetan Delannay Date: Fri, 5 Sep 2014 17:13:23 +0200 Subject: [PATCH] [gen] Changes in parameters of some basic field methods to enable field.languages to be defined dymanically via a method. --- fields/__init__.py | 28 ++++----- fields/boolean.py | 4 +- fields/date.py | 9 +-- fields/file.py | 9 ++- fields/float.py | 4 +- fields/integer.py | 6 +- fields/list.py | 11 ++-- fields/pod.py | 2 +- fields/string.py | 99 +++++++++++++++++------------- gen/mixins/ToolMixin.py | 25 ++++++-- gen/mixins/__init__.py | 37 ++++++----- gen/wrappers/ToolWrapper.py | 13 +--- gen/wrappers/TranslationWrapper.py | 5 +- gen/wrappers/__init__.py | 2 +- shared/utils.py | 11 ++++ 15 files changed, 153 insertions(+), 112 deletions(-) diff --git a/fields/__init__.py b/fields/__init__.py index eea2bc4..9432ffb 100644 --- a/fields/__init__.py +++ b/fields/__init__.py @@ -63,7 +63,7 @@ class Field: value=not isSearch and \ field.getFormattedValue(zobj, rawValue, showChanges); requestValue=not isSearch and zobj.getRequestFieldValue(name); - inRequest=field.valueIsInRequest(req, name); + inRequest=field.valueIsInRequest(zobj, req, name); error=req.get('%s_error' % name); isMultiple=(field.multiplicity[1] == None) or \ (field.multiplicity[1] > 1); @@ -360,7 +360,7 @@ class Field: else: master, masterValue = masterData if masterValue and callable(masterValue): return True - reqValue = master.getRequestValue(obj.REQUEST) + reqValue = master.getRequestValue(obj) # reqValue can be a list or not if type(reqValue) not in sutils.sequenceTypes: return reqValue in masterValue @@ -517,7 +517,7 @@ class Field: def getValue(self, obj): '''Gets, on_obj, the value conforming to self's type definition.''' value = getattr(obj.aq_base, self.name, None) - if self.isEmptyValue(value): + if self.isEmptyValue(obj, value): # If there is no value, get the default value if any: return # self.default, of self.default() if it is a method. if callable(self.default): @@ -539,7 +539,7 @@ class Field: purposes. Needs to be overridden by some child classes. If p_showChanges is True, the result must also include the changes that occurred on p_value across the ages.''' - if self.isEmptyValue(value): return '' + if self.isEmptyValue(obj, value): return '' return value def getIndexType(self): @@ -573,7 +573,7 @@ class Field: res = str(res) return res - def valueIsInRequest(self, request, name): + def valueIsInRequest(self, obj, request, name): '''Is there a value corresponding to this field in the request? p_name can be different from self.name (ie, if it is a field within another (List) field). In most cases, checking that this p_name is in the @@ -581,7 +581,7 @@ class Field: for string multilingual fields.''' return request.has_key(name) - def getRequestValue(self, request, requestName=None): + def getRequestValue(self, obj, requestName=None): '''Gets a value for this field as carried in the request object. In the simplest cases, the request value is a single value whose name in the request is the name of the field. @@ -595,15 +595,15 @@ class Field: the container field). In this case, p_requestName must be used for searching into the request, instead of the field name (self.name).''' name = requestName or self.name - return request.get(name, None) + return obj.REQUEST.get(name, None) - def getStorableValue(self, value): + def getStorableValue(self, obj, value): '''p_value is a valid value initially computed through calling m_getRequestValue. So, it is a valid string (or list of strings) representation of the field value coming from the request. This method computes the real (potentially converted or manipulated in some other way) value as can be stored in the database.''' - if self.isEmptyValue(value): return + if self.isEmptyValue(obj, value): return return value def getMasterData(self): @@ -634,11 +634,11 @@ class Field: return 'updateSlaves(this,null,%s,%s,null,null%s)' % \ (q(zobj.absolute_url()), q(layoutType), cName) - def isEmptyValue(self, value, obj=None): + def isEmptyValue(self, obj, value): '''Returns True if the p_value must be considered as an empty value.''' return value in self.nullValues - def isCompleteValue(self, value, obj=None): + def isCompleteValue(self, obj, value): '''Returns True if the p_value must be considered as "complete". While, in most cases, a "complete" value simply means a "non empty" value (see m_isEmptyValue above), in some special cases it is more subtle. @@ -648,7 +648,7 @@ class Field: a Date with the "hour" part required will not be considered as empty if the "day, month, year" part is present but will not be considered as complete without the "hour, minute" part.''' - return not self.isEmptyValue(value, obj) + return not self.isEmptyValue(obj, value) def validateValue(self, obj, value): '''This method may be overridden by child classes and will be called at @@ -673,7 +673,7 @@ class Field: definition. If it is the case, None is returned. Else, a translated error message is returned.''' # If the value is required, check that a (complete) value is present. - if not self.isCompleteValue(value, obj): + if not self.isCompleteValue(obj, value): if self.required and self.isClientVisible(obj): # If the field is required, but not visible according to # master/slave relationships, we consider it not to be required. @@ -686,7 +686,7 @@ class Field: message = self.validateValue(obj, value) if message: return message # Evaluate the custom validator if one has been specified - value = self.getStorableValue(value) + value = self.getStorableValue(obj, value) if self.validator and (type(self.validator) in self.validatorTypes): obj = obj.appy() if type(self.validator) != self.validatorTypes[-1]: diff --git a/fields/boolean.py b/fields/boolean.py index e99868e..5352197 100644 --- a/fields/boolean.py +++ b/fields/boolean.py @@ -117,8 +117,8 @@ class Boolean(Field): def getFormattedValue(self, obj, value, showChanges=False): return obj.translate(self.getValueLabel(value)) - def getStorableValue(self, value): - if not self.isEmptyValue(value): + def getStorableValue(self, obj, value): + if not self.isEmptyValue(obj, value): exec 'res = %s' % value return res diff --git a/fields/date.py b/fields/date.py index f1386a3..61a7ebe 100644 --- a/fields/date.py +++ b/fields/date.py @@ -207,7 +207,7 @@ class Date(Field): return obj.translate('bad_date') def getFormattedValue(self, obj, value, showChanges=False): - if self.isEmptyValue(value): return '' + if self.isEmptyValue(obj, value): return '' tool = obj.getTool().appy() # A problem may occur with some extreme year values. Replace the "year" # part "by hand". @@ -219,7 +219,8 @@ class Date(Field): res += ' %s' % value.strftime(tool.hourFormat) return res - def getRequestValue(self, request, requestName=None): + def getRequestValue(self, obj, requestName=None): + request = obj.REQUEST name = requestName or self.name # Manage the "date" part value = '' @@ -238,8 +239,8 @@ class Date(Field): value = value[:-1] return value - def getStorableValue(self, value): - if not self.isEmptyValue(value): + def getStorableValue(self, obj, value): + if not self.isEmptyValue(obj, value): import DateTime return DateTime.DateTime(value) diff --git a/fields/file.py b/fields/file.py index a0f46c3..77d58c1 100644 --- a/fields/file.py +++ b/fields/file.py @@ -327,16 +327,15 @@ class File(Field): historized, mapping, label, sdefault, scolspan, swidth, sheight, True) - def getRequestValue(self, request, requestName=None): + def getRequestValue(self, obj, requestName=None): name = requestName or self.name - return request.get('%s_file' % name) + return obj.REQUEST.get('%s_file' % name) def getDefaultLayouts(self): return {'view':'l-f','edit':'lrv-f'} - def isEmptyValue(self, value, obj=None): + def isEmptyValue(self, obj, value): '''Must p_value be considered as empty?''' - if not obj: return Field.isEmptyValue(self, value) - if value: return False + if value: return # If "nochange", the value must not be considered as empty return obj.REQUEST.get('%s_delete' % self.name) != 'nochange' diff --git a/fields/float.py b/fields/float.py index 6bf8445..fa749ab 100644 --- a/fields/float.py +++ b/fields/float.py @@ -94,8 +94,8 @@ class Float(Field): except ValueError: return obj.translate('bad_%s' % self.pythonType.__name__) - def getStorableValue(self, value): - if not self.isEmptyValue(value): + def getStorableValue(self, obj, value): + if not self.isEmptyValue(obj, value): for sep in self.sep: value = value.replace(sep, '.') value = value.replace(self.tsep, '') return self.pythonType(value) diff --git a/fields/integer.py b/fields/integer.py index b449f52..7e8e8d4 100644 --- a/fields/integer.py +++ b/fields/integer.py @@ -68,10 +68,10 @@ class Integer(Field): except ValueError: return obj.translate('bad_%s' % self.pythonType.__name__) - def getStorableValue(self, value): - if not self.isEmptyValue(value): return self.pythonType(value) + def getStorableValue(self, obj, value): + if not self.isEmptyValue(obj, value): return self.pythonType(value) def getFormattedValue(self, obj, value, showChanges=False): - if self.isEmptyValue(value): return '' + if self.isEmptyValue(obj, value): return '' return str(value) # ------------------------------------------------------------------------------ diff --git a/fields/list.py b/fields/list.py index f0d89cd..b41ad94 100644 --- a/fields/list.py +++ b/fields/list.py @@ -119,8 +119,9 @@ class List(Field): res.append(elem) return res - def getRequestValue(self, request, requestName=None): + def getRequestValue(self, obj, requestName=None): '''Concatenates the list from distinct form elements in the request.''' + request = obj.REQUEST name = requestName or self.name # A List may be into another List (?) prefix = name + '*' + self.fields[0][0] + '*' res = {} @@ -133,7 +134,7 @@ class List(Field): if rowIndex == -1: continue # Ignore the template row. for subName, subField in self.fields: keyName = '%s*%s*%s' % (name, subName, rowIndex) - v = subField.getRequestValue(request, requestName=keyName) + v = subField.getRequestValue(obj, requestName=keyName) setattr(row, subName, v) res[rowIndex] = row # Produce a sorted list. @@ -148,7 +149,7 @@ class List(Field): request.set(name, res) return res - def getStorableValue(self, value): + def getStorableValue(self, obj, value): '''Gets p_value in a form that can be stored in the database.''' res = [] for v in value: @@ -156,11 +157,11 @@ class List(Field): for name, field in self.fields: subValue = getattr(v, name) try: - setattr(sv, name, field.getStorableValue(subValue)) + setattr(sv, name, field.getStorableValue(obj, subValue)) except ValueError: # The value for this field for this specific row is # incorrect. It can happen in the process of validating the - # whole List field (a call to getStorableValue occurs at + # whole List field (a call to m_getStorableValue occurs at # this time). We don't care about it, because later on we # will have sub-field specific validation that will also # detect the error and will prevent storing the wrong value diff --git a/fields/pod.py b/fields/pod.py index 2aff3ce..1617797 100644 --- a/fields/pod.py +++ b/fields/pod.py @@ -295,7 +295,7 @@ class Pod(Field): tool = obj.tool diskFolder = tool.getDiskFolder() # Get the path to the pod template. - templatePath = os.path.join(diskFolder, template) + templatePath = sutils.resolvePath(os.path.join(diskFolder, template)) if not os.path.isfile(templatePath): raise Exception(self.TEMPLATE_NOT_FOUND % templatePath) # Get or compute the specific POD context diff --git a/fields/string.py b/fields/string.py index 01c6552..6bbe202 100644 --- a/fields/string.py +++ b/fields/string.py @@ -130,8 +130,8 @@ class String(Field): pxMultilingual = Px(''' - :field.pxLanguage + var="count=len(languages)"> + :field.pxLanguage @@ -139,7 +139,7 @@ class String(Field):
:field.subPx[layoutType][fmt]
- + :field.pxLanguage @@ -147,7 +147,8 @@ class String(Field): pxView = Px(''' @@ -193,7 +194,8 @@ class String(Field): pxEdit = Px('''
:field.subPx[layoutType][fmt]
' - def getInitiator(self, field=False): - '''Retrieves the object that triggered the creation of the object - being currently created (if any), or the name of the field in this - object if p_field is given.''' - nav = self.o.REQUEST.get('nav', '') - if not nav or not nav.startswith('ref.'): return - if not field: return self.getObject(nav.split('.')[1]) - return nav.split('.')[2].split(':')[0] - def getObject(self, uid): '''Allow to retrieve an object from its unique identifier p_uid.''' return self.o.getObject(uid, appy=True) @@ -666,10 +657,10 @@ class ToolWrapper(AbstractWrapper): '''Sends a mail. See doc for appy.gen.mail.sendMail.''' sendMail(self, to, subject, body, attachments=attachments) - def formatDate(self, date, withHour=True): + def formatDate(self, date, format=None, withHour=True, language=None): '''Check doc @ToolMixin::formatDate.''' if not date: return - return self.o.formatDate(date, withHour=withHour) + return self.o.formatDate(date, format, withHour, language) def getUserName(self, login=None, normalized=False): return self.o.getUserName(login=login, normalized=normalized) diff --git a/gen/wrappers/TranslationWrapper.py b/gen/wrappers/TranslationWrapper.py index ea4c346..bbe7ac6 100644 --- a/gen/wrappers/TranslationWrapper.py +++ b/gen/wrappers/TranslationWrapper.py @@ -43,10 +43,11 @@ class TranslationWrapper(AbstractWrapper): if field.type == 'Computed': name = field.name[:-6] else: name = field.name # Get the source message - sourceLanguage = self.o.getProductConfig(True).sourceLanguage + obj = self.o + sourceLanguage = obj.getProductConfig(True).sourceLanguage sourceTranslation = getattr(tool.o, sourceLanguage).appy() sourceMsg = getattr(sourceTranslation, name) - if field.isEmptyValue(sourceMsg): return False + if field.isEmptyValue(obj, sourceMsg): return return True poReplacements = ( ('\r\n', '
'), ('\n', '
'), ('"', '\\"') ) diff --git a/gen/wrappers/__init__.py b/gen/wrappers/__init__.py index 29bfe54..059a1f8 100644 --- a/gen/wrappers/__init__.py +++ b/gen/wrappers/__init__.py @@ -788,7 +788,7 @@ class AbstractWrapper(object): obj = self.o if hasattr(obj.aq_base, name): field = obj.getAppyType(name) - return field.isEmptyValue(getattr(obj, name)) + return field.isEmptyValue(obj, getattr(obj, name)) return True def isTemp(self): diff --git a/shared/utils.py b/shared/utils.py index 50e9a94..960d10c 100644 --- a/shared/utils.py +++ b/shared/utils.py @@ -72,6 +72,17 @@ def cleanFolder(folder, exts=extsToClean, folders=(), verbose=False): if verbose: print('Removing folder %s...' % toDelete) FolderDeleter.delete(toDelete) +# ------------------------------------------------------------------------------ +def resolvePath(path): + '''p_path is a file path that can contain occurences of "." and "..". This + function resolves them and procuces a minimal path.''' + res = [] + for elem in path.split(os.sep): + if elem == '.': pass + elif elem == '..': res.pop() + else: res.append(elem) + return os.sep.join(res) + # ------------------------------------------------------------------------------ def copyFolder(source, dest, cleanDest=False): '''Copies the content of folder p_source to folder p_dest. p_dest is