]> git.madduck.net Git - etc/taskwarrior.git/blob - tasklib/lazy.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

TaskQuerySet: Extend native filters with deleted and waiting
[etc/taskwarrior.git] / tasklib / lazy.py
1 """
2 Provides lazy implementations for Task and TaskQuerySet.
3 """
4
5
6 class LazyUUIDTask(object):
7     """
8     A lazy wrapper around Task object, referenced by UUID.
9
10     - Supports comparison with LazyUUIDTask or Task objects (equality by UUIDs)
11     - If any attribute other than 'uuid' requested, a lookup in the
12       backend will be performed and this object will be replaced by a proper
13       Task object.
14     """
15
16     def __init__(self, tw, uuid):
17         self._tw = tw
18         self._uuid = uuid
19
20     def __getitem__(self, key):
21         # LazyUUIDTask does not provide anything else other than 'uuid'
22         if key is 'uuid':
23             return self._uuid
24         else:
25             self.replace()
26             return self[key]
27
28     def __getattr__(self, name):
29         # Getattr is called only if the attribute could not be found using
30         # normal means
31         self.replace()
32         return getattr(self, name)
33
34     def __eq__(self, other):
35         if other and other['uuid']:
36             # For saved Tasks, just define equality by equality of uuids
37             return self['uuid'] == other['uuid']
38
39     def __ne__(self, other):
40         return not self.__eq__(other)
41
42     def __hash__(self):
43         return self['uuid'].__hash__()
44
45     def __repr__(self):
46         return "LazyUUIDTask: {0}".format(self._uuid)
47
48     def __copy__(self):
49         return LazyUUIDTask(self._tw, self._uuid)
50
51     def __deepcopy__(self, memo):
52         return LazyUUIDTask(self._tw, self._uuid)
53
54     @property
55     def saved(self):
56         """
57         Implementation of the 'saved' property. Always returns True.
58         """
59         return True
60
61     @property
62     def _modified_fields(self):
63         return set()
64
65     @property
66     def modified(self):
67         return False
68
69     def replace(self):
70         """
71         Performs conversion to the regular Task object, referenced by the
72         stored UUID.
73         """
74
75         replacement = self._tw.tasks.get(uuid=self._uuid)
76         self.__class__ = replacement.__class__
77         self.__dict__ = replacement.__dict__
78
79
80 class LazyUUIDTaskSet(object):
81     """
82     A lazy wrapper around TaskQuerySet object, for tasks referenced by UUID.
83
84     - Supports 'in' operator with LazyUUIDTask or Task objects
85     - If iteration over the objects in the LazyUUIDTaskSet is requested, the
86       LazyUUIDTaskSet will be converted to QuerySet and evaluated
87     """
88
89     def __init__(self, tw, uuids):
90         self._tw = tw
91         self._uuids = set(uuids)
92
93     def __getattr__(self, name):
94         # Getattr is called only if the attribute could not be found using
95         # normal means
96
97         if name.startswith('__'):
98             # If some internal method was being search, do not convert
99             # to TaskQuerySet just because of that
100             raise AttributeError
101         else:
102             self.replace()
103             return getattr(self, name)
104
105     def __repr__(self):
106         return "LazyUUIDTaskSet([{0}])".format(', '.join(self._uuids))
107
108     def __eq__(self, other):
109         return set(t['uuid'] for t in other) == self._uuids
110
111     def __ne__(self, other):
112         return not (self == other)
113
114     def __contains__(self, task):
115         return task['uuid'] in self._uuids
116
117     def __len__(self):
118         return len(self._uuids)
119
120     def __iter__(self):
121         for uuid in self._uuids:
122             yield LazyUUIDTask(self._tw, uuid)
123
124     def __sub__(self, other):
125         return self.difference(other)
126
127     def __isub__(self, other):
128         return self.difference_update(other)
129
130     def __rsub__(self, other):
131         return LazyUUIDTaskSet(self._tw,
132             set(t['uuid'] for t in other) - self._uuids)
133
134     def __or__(self, other):
135         return self.union(other)
136
137     def __ior__(self, other):
138         return self.update(other)
139
140     def __ror__(self, other):
141         return self.union(other)
142
143     def __xor__(self, other):
144         return self.symmetric_difference(other)
145
146     def __ixor__(self, other):
147         return self.symmetric_difference_update(other)
148
149     def __rxor__(self, other):
150         return self.symmetric_difference(other)
151
152     def __and__(self, other):
153         return self.intersection(other)
154
155     def __iand__(self, other):
156         return self.intersection_update(other)
157
158     def __rand__(self, other):
159         return self.intersection(other)
160
161     def __le__(self, other):
162         return self.issubset(other)
163
164     def __ge__(self, other):
165         return self.issuperset(other)
166
167     def issubset(self, other):
168         return all([task in other for task in self])
169
170     def issuperset(self, other):
171         return all([task in self for task in other])
172
173     def union(self, other):
174         return LazyUUIDTaskSet(self._tw,
175             self._uuids | set(t['uuid'] for t in other))
176
177     def intersection(self, other):
178         return LazyUUIDTaskSet(self._tw,
179             self._uuids & set(t['uuid'] for t in other))
180
181     def difference(self, other):
182         return LazyUUIDTaskSet(self._tw,
183             self._uuids - set(t['uuid'] for t in other))
184
185     def symmetric_difference(self, other):
186         return LazyUUIDTaskSet(self._tw,
187             self._uuids ^ set(t['uuid'] for t in other))
188
189     def update(self, other):
190         self._uuids |= set(t['uuid'] for t in other)
191         return self
192
193     def intersection_update(self, other):
194         self._uuids &= set(t['uuid'] for t in other)
195         return self
196
197     def difference_update(self, other):
198         self._uuids -= set(t['uuid'] for t in other)
199         return self
200
201     def symmetric_difference_update(self, other):
202         self._uuids ^= set(t['uuid'] for t in other)
203         return self
204
205     def add(self, task):
206         self._uuids.add(task['uuid'])
207
208     def remove(self, task):
209         self._uuids.remove(task['uuid'])
210
211     def pop(self):
212         return self._uuids.pop()
213
214     def clear(self):
215         self._uuids.clear()
216
217     def replace(self):
218         """
219         Performs conversion to the regular TaskQuerySet object, referenced by
220         the stored UUIDs.
221         """
222
223         replacement = self._tw.tasks.filter(' '.join(self._uuids))
224         self.__class__ = replacement.__class__
225         self.__dict__ = replacement.__dict__