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

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