]> 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:

Merge branch 'develop'
[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) if other else set()) == 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(
132             self._tw,
133             set(t['uuid'] for t in other) - self._uuids,
134         )
135
136     def __or__(self, other):
137         return self.union(other)
138
139     def __ior__(self, other):
140         return self.update(other)
141
142     def __ror__(self, other):
143         return self.union(other)
144
145     def __xor__(self, other):
146         return self.symmetric_difference(other)
147
148     def __ixor__(self, other):
149         return self.symmetric_difference_update(other)
150
151     def __rxor__(self, other):
152         return self.symmetric_difference(other)
153
154     def __and__(self, other):
155         return self.intersection(other)
156
157     def __iand__(self, other):
158         return self.intersection_update(other)
159
160     def __rand__(self, other):
161         return self.intersection(other)
162
163     def __le__(self, other):
164         return self.issubset(other)
165
166     def __ge__(self, other):
167         return self.issuperset(other)
168
169     def issubset(self, other):
170         return all([task in other for task in self])
171
172     def issuperset(self, other):
173         return all([task in self for task in other])
174
175     def union(self, other):
176         return LazyUUIDTaskSet(
177             self._tw,
178             self._uuids | set(t['uuid'] for t in other),
179         )
180
181     def intersection(self, other):
182         return LazyUUIDTaskSet(
183             self._tw,
184             self._uuids & set(t['uuid'] for t in other),
185         )
186
187     def difference(self, other):
188         return LazyUUIDTaskSet(
189             self._tw,
190             self._uuids - set(t['uuid'] for t in other),
191         )
192
193     def symmetric_difference(self, other):
194         return LazyUUIDTaskSet(
195             self._tw,
196             self._uuids ^ set(t['uuid'] for t in other),
197         )
198
199     def update(self, other):
200         self._uuids |= set(t['uuid'] for t in other)
201         return self
202
203     def intersection_update(self, other):
204         self._uuids &= set(t['uuid'] for t in other)
205         return self
206
207     def difference_update(self, other):
208         self._uuids -= set(t['uuid'] for t in other)
209         return self
210
211     def symmetric_difference_update(self, other):
212         self._uuids ^= set(t['uuid'] for t in other)
213         return self
214
215     def add(self, task):
216         self._uuids.add(task['uuid'])
217
218     def remove(self, task):
219         self._uuids.remove(task['uuid'])
220
221     def pop(self):
222         return self._uuids.pop()
223
224     def clear(self):
225         self._uuids.clear()
226
227     def replace(self):
228         """
229         Performs conversion to the regular TaskQuerySet object, referenced by
230         the stored UUIDs.
231         """
232
233         replacement = self._tw.tasks.filter(' '.join(self._uuids))
234         self.__class__ = replacement.__class__
235         self.__dict__ = replacement.__dict__