~jplacerda/zeitgeist/784850

« back to all changes in this revision

Viewing changes to zeitgeist/datamodel.py

  • Committer: Mikkel Kamstrup Erlandsen
  • Date: 2010-04-28 19:11:01 UTC
  • mfrom: (1322.1.103 ontology_definition)
  • Revision ID: kamstrup@hardback-20100428191101-9pmau6vlqmna0fow
Merge lp:~zeitgeist/zeitgeist/ontology_definition. This introduces some slight API breaks on the Python level and maybe the need for a DB version upgrade to reflect new URIs here and there. We will tackle these issues in trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
# You should have received a copy of the GNU Lesser General Public License
21
21
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
22
 
23
 
"""
24
 
This module provides the abstract datamodel used by the Zeitgeist framework.
25
 
In addition to providing useful constructs for dealing with the Zeitgeist data
26
 
it also defines symbolic values for the common item types. Using symbolic values
27
 
instead of URI strings will help detect programmer typos.
28
 
"""
29
 
 
 
23
import os.path
 
24
import gettext
30
25
import time
31
 
import gettext
 
26
import sys
32
27
gettext.install("zeitgeist", unicode=1)
33
28
 
 
29
__all__ = [
 
30
        'Interpretation',
 
31
        'Manifestation',
 
32
        'ResultType',
 
33
        'StorageState',
 
34
        'TimeRange',
 
35
        'DataSource',
 
36
        'Event',
 
37
        'Subject',
 
38
        'NULL_EVENT',
 
39
]
 
40
 
 
41
# next() function is python >= 2.6
 
42
try:
 
43
        next = next
 
44
except NameError:
 
45
        # workaround this for older python versions
 
46
        _default_next = object()
 
47
        def next(iterator, default=_default_next):
 
48
                try:
 
49
                        return iterator.next()
 
50
                except StopIteration:
 
51
                        if default is not _default_next:
 
52
                                return default
 
53
                        raise
 
54
 
 
55
runpath = os.path.dirname(__file__)
 
56
 
 
57
NEEDS_CHILD_RESOLUTION = set()
 
58
 
 
59
if not os.path.isfile(os.path.join(runpath, '_config.py.in')):
 
60
        # we are in a global installation
 
61
        # this means we have already parsed zeo.trig into a python file
 
62
        # all we need is to load this python file now
 
63
        IS_LOCAL = False
 
64
else:
 
65
        # we are using zeitgeist `from the branch` in development mode
 
66
        # in this mode we would like to use the recent version of our
 
67
        # ontology. This is why we parse the ontology to a temporary file
 
68
        # and load it from there
 
69
        IS_LOCAL = True
 
70
        
34
71
def get_timestamp_for_now():
35
72
        """
36
73
        Return the current time in milliseconds since the Unix Epoch.
37
74
        """
38
75
        return int(time.time() * 1000)
 
76
                
 
77
 
 
78
class enum_factory(object):
 
79
        """factory for enums"""
 
80
        counter = 0
 
81
        
 
82
        def __init__(self, doc):
 
83
                self.__doc__ = doc
 
84
                self._id = enum_factory.counter
 
85
                enum_factory.counter += 1
 
86
                
 
87
                
 
88
class EnumMeta(type):
 
89
        """Metaclass to register enums in correct order and assign interger
 
90
        values to them
 
91
        """
 
92
        def __new__(cls, name, bases, attributes):
 
93
                enums = filter(
 
94
                        lambda x: isinstance(x[1], enum_factory), attributes.iteritems()
 
95
                )
 
96
                enums = sorted(enums, key=lambda x: x[1]._id)
 
97
                for n, (key, value) in enumerate(enums):
 
98
                        attributes[key] = EnumValue(n, value.__doc__)
 
99
                return super(EnumMeta, cls).__new__(cls, name, bases, attributes)
 
100
 
 
101
 
 
102
class EnumValue(int):
 
103
        """class which behaves like an int, but has an additional docstring"""
 
104
        def __new__(cls, value, doc=""):
 
105
                obj = super(EnumValue, cls).__new__(EnumValue, value)
 
106
                obj.__doc__ = "%s. ``(Integer value: %i)``" %(doc, obj)
 
107
                return obj
 
108
 
 
109
 
 
110
class Enum(object):
 
111
 
 
112
        def __init__(self, docstring):
 
113
                self.__doc__ = str(docstring)
 
114
                self.__enums = {}
 
115
 
 
116
        def __getattr__(self, name):
 
117
                try:
 
118
                        return self.__enums[name]
 
119
                except KeyError:
 
120
                        raise AttributeError
 
121
 
 
122
        def register(self, value, name, docstring):
 
123
                ids = map(int, self.__enums.values())
 
124
                if value in ids or name in self.__enums:
 
125
                        raise ValueError
 
126
                self.__enums[name] = EnumValue(value, docstring)
 
127
                
 
128
                
 
129
def isCamelCase(text):
 
130
        return text and text[0].isupper() and " " not in text
 
131
        
 
132
def get_name_or_str(obj):
 
133
        try:
 
134
                return str(obj.name)
 
135
        except AttributeError:
 
136
                return str(obj)
 
137
 
 
138
_SYMBOLS_BY_URI = {}
39
139
 
40
140
class Symbol(str):
41
 
        
42
 
        """Immutable string-like object representing a Symbol
43
 
        Zeitgeist uses Symbols when defining Manifestations and 
44
 
        Interpretations.
45
 
        """
46
 
        
47
 
        def __new__(cls, symbol_type, name, uri=None, display_name=None, doc=None):
48
 
                obj = super(Symbol, cls).__new__(Symbol, uri or name)
49
 
                obj.__type = symbol_type
50
 
                obj.__name = name
51
 
                obj.__uri = uri
52
 
                obj.__display_name = display_name
53
 
                obj.__doc = doc
54
 
                return obj
55
 
        
 
141
 
 
142
        def __new__(cls, name, parent=None, uri=None, display_name=None, doc=None, auto_resolve=True):
 
143
                if not isCamelCase(name):
 
144
                        raise ValueError("Naming convention requires symbol name to be CamelCase, got '%s'" %name)
 
145
                return super(Symbol, cls).__new__(Symbol, uri or name)
 
146
                
 
147
        def __init__(self, name, parent=None, uri=None, display_name=None, doc=None, auto_resolve=True):
 
148
                self._children = dict()
 
149
                self._all_children = None
 
150
                self._parents = parent or set() # will be bootstrapped to a dict at module load time
 
151
                assert isinstance(self._parents, set), name
 
152
                self._name = name
 
153
                self._uri = uri
 
154
                self._display_name = display_name
 
155
                self._doc = doc
 
156
                _SYMBOLS_BY_URI[uri] = self
 
157
 
56
158
        def __repr__(self):
57
 
                return "<%s %r>" %(self.__type, self.uri)
58
 
        
 
159
                return "<%s '%s'>" %(get_name_or_str(self), self.uri)
 
160
                
 
161
        def __getattr__(self, name):
 
162
                self._ensure_all_children()
 
163
                try:
 
164
                        return self._all_children[name]
 
165
                except KeyError:
 
166
                        for child in self.iter_all_children():
 
167
                                if child == self:
 
168
                                        continue
 
169
                                try:
 
170
                                        return getattr(child, name)
 
171
                                except AttributeError:
 
172
                                        pass
 
173
                        raise AttributeError("'%s' object has no attribute '%s'" %(self.__class__.__name__, name))
 
174
        
 
175
        def _ensure_all_children (self):
 
176
                if self._all_children is not None : return
 
177
                self._all_children = dict()
 
178
                for child in self._children.itervalues():
 
179
                        child._visit(self._all_children)
 
180
        
 
181
        def _visit (self, dikt):
 
182
                dikt[self.name] = self
 
183
                for child in self._children.itervalues():
 
184
                        child._visit(dikt) 
 
185
 
59
186
        @property
60
187
        def uri(self):
61
 
                return self.__uri or self.name
62
 
        
 
188
                return self._uri or self.name
 
189
 
63
190
        @property
64
191
        def display_name(self):
65
 
                return self.__display_name or ""
66
 
        
 
192
                return self._display_name or ""
 
193
 
67
194
        @property
68
195
        def name(self):
69
 
                return self.__name
 
196
                return self._name
 
197
        __name__ = name
70
198
        
 
199
        def __dir__(self):
 
200
                self._ensure_all_children()
 
201
                return self._all_children.keys()
 
202
 
71
203
        @property
72
204
        def doc(self):
73
 
                return self.__doc or ""
74
 
                
 
205
                return self._doc or ""
 
206
 
75
207
        @property
76
208
        def __doc__(self):
77
209
                return "%s\n\n  %s. ``(Display name: '%s')``" %(self.uri, self.doc.rstrip("."), self.display_name)
78
 
 
79
 
 
80
 
class SymbolCollection(object):
81
 
        
82
 
        def __init__(self, name, doc=""):
83
 
                self.__name__ = name
84
 
                self.__doc__ = str(doc)
85
 
                self.__symbols = {}
86
 
        
87
 
        def register(self, name, uri, display_name, doc):
88
 
                if name in self.__symbols:
89
 
                        raise ValueError("Cannot register symbol %r, a definition for "
90
 
                                "this symbol already exists" % name)
91
 
                if not name.isupper():
92
 
                        raise ValueError("Cannot register %r, name must be uppercase" %name)
93
 
                self.__symbols[name] = Symbol(self.__name__, name, uri, display_name, doc)
94
 
        
95
 
        def __len__(self):
96
 
                return len(self.__symbols)
97
 
        
98
 
        def __getattr__(self, name):
99
 
                if not name in self.__symbols:
100
 
                        if not name.isupper():
101
 
                                # Symbols must be upper-case
102
 
                                raise AttributeError("%s has no attribute '%s'" % (
103
 
                                        self.__name__, name))
104
 
                        print "Unrecognized %s: %s" % (self.__name__, name)
105
 
                        self.__symbols[name] = Symbol(self.__name__, name)
106
 
                return self.__symbols[name]
107
 
        
108
 
        def __getitem__(self, uri):
109
 
                """ Get a symbol by its URI. """
110
 
                symbol = [s for s in self.__symbols.values() if s.uri == uri]
111
 
                if symbol:
112
 
                        return symbol[0]
113
 
                raise KeyError("Could not find symbol for URI: %s" % uri)
114
 
        
115
 
        def __iter__(self):
116
 
                return self.__symbols.itervalues()
117
 
        
118
 
        def __dir__(self):
119
 
                return self.__symbols.keys()
120
 
 
121
 
 
122
 
INTERPRETATION_ID = "interpretation"
123
 
MANIFESTATION_ID = "manifestation"
124
 
 
125
 
INTERPRETATION_DOC = \
126
 
"""In general terms the *interpretation* of an event or subject is an abstract
127
 
description of *"what happened"* or *"what is this"*.
128
 
 
129
 
Each interpretation type is uniquely identified by a URI. This class provides
130
 
a list of hard coded URI constants for programming convenience. In addition;
131
 
each interpretation instance in this class has a *display_name* property, which
132
 
is an internationalized string meant for end user display.
133
 
 
134
 
The interpretation types listed here are all subclasses of *str* and may be
135
 
used anywhere a string would be used."""
136
 
 
137
 
MANIFESTATION_DOC = \
138
 
"""The manifestation type of an event or subject is an abstract classification
139
 
of *"how did this happen"* or *"how does this item exist"*.
140
 
 
141
 
Each manifestation type is uniquely identified by a URI. This class provides
142
 
a list of hard coded URI constants for programming convenience. In addition;
143
 
each interpretation instance in this class has a *display_name* property, which
144
 
is an internationalized string meant for end user display.
145
 
 
146
 
The manifestation types listed here are all subclasses of *str* and may be
147
 
used anywhere a string would be used."""
148
 
 
149
 
 
150
 
Interpretation = SymbolCollection(INTERPRETATION_ID, doc=INTERPRETATION_DOC)
151
 
Manifestation = SymbolCollection(MANIFESTATION_ID, doc=MANIFESTATION_DOC)
152
 
 
153
 
#
154
 
# Interpretation categories
155
 
#
156
 
Interpretation.register(
157
 
        "TAG",
158
 
        u"http://www.semanticdesktop.org/ontologies/2007/08/15/nao#Tag",
159
 
        display_name=_("Tags"),
160
 
        doc="User provided tags. The same tag may refer multiple items"
161
 
)
162
 
Interpretation.register(
163
 
        "BOOKMARK",
164
 
        u"http://www.semanticdesktop.org/ontologies/nfo/#Bookmark",
165
 
        display_name=_("Bookmarks"),
166
 
        doc="A user defined bookmark. The same bookmark may only refer exectly one item"
167
 
)
168
 
Interpretation.register(
169
 
        "COMMENT",
170
 
        u"http://www.semanticdesktop.org/ontologies/2007/01/19/nie/#comment",
171
 
        display_name=_("Comments"),
172
 
        doc="User provided comment"
173
 
)
174
 
Interpretation.register(
175
 
        "DOCUMENT",
176
 
        u"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/#Document",
177
 
        display_name=_("Documents"),
178
 
        doc="A document, presentation, spreadsheet, or other content centric item"
179
 
)
180
 
Interpretation.register(
181
 
        "SOURCECODE",
182
 
        u"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/#ManifestationCode",
183
 
        display_name=_("Source Code"),
184
 
        doc="Code in a compilable or interpreted programming language."
185
 
)
186
 
Interpretation.register(
187
 
        "IMAGE",
188
 
        u"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/#Image",
189
 
        display_name=_("Images"),
190
 
        doc="A photography, painting, or other digital image"
191
 
)
192
 
Interpretation.register(
193
 
        "VIDEO",
194
 
        u"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/#Video",
195
 
        display_name=_("Videos"),
196
 
        doc="Any form of digital video, streaming and non-streaming alike"
197
 
)
198
 
Interpretation.register(
199
 
        "MUSIC",
200
 
        u"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo/#Audio",
201
 
        display_name=_("Music"),
202
 
        doc="Digital music or other creative audio work"
203
 
)
204
 
Interpretation.register(
205
 
        "EMAIL",
206
 
        u"http://www.semanticdesktop.org/ontologies/2007/03/22/nmo/#Email",
207
 
        display_name=_("Email"),
208
 
        doc="An email is an email is an email"
209
 
)
210
 
Interpretation.register(
211
 
        "IM_MESSAGE",
212
 
        u"http://www.semanticdesktop.org/ontologies/2007/03/22/nmo/#IMMessage",
213
 
        display_name=_("Messages"),
214
 
        doc="A message received from an instant messaging service"
215
 
)
216
 
Interpretation.register(
217
 
        "FEED_MESSAGE",
218
 
                u"http://www.tracker-project.org/temp/mfo#FeedMessage",
219
 
        display_name=_("Feeds"),
220
 
        doc="Any syndicated item, RSS, Atom, or other"
221
 
)
222
 
Interpretation.register(
223
 
        "BROADCAST_MESSAGE",
224
 
        u"http://zeitgeist-project.com/schema/1.0/core#BroadcastMessage",
225
 
        display_name=_("Broadcasts"), # FIXME: better display name
226
 
        doc="Small broadcasted message, like Twitter/Identica micro blogging (TBD in tracker)"
227
 
)
228
 
Interpretation.register(
229
 
        "CREATE_EVENT",
230
 
        u"http://zeitgeist-project.com/schema/1.0/core#CreateEvent",
231
 
        display_name=_("Created"),
232
 
        doc="Event type triggered when an item is created"
233
 
)
234
 
Interpretation.register(
235
 
        "MODIFY_EVENT",
236
 
        u"http://zeitgeist-project.com/schema/1.0/core#ModifyEvent",
237
 
        display_name=_("Modified"),
238
 
        doc="Event type triggered when an item is modified"
239
 
)
240
 
Interpretation.register(
241
 
        "VISIT_EVENT",
242
 
        u"http://zeitgeist-project.com/schema/1.0/core#VisitEvent",
243
 
        display_name=_("Visited"),
244
 
        doc="Event type triggered when an item is visited or opened"
245
 
)
246
 
Interpretation.register(
247
 
        "OPEN_EVENT",
248
 
        u"http://zeitgeist-project.com/schema/1.0/core#OpenEvent",
249
 
        display_name=_("Opened"),
250
 
        doc="Event type triggered when an item is visited or opened"
251
 
)
252
 
Interpretation.register(
253
 
        "SAVE_EVENT",
254
 
        u"http://zeitgeist-project.com/schema/1.0/core#SaveEvent",
255
 
        display_name=_("Saved"),
256
 
        doc="Event type triggered when an item is saved"
257
 
)
258
 
Interpretation.register(
259
 
        "CLOSE_EVENT",
260
 
        u"http://zeitgeist-project.com/schema/1.0/core#CloseEvent",
261
 
        display_name=_("Closed"),
262
 
        doc="Event type triggered when an item is closed"
263
 
)
264
 
Interpretation.register(
265
 
        "SEND_EVENT",
266
 
        u"http://zeitgeist-project.com/schema/1.0/core#SendEvent",
267
 
        display_name=_("Send"),
268
 
        doc="Event type triggered when the user sends/emails an item or message to a remote host"
269
 
)
270
 
Interpretation.register(
271
 
        "RECEIVE_EVENT",
272
 
        u"http://zeitgeist-project.com/schema/1.0/core#ReceiveEvent",
273
 
        display_name=_("Received"),
274
 
        doc="Event type triggered when the user has received an item from a remote host"
275
 
)
276
 
Interpretation.register(
277
 
        "FOCUS_EVENT",
278
 
        u"http://zeitgeist-project.com/schema/1.0/core#FocusEvent",
279
 
        display_name=_("Focused"),
280
 
        doc="Event type triggered when the user has switched focus to a new item"
281
 
)
282
 
Interpretation.register(
283
 
        "WARN_EVENT",
284
 
        u"http://zeitgeist-project.com/schema/1.0/core#WarnEvent",
285
 
        display_name=_("Warnings"),
286
 
        doc="Event type triggered when the user is warned about something"
287
 
)
288
 
Interpretation.register(
289
 
        "ERROR_EVENT",
290
 
        "http://zeitgeist-project.com/schema/1.0/core#ErrorEvent",
291
 
        display_name=_("Errors"),
292
 
        doc="Event type triggered when the user has encountered an error"
293
 
)
294
 
Interpretation.register(
295
 
        "APPLICATION",
296
 
                u"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Application",
297
 
        display_name=_("Applications"),
298
 
        doc="An item that is a launchable application. The item's URI must point to the relevant .desktop file"
299
 
)
300
 
Interpretation.register(
301
 
        "UNKNOWN",
302
 
        u"http://zeitgeist-project.com/schema/1.0/core#UnknownInterpretation",
303
 
        display_name=_("Unknown"),
304
 
        doc="An entity with an unknown interpretation"
305
 
)
306
 
 
307
 
#
308
 
# Manifestation categories
309
 
#
310
 
Manifestation.register(
311
 
        "WEB_HISTORY",
312
 
                u"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#WebHistory",
313
 
        display_name=_("Web History"),
314
 
        doc="An item that has been extracted from the user's browsing history"
315
 
)
316
 
Manifestation.register(
317
 
        "USER_ACTIVITY",
318
 
        u"http://zeitgeist-project.com/schema/1.0/core#UserActivity",
319
 
        display_name=_("Activities"),
320
 
        doc="An item that has been created solely on the basis of user actions and is not otherwise stored in some physical location"
321
 
)
322
 
Manifestation.register(
323
 
        "HEURISTIC_ACTIVITY",
324
 
        u"http://zeitgeist-project.com/schema/1.0/core#HeuristicActivity",
325
 
        display_name=_("Activities"),
326
 
        doc="An application has calculated via heuristics that some relationship is very probable."
327
 
)
328
 
Manifestation.register(
329
 
        "SCHEDULED_ACTIVITY",
330
 
        u"http://zeitgeist-project.com/schema/1.0/core#ScheduledActivity",
331
 
        display_name=_("Activities"), # FIXME: Is this a bad name?
332
 
        doc="An event that has been triggered by some long running task activated by the user. Fx. playing a song from a playlist"
333
 
)
334
 
Manifestation.register(
335
 
        "USER_NOTIFICATION",
336
 
        u"http://zeitgeist-project.com/schema/1.0/core#UserNotification",
337
 
        display_name=_("Notifications"),
338
 
        doc="An item that has been send as a notification to the user"
339
 
)
340
 
Manifestation.register(
341
 
        "FILE",
342
 
        u"http://www.semanticdesktop.org/ontologies/nfo/#FileDataObject",
343
 
        display_name=_("Files"),
344
 
        doc="An item stored on the local filesystem"
345
 
)
346
 
Manifestation.register(
347
 
        "SYSTEM_RESOURCE",
348
 
        u"http://freedesktop.org/standards/xesam/1.0/core#SystemRessource",
349
 
        display_name=_("System Resources"),
350
 
        doc="An item available through the host operating system, such as an installed application or manual page (TBD in tracker)"
351
 
)
352
 
Manifestation.register(
353
 
        "UNKNOWN",
354
 
        u"http://zeitgeist-project.com/schema/1.0/core#UnknownManifestation",
355
 
        display_name=_("Unknown"),
356
 
        doc="An entity with an unknown manifestation"
357
 
)
358
 
 
 
210
                
 
211
        def get_children(self):
 
212
                """
 
213
                Returns a list of immediate child symbols
 
214
                """
 
215
                return frozenset(self._children.itervalues())
 
216
                
 
217
        def iter_all_children(self):
 
218
                """
 
219
                Returns a generator that recursively iterates over all children
 
220
                of this symbol
 
221
                """
 
222
                yield self
 
223
                for child in self._children.itervalues():
 
224
                        for sub_child in child.iter_all_children():
 
225
                                yield sub_child
 
226
                
 
227
        def get_all_children(self):
 
228
                """
 
229
                Return a read-only set containing all children of this symbol
 
230
                """
 
231
                return frozenset(self.iter_all_children())
 
232
                
 
233
        def get_parents(self):
 
234
                """
 
235
                Returns a list of immediate parent symbols
 
236
                """
 
237
                return frozenset(self._parents.itervalues())
 
238
                
 
239
                
359
240
class TimeRange(list):
360
241
        """
361
242
        A class that represents a time range with a beginning and an end.
458
339
                return result
459
340
                
460
341
                
461
 
class enum_factory(object):
462
 
        """factory for enums"""
463
 
        counter = 0
464
 
        
465
 
        def __init__(self, doc):
466
 
                self.__doc__ = doc
467
 
                self._id = enum_factory.counter
468
 
                enum_factory.counter += 1
469
 
                
470
 
 
471
 
class EnumValue(int):
472
 
        """class which behaves like an int, but has an additional docstring"""
473
 
        def __new__(cls, value, doc=""):
474
 
                obj = super(EnumValue, cls).__new__(EnumValue, value)
475
 
                obj.__doc__ = "%s. ``(Integer value: %i)``" %(doc, obj)
476
 
                return obj
477
 
                
478
 
                
479
 
class EnumMeta(type):
480
 
        """Metaclass to register enums in correct order and assign interger
481
 
        values to them
482
 
        """
483
 
        def __new__(cls, name, bases, attributes):
484
 
                enums = filter(
485
 
                        lambda x: isinstance(x[1], enum_factory), attributes.iteritems()
486
 
                )
487
 
                enums = sorted(enums, key=lambda x: x[1]._id)
488
 
                for n, (key, value) in enumerate(enums):
489
 
                        attributes[key] = EnumValue(n, value.__doc__)
490
 
                return super(EnumMeta, cls).__new__(cls, name, bases, attributes)
491
 
                
492
 
                
493
 
class StorageState(object):
494
 
        """
495
 
        Enumeration class defining the possible values for the storage state
496
 
        of an event subject.
497
 
        
498
 
        The StorageState enumeration can be used to control whether or not matched
499
 
        events must have their subjects available to the user. Fx. not including
500
 
        deleted files, files on unplugged USB drives, files available only when
501
 
        a network is available etc.
502
 
        """
503
 
        __metaclass__ = EnumMeta
504
 
        
505
 
        NotAvailable = enum_factory(("The storage medium of the events "
506
 
                "subjects must not be available to the user"))
507
 
        Available = enum_factory(("The storage medium of all event subjects "
508
 
                "must be immediately available to the user"))
509
 
        Any = enum_factory("The event subjects may or may not be available")
510
 
 
511
 
 
512
 
class ResultType(object):
513
 
        """
514
 
        An enumeration class used to define how query results should be returned
515
 
        from the Zeitgeist engine.
516
 
        """
517
 
        __metaclass__ = EnumMeta
518
 
        
519
 
        MostRecentEvents = enum_factory("All events with the most recent events first")
520
 
        LeastRecentEvents = enum_factory("All events with the oldest ones first")
521
 
        MostRecentSubjects = enum_factory(("One event for each subject only, "
522
 
                "ordered with the most recent events first"))
523
 
        LeastRecentSubjects = enum_factory(("One event for each subject only, "
524
 
                "ordered with oldest events first"))
525
 
        MostPopularSubjects = enum_factory(("One event for each subject only, "
526
 
                "ordered by the popularity of the subject"))
527
 
        LeastPopularSubjects = enum_factory(("One event for each subject only, "
528
 
                "ordered ascendently by popularity"))
529
 
        MostPopularActor = enum_factory(("The last event of each different actor,"
530
 
                "ordered by the popularity of the actor"))
531
 
        LeastPopularActor = enum_factory(("The last event of each different actor,"
532
 
                "ordered ascendently by the popularity of the actor"))
533
 
        MostRecentActor = enum_factory(("The last event of each different actor"))
534
 
        LeastRecentActor = enum_factory(("The first event of each different actor"))
535
 
        
536
342
class RelevantResultType(object):
537
343
        """
538
344
        An enumeration class used to define how query results should be returned
543
349
        Recent = enum_factory("All uris with the most recent uri first")
544
350
        Related = enum_factory("All uris with the most related one first")
545
351
        
 
352
        
546
353
class Subject(list):
547
354
        """
548
355
        Represents a subject of an :class:`Event`. This class is both used to
982
789
This `NULL_EVENT` is used by the API to indicate a queried but not
983
790
available (not found or blocked) Event.
984
791
"""
 
792
                
 
793
                
 
794
class StorageState(object):
 
795
        """
 
796
        Enumeration class defining the possible values for the storage state
 
797
        of an event subject.
 
798
        
 
799
        The StorageState enumeration can be used to control whether or not matched
 
800
        events must have their subjects available to the user. Fx. not including
 
801
        deleted files, files on unplugged USB drives, files available only when
 
802
        a network is available etc.
 
803
        """
 
804
        __metaclass__ = EnumMeta
 
805
        
 
806
        NotAvailable = enum_factory(("The storage medium of the events "
 
807
                "subjects must not be available to the user"))
 
808
        Available = enum_factory(("The storage medium of all event subjects "
 
809
                "must be immediately available to the user"))
 
810
        Any = enum_factory("The event subjects may or may not be available")
 
811
 
 
812
 
 
813
class ResultType(object):
 
814
        """
 
815
        An enumeration class used to define how query results should be returned
 
816
        from the Zeitgeist engine.
 
817
        """
 
818
        __metaclass__ = EnumMeta
 
819
        
 
820
        MostRecentEvents = enum_factory("All events with the most recent events first")
 
821
        LeastRecentEvents = enum_factory("All events with the oldest ones first")
 
822
        MostRecentSubjects = enum_factory(("One event for each subject only, "
 
823
                "ordered with the most recent events first"))
 
824
        LeastRecentSubjects = enum_factory(("One event for each subject only, "
 
825
                "ordered with oldest events first"))
 
826
        MostPopularSubjects = enum_factory(("One event for each subject only, "
 
827
                "ordered by the popularity of the subject"))
 
828
        LeastPopularSubjects = enum_factory(("One event for each subject only, "
 
829
                "ordered ascendently by popularity"))
 
830
        MostPopularActor = enum_factory(("The last event of each different actor,"
 
831
                "ordered by the popularity of the actor"))
 
832
        LeastPopularActor = enum_factory(("The last event of each different actor,"
 
833
                "ordered ascendently by the popularity of the actor"))
 
834
        MostRecentActor = enum_factory(("The last event of each different actor"))
 
835
        LeastRecentActor = enum_factory(("The first event of each different actor"))
 
836
 
 
837
 
 
838
INTERPRETATION_DOC = \
 
839
"""In general terms the *interpretation* of an event or subject is an abstract
 
840
description of *"what happened"* or *"what is this"*.
 
841
 
 
842
Each interpretation type is uniquely identified by a URI. This class provides
 
843
a list of hard coded URI constants for programming convenience. In addition;
 
844
each interpretation instance in this class has a *display_name* property, which
 
845
is an internationalized string meant for end user display.
 
846
 
 
847
The interpretation types listed here are all subclasses of *str* and may be
 
848
used anywhere a string would be used.
 
849
 
 
850
Interpretations form a hierarchical type tree. So that fx. Audio, Video, and
 
851
Image all are sub types of Media. These types again have their own sub types,
 
852
like fx. Image has children Icon, Photo, and VectorImage (among others).
 
853
 
 
854
Templates match on all sub types, so that a query on subjects with
 
855
interpretation Media also match subjects with interpretations
 
856
Audio, Photo, and all other sub types of Media.
 
857
"""
 
858
 
 
859
MANIFESTATION_DOC = \
 
860
"""The manifestation type of an event or subject is an abstract classification
 
861
of *"how did this happen"* or *"how does this item exist"*.
 
862
 
 
863
Each manifestation type is uniquely identified by a URI. This class provides
 
864
a list of hard coded URI constants for programming convenience. In addition;
 
865
each interpretation instance in this class has a *display_name* property, which
 
866
is an internationalized string meant for end user display.
 
867
 
 
868
The manifestation types listed here are all subclasses of *str* and may be
 
869
used anywhere a string would be used.
 
870
 
 
871
Manifestations form a hierarchical type tree. So that fx. ArchiveItem,
 
872
Attachment, and RemoteDataObject all are sub types of FileDataObject.
 
873
These types can again have their own sub types.
 
874
 
 
875
Templates match on all sub types, so that a query on subjects with manifestation
 
876
FileDataObject also match subjects of types Attachment or ArchiveItem and all
 
877
other sub types of FileDataObject
 
878
"""
 
879
 
 
880
start_symbols = time.time()
 
881
 
 
882
Interpretation = Symbol("Interpretation", doc=INTERPRETATION_DOC)
 
883
Manifestation = Symbol("Manifestation", doc=MANIFESTATION_DOC)
 
884
_SYMBOLS_BY_URI["Interpretation"] = Interpretation
 
885
_SYMBOLS_BY_URI["Manifestation"] = Manifestation
 
886
 
 
887
if IS_LOCAL:
 
888
        try:
 
889
                execfile(os.path.join(runpath, "../extra/ontology/zeitgeist.py"))
 
890
        except IOError:
 
891
                raise ImportError("Unable to load zeitgeist ontology, "
 
892
                                  "please run `make` and try again.")
 
893
else:
 
894
        from zeitgeist import _config
 
895
        execfile(os.path.join(_config.datadir, "zeitgeist/ontology/zeitgeist.py"))
 
896
 
 
897
#
 
898
# Bootstrap the symbol relations. We use a 2-pass strategy:
 
899
#
 
900
# 1) Make sure that all parents and children are registered on each symbol
 
901
for symbol in _SYMBOLS_BY_URI.itervalues():
 
902
        for parent in symbol._parents:
 
903
                try:
 
904
                        _SYMBOLS_BY_URI[parent]._children[symbol.uri] = None
 
905
                except KeyError, e:
 
906
                        print "ERROR", e, parent, symbol.uri
 
907
                        pass
 
908
        for child in symbol._children:
 
909
                try:
 
910
                        _SYMBOLS_BY_URI[child]._parents.add(symbol.uri)
 
911
                except KeyError:
 
912
                        print "ERROR", e, child, symbol.uri
 
913
                        pass
 
914
 
 
915
# 2) Resolve all child and parent URIs to their actual Symbol instances
 
916
for symbol in _SYMBOLS_BY_URI.itervalues():
 
917
        for child_uri in symbol._children.iterkeys():
 
918
                symbol._children[child_uri] = _SYMBOLS_BY_URI[child_uri]
 
919
        
 
920
        parents = {}
 
921
        for parent_uri in symbol._parents:
 
922
                parents[parent_uri] = _SYMBOLS_BY_URI[parent_uri]
 
923
        symbol._parents = parents
 
924
 
 
925
 
 
926
if __name__ == "__main__":
 
927
        print "Success"
 
928
        end_symbols = time.time()
 
929
        print >> sys.stderr, "Import time: %s" % (end_symbols - start_symbols)
 
930
        #~ x = len(Interpretation.get_all_children())
 
931
        #~ y = len(Manifestation.get_all_children())
 
932
        #~ print >> sys.stderr, \
 
933
                #~ ("Overall number of symbols: %i (man.: %i, int.: %i)" %(x+y, y, x))
 
934
        #~ print >> sys.stderr, ("Resolved %i symbols, needed %i iterations" %(initial_count, initial_count-c))
 
935
        #~ print >> sys.stderr, ("Loading symbols took %.4f seconds" %(end_symbols - start_symbols))
 
936
        #~ #
 
937
        #~ # shortcuts
 
938
        #~ EventManifestation = Manifestation.EventManifestation
 
939
        #~ EventInterpretation = Interpretation.EventInterpretation
 
940
        #~ 
 
941
        #~ DataContainer = Interpretation.DataContainer
 
942
        #~ 
 
943
        #~ # testing
 
944
        #~ print dir(EventManifestation)
 
945
        #~ print dir(Manifestation)
 
946
        #~ print EventManifestation.UserActivity
 
947
        #~ 
 
948
        #~ print DataContainer
 
949
        #~ print DataContainer.Filesystem
 
950
        #~ print DataContainer.Filesystem.__doc__
 
951
        #~ 
 
952
        #~ print " OR ".join(DataContainer.get_all_children())
 
953
        #~ print " OR ".join(DataContainer.Filesystem.get_all_children())
 
954
        #~ 
 
955
        #~ print DataContainer.Boo
 
956
        #~ 
 
957
        #~ #Symbol("BOO", DataContainer) #must fail with ValueError
 
958
        #~ #Symbol("Boo", DataContainer) #must fail with ValueError
 
959
        #~ Symbol("Foo", set([DataContainer,]))
 
960
        #~ print DataContainer.Foo
 
961
        #~ 
 
962
        #~ #DataContainer._add_child("booo") #must fail with TypeError
 
963
        #~ 
 
964
        #~ print Interpretation
 
965
        #~ #print Interpretation.get_all_children()
 
966
        #~ import pprint
 
967
        #~ pprint.pprint(Interpretation.Software.get_all_children())
 
968
        #~ 
 
969
        #~ print Interpretation["http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#MindMap"]