Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

I think I've seen this ORM somewhere before...

root/trunk/analysis.py

Revision 1 (checked in by cnew, 9 years ago)

initial import

Line 
1 """Analysis tools for dejavu Units."""
2
3 def sort(attrs, descending=False):
4     """sort(attrs, descending=False) -> create a function for list.sort() for Units."""
5     if isinstance(attrs, (str, unicode)):
6         attrs = (attrs, )
7     def sort_func(x, y):
8         for attr in attrs:
9             xv = getattr(x, attr)
10             if callable(xv):
11                 xv = xv()
12             if xv is None:
13                 diff = -1
14             else:
15                 yv = getattr(y, attr)
16                 if callable(yv):
17                     yv = yv()
18                 if yv is None:
19                     diff = 1
20                 else:
21                     diff = cmp(xv, yv)
22             if descending:
23                 diff = -diff
24             if diff != 0:
25                 return diff
26         return 0
27     return sort_func
28
29
30 def _force_function(attr):
31     if callable(attr):
32         return attr
33    
34     def g(obj):
35         return getattr(obj, attr)
36    
37     return g
38
39
40 def SUM(attribute):
41     """sum(attribute) -> create an aggregate function for use with crosstab().
42     
43     'attribute' can be either the name of an attribute defined for
44     all objects in self.source, or a further callable to which each obj
45     is passed and evaluated.
46     """
47     if callable(attribute):
48         def aggfunc(obj, current_agg_value):
49             a, b = current_agg_value, attribute(obj)
50             if a is None:
51                 return b
52             if b is None:
53                 return a
54             return a + b
55     else:
56         def aggfunc(obj, current_agg_value):
57             a, b = current_agg_value, getattr(obj, attribute)
58             if a is None:
59                 return b
60             if b is None:
61                 return a
62             return a + b
63     return aggfunc
64
65 def COUNT(obj, current_agg_value):
66     """count -> an aggregate function for use with crosstab()."""
67     return (current_agg_value or 0) + 1
68
69
70 class CrossTab(list):
71     """Tool to form crosstabs of Unit property values.
72     
73     Example:
74         data = CrossTab(source, (lambda x: x.FirstDate.month,),
75                         'Field', CrossTab.sum('Size')).results()
76     """
77    
78     def __init__(self, source=[], groups=[], pivot=None, aggfunc=COUNT):
79         """CrossTab(source, groups, pivot, aggfunc=count)
80         
81         groups: a sequence of attribute names or callables,
82             which will form the rows of the result.
83         
84         pivot: either an attribute name or a callable, which will
85             form the columns of the result.
86         """
87         # Iterate through generator if provided. We do this here rather
88         # than results() because we want to allow multiple calls to
89         # results() without exhausting the generator.
90         self.source = [x for x in source]
91        
92         if not isinstance(groups, (tuple, list)):
93             groups = [groups,]
94         self.groups = groups
95        
96         self.pivot = pivot
97         self.aggfunc = aggfunc
98    
99     def results(self):
100         # Force all groups to functions. The reason we do it here instead
101         # of __init__ is so consumers can still read self.groups as strings
102         # if that's what they supplied.
103         groups = [_force_function(group) for group in self.groups]
104         pivot = _force_function(self.pivot)
105         aggfunc = self.aggfunc
106        
107         data = {}
108         columns = {}
109         for obj in self.source:
110             key = tuple([group(obj) for group in groups])
111             val = pivot(obj)
112             columns[val] = None
113            
114             row = data.setdefault(key, {})
115             row[val] = aggfunc(obj, row.get(val))
116        
117         columns = columns.keys()
118         columns.sort()
119         return data, columns
120
Note: See TracBrowser for help on using the browser.