Module ExampleModule
[hide private]

Source Code for Module ExampleModule

  1  """ 
  2  An Example DataSource and DataType implementation. 
  3  """ 
  4  import random 
  5  import logging 
  6  log = logging.getLogger("modules.Example") 
  7   
  8  import conduit 
  9  import conduit.Exceptions as Exceptions 
 10  import conduit.Utils as Utils 
 11  import conduit.datatypes.DataType as DataType 
 12  import conduit.dataproviders.DataProvider as DataProvider 
 13   
 14  MODULES = { 
 15      "ExampleDataProviderTwoWay" :   { "type": "dataprovider" }, 
 16      "ExampleConverter"          :   { "type": "converter" } 
 17  } 
 18   
19 -class ExampleDataProviderTwoWay(DataProvider.TwoWay):
20 """ 21 An example dataprovider demonstrating how to partition 22 funtionality in such a way 23 """ 24 25 _name_ = "Example Dataprovider" 26 _description_ = "Demonstrates a Twoway Dataprovider" 27 _category_ = conduit.dataproviders.CATEGORY_MISC 28 _module_type_ = "twoway" 29 _in_type_ = "exampledata" 30 _out_type_ = "exampledata" 31 _icon_ = "applications-internet" 32 33 DEFAULT_FOO_VALUE = 42 34
35 - def __init__(self):
36 """ 37 Constructor should call the base constructor and initialize 38 all variables that are restored from configuration 39 """ 40 DataProvider.TwoWay.__init__(self) 41 self.data = [] 42 self.foo = 0
43
44 - def _data_exists(self, LUID):
45 """ 46 @returns: True if data at the LUID exists 47 """ 48 return random.randint(0,1)
49
50 - def _get_data(self, LUID):
51 """ 52 @returns: A ExampleDataType with the specified LUID 53 """ 54 data = ExampleDataType( 55 uri=LUID, 56 data=self.foo*random.randint(1,100) 57 ) 58 return data
59
60 - def _put_data(self, data):
61 """ 62 @returns: Rid 63 """ 64 data = ExampleDataType( 65 uri=random.randint(1,100), 66 data=self.foo*random.randint(1,100) 67 ) 68 return data.get_rid()
69
70 - def _replace_data(self, LUID, data):
71 """ 72 Some dataproviders assign a new LUID when data is replaced. This 73 is the purpose of having replace in a different function to _put 74 """ 75 data.set_UID(random.randint(1,100)) 76 return data.get_rid()
77
78 - def configure(self, window):
79 """ 80 Uses the L{conduit.DataProvider.DataProviderSimpleConfigurator} class 81 to show a simple configuration dialog which is just a gtk.Enry 82 where the user can enter one or more GNOME wiki pages names, 83 seperated by commas 84 85 @param window: The parent window (used for modal dialogs) 86 @type window: C{gtk.Window} 87 """ 88 #lazy import gtk so if conduit is run from command line arg, or 89 #a non gtk system, this dp will still load. There should be no need 90 #to use gtk outside of this function 91 import gtk 92 import conduit.gtkui.SimpleConfigurator as SimpleConfigurator 93 94 def set_foo(param): 95 self.foo = int(param)
96 97 items = [ 98 { 99 "Name" : "Value of Foo:", 100 "Widget" : gtk.Entry, 101 "Callback" : set_foo, 102 "InitialValue" : str(self.foo) 103 } 104 ] 105 #We just use a simple configuration dialog 106 dialog = SimpleConfigurator.SimpleConfigurator(window, self._name_, items) 107 #This call blocks 108 dialog.run()
109
110 - def refresh(self):
111 """ 112 The refresh method should do whatever is needed to ensure that a 113 subseqent call to get_all returns the correct result. 114 115 The refresh method is always called before the sync step. DataSources 116 should always call the base classes refresh() method. 117 """ 118 DataProvider.TwoWay.refresh(self) 119 self.data = [str(random.randint(1,100)) for i in range(10)]
120
121 - def get_all(self):
122 """ 123 Returns the LUIDs of all items to synchronize. 124 DataSources should always call the base classes get_all() method 125 @return: A list of string LUIDs 126 """ 127 DataProvider.TwoWay.get_all(self) 128 return self.data
129
130 - def get(self, LUID):
131 """ 132 Returns the data identified by the supplied LUID. 133 @param LUID: A LUID which uniquely represents data to return 134 @type LUID: C{str} 135 """ 136 DataProvider.TwoWay.get(self, LUID) 137 data = self._get_data(LUID) 138 #datatypes can be shared between modules. For this reason it is 139 #necessary tp explicity set parameters like the LUID 140 data.set_UID(LUID) 141 data.set_open_URI("file:///home/") 142 return data
143
144 - def put(self, data, overwrite, LUID):
145 """ 146 @returns: The Rid of the page at location LUID 147 """ 148 DataProvider.TwoWay.put(self, data, overwrite, LUID) 149 #If LUID is None, then we have once-upon-a-time uploaded this data 150 if LUID != None: 151 #Check if the remote data exists (i.e. has it been deleted) 152 if self._data_exists(LUID): 153 #The remote page exists 154 if overwrite == False: 155 #Only replace the data if it is newer than the remote one 156 oldData = self._get_data(LUID) 157 comp = data.compare(oldData) 158 if comp == conduit.datatypes.COMPARISON_NEWER: 159 return self._replace_data(LUID, data) 160 elif comp == conduit.datatypes.COMPARISON_EQUAL: 161 #We are the same, so return either rid 162 return oldData.get_rid() 163 else: 164 #If we are older that the remote page, or if the two could not 165 #be compared, then we must ask the user what to do via a conflict 166 raise Exceptions.SynchronizeConflictError(comp, data, oldData) 167 168 #If we get here then the data is new 169 return self._put_data(data)
170
171 - def delete(self, LUID):
172 """ 173 Not all dataproviders support delete 174 """ 175 DataProvider.TwoWay.delete(self, LUID)
176
177 - def get_configuration(self):
178 """ 179 Returns a dict of key:value pairs. Key is the name of an internal 180 variable, and value is its current value to save. 181 182 It is important the the key is the actual name (minus the self.) of the 183 internal variable that should be restored when the user saves 184 their settings. 185 """ 186 return {"foo" : self.foo}
187
188 - def set_configuration(self, config):
189 """ 190 If you override this function then you are responsible for 191 checking the sanity of values in the config dict, including setting 192 any instance variables to sane defaults 193 """ 194 self.foo = config.get("foo",ExampleDataProviderTwoWay.DEFAULT_FOO_VALUE)
195
196 - def is_configured(self, isSource, isTwoWay):
197 """ 198 @returns: True if this instance has been correctly configured, and data 199 can be retrieved/stored into it 200 """ 201 return self.foo != 0
202
203 - def get_UID(self):
204 """ 205 @returns: A string uniquely representing this dataprovider. 206 """ 207 return "Example UID %s" % self.foo
208
209 -class ExampleDataType(DataType.DataType):
210 """ 211 A sample L{conduit.DataType.DataType} used to represent a page from 212 the GNOME wiki. 213 214 DataSources should try to used the supplied types (Note, File, etc) but 215 if they must define their own then this class shows how. 216 """ 217 218 _name_ = "exampledata" 219
220 - def __init__(self, uri, **kwargs):
221 """ 222 It is recommended to have compulsory parameters and then 223 kwargs as arguments to the constructor 224 """ 225 DataType.DataType.__init__(self) 226 self.data = kwargs.get("data",0)
227
228 - def __str__(self):
229 """ 230 The result of str may be shown to the user if there is a conflict. 231 It should represent a small descriptive snippet of the Datatype. 232 """ 233 return self.get_string()
234
235 - def get_hash(self):
236 """ 237 The hash should be able to detect if the data has been modified, irrespective 238 of the mtime - i.e. use the page contents directly 239 """ 240 return hash(self.data)
241
242 - def get_string(self):
243 return "string %d" % self.data
244
245 -class ExampleConverter:
246 """ 247 An example showing how to convert data from one type to another 248 249 If you define your own DataType then you should define one or more 250 converter (methods) for it, because it is likely that other DataSources, 251 such as the ones that ship with conduit will not know how to deal with 252 the new DataType. 253 254 @ivar self.conversions: A dictionary mapping conversions to functions 255 which perform the conversion 256 """
257 - def __init__(self):
258 """ 259 Fills out the required L{self.conversions} dict 260 261 Simply provide a list of conversions and associated functions 262 in the following formatt:: 263 264 self.conversions = { 265 "from_type_name,to_type_name" : convert_function 266 } 267 """ 268 self.conversions = { 269 "exampledata,file" : self.exampledata_to_file 270 }
271 272
273 - def exampledata_to_file(self, data, **kwargs):
274 """ 275 Converts exampledata to a file containing the text 276 """ 277 f = Utils.new_tempfile( 278 contents=data.get_string() 279 ) 280 return f
281