source: orange-bioinformatics/obiGenomicsUpdate.py @ 550:6c1db8e91f12

Revision 550:6c1db8e91f12, 7.0 KB checked in by ales_erjavec <ales.erjavec@…>, 5 years ago (diff)
Line 
1from __future__ import with_statement
2import os
3import shelve
4import datetime
5import tarfile
6import pickle
7import orngServerFiles
8from UserDict import DictMixin
9
10class UpdateShelve(DictMixin):
11    def __init__(self, path):
12        self.__shelve = shelve.open(path)
13
14    def __expand(self, (func, args)):
15        return func.im_class, func.__name__, args
16
17    def __collapse(self, (class_, funcname, args)):
18        return getattr(class_, funcname), args
19
20    def __dumps(self, arg):
21        return pickle.dumps(self.__expand(arg))
22
23    def __loads(self, arg):
24        return self.__collapse(pickle.loads(arg))
25       
26    def __getitem__(self, arg):
27        return self.__shelve.__getitem__(self.__dumps(arg))
28
29    def __setitem__(self, arg, val):
30        self.__shelve.__setitem__(self.__dumps(arg), val)
31
32    def __delitem__(self, arg):
33        self.__shelve.__delitem__(self.__dumps(arg))
34
35    def keys(self):
36        return [self.__loads(key) for key in self.__shelve.keys()]
37
38    def __contains__(self, arg):
39        return self.__shelve.__contains__(self.__dumps(arg))
40
41    def __iter__(self):
42        for key in self.__shelve:
43            yield self.__loads(key)
44
45    def iteritems(self):
46        for key, val in self.__shelve.iteritems():
47            yield self.__loads(key), val
48
49    def sync(self):
50        self.__shelve.sync()
51           
52from threading import Lock
53from functools import wraps
54
55def synchronized(lock):
56    def syncfunc(func):
57        @wraps(func)
58        def f(*args, **kwargs):
59            with lock:
60                return func(*args, **kwargs)
61        return f
62    return syncfunc
63
64from datetime import datetime
65
66class Update(object):
67    def __init__(self, local_database_path, progressCallback=None):
68        """Base update object.
69        Each obi module that uses updatable resources should subclass this class and at minimum reimplement
70        the IsUpdatable and GetDownloadable methods.
71        """
72        self.local_database_path = local_database_path
73        self.progressCallback = progressCallback
74        import os
75        try:
76            os.mkdir(self.local_database_path)
77        except:
78            pass
79        self.shelve = UpdateShelve(os.path.join(self.local_database_path, ".updates.shelve"))
80
81    def IsUpdatable(self, *args):
82        """Return True if the local can be updated else return False
83        """
84        raise NotImplementedError
85   
86    def GetLocal(self):
87        """Return a list [(callable, args), ...] that have been called in the past.
88        """
89        return self.shelve.keys()
90   
91    def GetUpdatable(self):
92        """Return a list [(callable, args), ...] that can be updated.
93        """
94        return [item for item in self.GetLocal() if self.IsUpdatable(*item)]
95       
96    def GetDownloadable(self):
97        """Return a list [(callable, args), ...] that can be downloaded. Must no contain any
98        (callable, args) that are returnd by GetLocal.
99        """
100        raise NotImplementedError
101   
102    def GetLastUpdateTime(self, callable, args):
103        """Returns the last update time of callable with args.
104        """
105        return self.shelve.get((callable, args), datetime(1,1,1))
106
107    def _update(self, callable, args, date=None):
108        """Insert the record of update with date. if date is None use the current date.
109        """
110        self.shelve[callable, args] = date if date else datetime.now()
111        self.shelve.sync()
112
113import orngServerFiles
114
115class PKGUpdate(Update):
116    def __init__(self, domain, wrappedUpdater, *args, **kwargs):
117        """Wrap the subclass of Update to download data as packages from our own server.
118        Arguments:
119            - domain : should be a string that identifies a resource e.g. "kegg", "go" ...
120            - wrappedUpdater : instance of a subclass of Update that is wrapped
121        Example:
122        >>> pkg = PKGUpdate("go", obiGO.Update())
123        >>> for item in pkg.GetUpdatable():
124        ...     pkg.Apply(*item)
125        ...
126        >>>
127        """
128        Update.__init__(self, wrappedUpdater.local_database_path, wrappedUpdater.progressCallback)
129        self.domain = domain
130        self.serverFiles = orngServerFiles.ServerFiles()
131        self.wrappedUpdater = wrappedUpdater
132        self.wrappedUpdaterClass = wrappedUpdater.__class__
133
134    def _GetServerFileName(self, func, args):
135        return func.__name__+ ("_" + str(args) if args else "") + ".tar.gz"
136
137    def _GetServerDateTime(self, *args):
138        time = self.serverFiles.info(self.domain, self._GetServerFileName(*args))["datetime"].split(".")[0]
139        return datetime.strptime(time, "%Y-%m-%d %H:%M:%S")
140   
141    def IsUpdatable(self, *args):
142        try:
143            return args in self.shelve and self.GetLastUpdateTime(*args) < self._GetServerDateTime(*args)
144        except Exception:
145            return False
146       
147    def GetDownloadable(self):
148        files = self.serverFiles.listfiles(self.domain)
149        downloadable = []
150        for filename in files:
151            if "_" in filename:
152                funcname, args = filename.split("_",1)
153                args = args.split(".")[0]
154                args = eval(args) 
155            else:
156                funcname, args = filename.split(".")[0], ()
157            downloadable.append((getattr(self.wrappedUpdaterClass, funcname), args))
158        return [item for item in downloadable if item not in self.shelve]
159
160    def UpdateWrapper(self, func):
161        @wraps(func)
162        def update(*args):
163            filename = self._GetServerFileName(func, args)
164            time = self._GetServerDateTime(func, args)
165            orngServerFiles.download(self.domain, filename)
166            filepath = orngServerFiles.localpath(self.domain, filename)
167            tar = tarfile.open(filepath)
168            tar.extractall(self.local_database_path)
169            self._update(func, args, time)
170        return update
171
172    def Apply(self, func, args):
173        """Use this method to apply a return values of GetUpdatable ... which are unwrapped
174        """
175        if func.im_class == type(self):
176            return func(self, *args)
177        else:
178            return getattr(self, func.__name__)(*args)
179           
180    def __getattr__(self, name):
181        try:
182            return self.UpdateWrapper(getattr(self.wrappedUpdaterClass, name))
183        except AttributeError:
184            raise AttributeError(name)
185
186def firstUpdateConsole():
187    import obiKEGG, obiGO, obiGenomicsUpdate
188
189    pkgUpdate = obiGenomicsUpdate.PKGUpdate("go", obiGO.Update())
190
191    print "Updating GO ontology"
192    pkgUpdate.UpdateOntology()
193
194    for org, name in [("goa_human", "Homo sapiens"), ("sgd", "Yeast")]:
195        print "Updating GO anotations for", name
196        pkgUpdate.UpdateAnnotation(org)
197
198    pkgUpdate = obiGenomicsUpdate.PKGUpdate("kegg", obiKEGG.Update())
199
200    print "Updating KEGG taxonomy"
201    pkgUpdate.UpdateTaxonomy()
202
203    print "Updating KEGG orthology"
204    pkgUpdate.UpdateOrthology()
205
206    print "Updating KEGG reference pathways"
207    pkgUpdate.UpdateReference()
208
209    for org, name in [("hsa", "Homo sapiens"), ("sce", "Yeast")]:
210        print "Updating KEGG pathways for", name
211        pkgUpdate.UpdateOrganism(org)
212   
213
214def firstUpdateQt():
215    pass
216   
Note: See TracBrowser for help on using the repository browser.