/
__init__.py
144 lines (98 loc) · 3.24 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# vim: set ts=4 sw=4 filetype=python:
"""
Stuff that is useful in lots of different places goes in here.
Stuff that is REALLY useful should be in the awesome clepy package,
which is a grab bag of fanciness.
"""
from __future__ import with_statement
import logging
__version__ = "1.0.3"
# This bugs me. I don't like how instead of just defining stuff, I'm
# making stuff really happen.
log = logging.getLogger('pitz')
log.setLevel(logging.DEBUG)
h = logging.StreamHandler()
h.setLevel(logging.DEBUG)
log.addHandler(h)
# TODO: Move this into the clepy package.
def by_whatever(func_name, *whatever, **kwargs):
"""
Returns a function suitable for sorting, using whatever.
>>> e1, e2 = {'a':1, 'b':1, 'c':2}, {'a':2, 'b':2, 'c':1}
>>> by_whatever('xxx', 'a')(e1, e2)
-1
>>> by_whatever('xxx', 'c', 'a')(e1, e2)
1
>>> by_whatever('xxx', 'c', 'a', reverse=True)(e1, e2)
-1
"""
def f(e1, e2):
y = cmp(
[e1.get(w) for w in whatever],
[e2.get(w) for w in whatever])
if kwargs.get('reverse'):
y *= -1
return y
if 'reverse' in kwargs:
f.__doc__ = '%s (reversed)' % list(whatever)
else:
f.__doc__ = str(list(whatever))
f.func_name = func_name
return f
# TODO: Figure out if I should use functools.partial instead.
by_spiciness = by_whatever('by_spiciness', 'peppers')
by_created_time = by_whatever('by_created_time', 'created_time')
by_descending_created_time = by_whatever('by descending created time',
'created_time', reverse=True)
by_type_status_created_time = by_whatever('by_type_status_created_time',
'type', 'status', 'created time')
by_milestone = by_whatever('by_milestone',
'milestone', 'type', 'status', 'created time')
def by_pscore_and_milestone(e1, e2):
y = cmp(e1['pscore'], e2['pscore']) * -1
if y != 0:
return y
else:
return by_milestone(e1, e2)
def by_status(e1, e2):
"""
Compare the status attribute of the two entities.
"""
y = -1 * cmp(e1['status'], e2['status'])
if y != 0:
return y
else:
return by_created_time(e1, e2)
by_milestone_status_pscore_created_time = by_whatever(
'by_milestone_status_pscore_created_time',
'milestone', 'status', 'pscore', 'created time', reverse=True)
by_milestone_status_pscore = by_milestone_status_pscore_created_time
class PitzException(Exception):
"""
All pitz exceptions subclass this guy.
"""
class NoProject(PitzException):
"""
Indicates that this object can't do what you are asking it to do
because it doesn't have a pitz.project.Project instance to work
with.
"""
class ProjectNotFound(PitzException):
"""
Indicates that the system couldn't find what it needed to create a
project.
"""
def build_filter(args):
"""
Return a dictionary suitable for filtering.
>>> build_filter(['a=1', 'b=2', 'c=[3,4,5]'])
{'a': '1', 'c': ['3', '4', '5'], 'b': '2'}
"""
d = dict()
for a in args:
attr, value = a.split('=')
# Make a list of values if we got a string like "[1, 2, 3]"
if value.startswith('[') and value.endswith(']'):
value = value.strip('[]').split(',')
d[attr] = value
return d