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

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