From cce09936848b0f1048f848440f12d4816cb3b705 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 26 Nov 2011 14:52:59 +0100 Subject: [PATCH 1/5] move report parameters to separate interface --- composer/report/interfaces.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/composer/report/interfaces.py b/composer/report/interfaces.py index 8d020f2..5d2b42c 100644 --- a/composer/report/interfaces.py +++ b/composer/report/interfaces.py @@ -53,7 +53,20 @@ class IReportManager(Interface): """ -class IReport(ITemplate): +class IReportParams(Interface): + """ Contains the real reporting parameters like query and sort criteria, + column definitions, etc. + """ + + queryCriteria = Attribute('The criteria to be used for executing the ' + 'query step.') + sortSpec = Attribute('A sequence of fields/sort directions to be used for ' + 'executing the sorting step.') + outputSpec = Attribute('A sequence of output fields (column/cell ' + 'specifications) to be used for presenting the result data.') + + +class IReport(ITemplate, IReportParams): """ A configurable report. """ @@ -90,13 +103,6 @@ class IReport(ITemplate): renderers = Attribute('An ordered collection of renderers available ' 'for this report type.') - queryCriteria = Attribute('The criteria to be used for executing the ' - 'query step.') - sortSpec = Attribute('A sequence of fields/sort directions to be used for ' - 'executing the sorting step.') - outputSpec = Attribute('A sequence of output fields (column/cell ' - 'specifications) to be used for presenting the result data.') - def getQueryFields(): """ Return a sequence of fields that may be used for setting up the query criteria. From a33f17faf068fa8a9a21709b1bdf7d4e3c8ba875 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 27 Nov 2011 15:18:37 +0100 Subject: [PATCH 2/5] continuous improvement and extension of reporting facilities --- composer/report/base.py | 2 -- composer/report/field.py | 5 ++++- composer/report/result.py | 13 ++++++++++--- util/date.py | 9 +++++---- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/composer/report/base.py b/composer/report/base.py index 86b5cf3..fddcdb0 100644 --- a/composer/report/base.py +++ b/composer/report/base.py @@ -18,8 +18,6 @@ """ Basic classes for report management. - -$Id$ """ import operator as standard_operators diff --git a/composer/report/field.py b/composer/report/field.py index f144755..b773fe5 100644 --- a/composer/report/field.py +++ b/composer/report/field.py @@ -70,7 +70,7 @@ class Field(Component): return self.__name__ def getRawValue(self, row): - return getattr(row.context, self.name) + return row.getRawValue(self.name) def getSelectValue(self, row): return getattr(row, self.name, None) @@ -84,6 +84,9 @@ class Field(Component): return value return getattr(value, 'title', str(value)) + def getDisplayValue(self, row): + return self.getValue(row) + def getSortValue(self, row): # TODO: consider 'descending' flag, use raw value instead of formatted one return getattr(row, self.name, None) diff --git a/composer/report/result.py b/composer/report/result.py index 99605f2..bfe082b 100644 --- a/composer/report/result.py +++ b/composer/report/result.py @@ -18,8 +18,6 @@ """ Report result sets and related classes. - -$Id$ """ from zope.cachedescriptors.property import Lazy @@ -28,8 +26,14 @@ from cybertools.composer.interfaces import IInstance from cybertools.composer.report.base import BaseQueryCriteria +def getContextAttr(obj, attr): + return getattr(obj.context, attr) + + class Row(object): + attributeHandlers = {} + def __init__(self, context, parent): self.context = context self.parent = parent @@ -38,12 +42,15 @@ class Row(object): f = self.parent.context.fields[attr] return f.getValue(self) + def getRawValue(self, attr): + return self.attributeHandlers.get(attr, getContextAttr)(self, attr) + class ResultSet(object): def __init__(self, context, data, rowFactory=Row, sortCriteria=None, queryCriteria=BaseQueryCriteria()): - self.context = context + self.context = context # the report or report instance self.data = data self.rowFactory = rowFactory self.sortCriteria = sortCriteria diff --git a/util/date.py b/util/date.py index 5613747..e774fb8 100644 --- a/util/date.py +++ b/util/date.py @@ -18,8 +18,6 @@ """ Date and time utilities. - -$Id$ """ import time @@ -30,6 +28,11 @@ def getTimeStamp(): return int(time.time()) +def timeStamp2Date(ts, useGM=False): + if ts is None: + ts = getTimeStamp() + return datetime.fromtimestamp(ts) + def timeStamp2ISO(ts, useGM=False, format='%Y-%m-%d %H:%M'): return formatTimeStamp(ts, useGM, format) @@ -38,8 +41,6 @@ def formatTimeStamp(ts, useGM=False, format='%Y-%m-%d %H:%M'): ts = getTimeStamp() fct = useGM and time.gmtime or time.localtime return time.strftime(format, fct(ts)) - #return time.strftime('%Y-%m-%d %H:%M', time.gmtime(ts)) - #return time.strftime('%Y-%m-%d %H:%M', time.localtime(ts)) def str2timeStamp(s): From add1a31bae143a9a4db32e7f058bfd80e3d5cf35 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 27 Nov 2011 19:43:04 +0100 Subject: [PATCH 3/5] define row data for report totals --- composer/report/field.py | 2 +- composer/report/result.py | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/composer/report/field.py b/composer/report/field.py index b773fe5..4debe38 100644 --- a/composer/report/field.py +++ b/composer/report/field.py @@ -47,7 +47,7 @@ class Field(Component): renderer = 'standard' operator = 'in' - executionSteps = ['query', 'sort', 'output'] + executionSteps = ['query', 'sort', 'output'] # , 'totals'] operators = [{'token': 'eq', 'label': '=='}, {'token': 'lt', 'label': '<'}, diff --git a/composer/report/result.py b/composer/report/result.py index bfe082b..b033b19 100644 --- a/composer/report/result.py +++ b/composer/report/result.py @@ -26,24 +26,33 @@ from cybertools.composer.interfaces import IInstance from cybertools.composer.report.base import BaseQueryCriteria -def getContextAttr(obj, attr): - return getattr(obj.context, attr) - -class Row(object): - - attributeHandlers = {} +class BaseRow(object): def __init__(self, context, parent): self.context = context self.parent = parent + self.data = {} def __getattr__(self, attr): f = self.parent.context.fields[attr] return f.getValue(self) def getRawValue(self, attr): - return self.attributeHandlers.get(attr, getContextAttr)(self, attr) + return self.data.get(attr) + + +class Row(BaseRow): + + attributeHandlers = {} + + def getRawValue(self, attr): + return self.attributeHandlers.get(attr, Row.getContextAttr)(self, attr) + + @classmethod + def getContextAttr(obj, attr): + return getattr(obj.context, attr) + class ResultSet(object): @@ -55,6 +64,7 @@ class ResultSet(object): self.rowFactory = rowFactory self.sortCriteria = sortCriteria self.queryCriteria = queryCriteria + self.totals = BaseRow(None, self) def getResult(self): result = [self.rowFactory(item, self) for item in self.data] From ab20786f34eac4ba66e6132425d31be7a3e5ad40 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Thu, 1 Dec 2011 08:39:54 +0100 Subject: [PATCH 4/5] fix method decorator for default attribute access --- composer/report/result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer/report/result.py b/composer/report/result.py index b033b19..7396fbe 100644 --- a/composer/report/result.py +++ b/composer/report/result.py @@ -49,7 +49,7 @@ class Row(BaseRow): def getRawValue(self, attr): return self.attributeHandlers.get(attr, Row.getContextAttr)(self, attr) - @classmethod + @staticmethod def getContextAttr(obj, attr): return getattr(obj.context, attr) From e9fedc542e5f644f277124c046ea80f24834ab99 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Thu, 1 Dec 2011 08:40:55 +0100 Subject: [PATCH 5/5] use prefix 'meta' for attribute names to avoid name clashes --- browser/base_macros.pt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/base_macros.pt b/browser/base_macros.pt index afb7edd..21b927e 100644 --- a/browser/base_macros.pt +++ b/browser/base_macros.pt @@ -11,8 +11,8 @@ - +