conduit r1286 - in trunk: . doc



Author: jstowers
Date: Thu Feb  7 11:19:07 2008
New Revision: 1286
URL: http://svn.gnome.org/viewvc/conduit?rev=1286&view=rev

Log:
2008-02-08  John Stowers  <john stowers gmail com>

	* doc/ExampleModule.py: Make the example dataprovider twoway and 
	more exemplary and remove the live.gnome.org xmlrpc business because
	thats broken with the new moinmoin version anyway.

2008-02-07  Thomas Van Machelen <thomas vanmachelen gmail com>
	* conduit/data/conduit.glade: Make the Conflict	Preferences a bit 


Modified:
   trunk/ChangeLog
   trunk/doc/ExampleModule.py

Modified: trunk/doc/ExampleModule.py
==============================================================================
--- trunk/doc/ExampleModule.py	(original)
+++ trunk/doc/ExampleModule.py	Thu Feb  7 11:19:07 2008
@@ -1,7 +1,9 @@
 """
 An Example DataSource and DataType implementation.
 """
-import xmlrpclib
+import random
+import logging
+log = logging.getLogger("modules.Example")
 
 import conduit
 import conduit.Exceptions as Exceptions
@@ -10,48 +12,69 @@
 import conduit.dataproviders.DataProvider as DataProvider
 
 MODULES = {
-    "MoinMoinDataSource" :  { "type": "dataprovider" },
-    "WikiPageConverter" :   { "type": "converter" }
+    "ExampleDataProviderTwoWay" :   { "type": "dataprovider" },
+    "ExampleConverter"          :   { "type": "converter" }
 }
 
-class MoinMoinDataSource(DataProvider.DataSource):
+class ExampleDataProviderTwoWay(DataProvider.TwoWay):
     """
-    This datasource fetches pages from the GNOME wiki.
-    DataSources are presumed to be one-way, that is they are a source
-    of data and should implement the get() and get_num_items() methods
-
-    @ivar self.pages: A array of page names
-    @type self.pages: C{string}[]
+    An example dataprovider demonstrating how to partition
+    funtionality in such a way
     """
 
-    WIKI_ADDRESS = "http://live.gnome.org/";
-
-    _name_ = "GNOME Wiki"
-    _description_ = "Get Pages from the GNOME Wiki"
-    _category_ = conduit.dataproviders.CATEGORY_FILES
-    _module_type_ = "source"
-    _in_type_ = "wikipage"
-    _out_type_ = "wikipage"
+    _name_ = "Example Dataprovider"
+    _description_ = "Demonstrates a Twoway Dataprovider"
+    _category_ = conduit.dataproviders.CATEGORY_MISC
+    _module_type_ = "twoway"
+    _in_type_ = "exampledata"
+    _out_type_ = "exampledata"
     _icon_ = "applications-internet"
 
+    DEFAULT_FOO_VALUE = 42
+
     def __init__(self):
         """
-        A DataSource constructor should call the base constructor with 
-        three arguments
-         1. The name of the datasource
-         2. A short description
-         3. An icon name
-        The name and description are typically the same values as specified
-        in the MODULES dict at the top of the file
+        Constructor should call the base constructor and initialize
+        all variables that are restored from configuration
         """
-        DataProvider.DataSource.__init__(self)
+        DataProvider.TwoWay.__init__(self)
+        self.data = []
+        self.foo = 0
+
+    def _data_exists(self, LUID):
+        """
+        @returns: True if data at the LUID exists
+        """
+        return random.randint(0,1)
+
+    def _get_data(self, LUID):
+        """
+        @returns: A ExampleDataType with the specified LUID
+        """
+        data = ExampleDataType(
+                        uri=LUID,
+                        data=self.foo*random.randint(1,100)
+                        )
+        return data
+
+    def _put_data(self, data):
+        """
+        @returns: Rid
+        """
+        data = ExampleDataType(
+                        uri=random.randint(1,100),
+                        data=self.foo*random.randint(1,100)
+                        )
+        return data.get_rid()
+
+    def _replace_data(self, LUID, data):
+        """
+        Some dataproviders assign a new LUID when data is replaced. This
+        is the purpose of having replace in a different function to _put
+        """
+        data.set_UID(random.randint(1,100))
+        return data.get_rid()
 
-        conduit.log("Hello World!")
-        
-        #class specific
-        self.srcwiki = None
-        self.pages = []
-        
     def configure(self, window):
         """
         Uses the L{conduit.DataProvider.DataProviderSimpleConfigurator} class
@@ -68,18 +91,15 @@
         import gtk
         import conduit.gtkui.SimpleConfigurator as SimpleConfigurator
         
-        def set_pages(param):
-            self.pages = param.split(',')
+        def set_foo(param):
+            self.foo = int(param)
         
-        #Make the list into a comma seperated string for display
-        pageString = ",".join(self.pages)
-        #Define the items in the configure dialogue
         items = [
                     {
-                    "Name" : "Page Name to Synchronize:",
+                    "Name" : "Value of Foo:",
                     "Widget" : gtk.Entry,
-                    "Callback" : set_pages,
-                    "InitialValue" : pageString
+                    "Callback" : set_foo,
+                    "InitialValue" : str(self.foo)
                     }                    
                 ]
         #We just use a simple configuration dialog
@@ -90,31 +110,22 @@
     def refresh(self):
         """
         The refresh method should do whatever is needed to ensure that a 
-        subseuent call to get_num_items returns the correct result.
+        subseqent call to get_all returns the correct result.
 
         The refresh method is always called before the sync step. DataSources 
-        should always call the base classes refresh() method
+        should always call the base classes refresh() method.
         """
-        DataProvider.DataSource.refresh(self)
-        if self.srcwiki is None:
-            try:
-                #use_datetime tells xmlrpc to return python datetime objects
-                #for the page modification date
-                self.srcwiki = xmlrpclib.ServerProxy(
-                                            uri="http://live.gnome.org/?action=xmlrpc2";,
-                                            use_datetime=True
-                                            )
-            except:
-                raise Exceptions.RefreshError
+        DataProvider.TwoWay.refresh(self)
+        self.data = [str(random.randint(1,100)) for i in range(10)]
 
     def get_all(self):
         """
         Returns the LUIDs of all items to synchronize.        
         DataSources should always call the base classes get_all() method
+        @return: A list of string LUIDs
         """
-        DataProvider.DataSource.get_all(self)
-        #the LUID for the page is its full url    
-        return [MoinMoinDataSource.WIKI_ADDRESS+p for p in self.pages]
+        DataProvider.TwoWay.get_all(self)
+        return self.data
             
     def get(self, LUID):
         """
@@ -122,29 +133,46 @@
         @param LUID: A LUID which uniquely represents data to return
         @type LUID: C{str}
         """
-        DataProvider.DataSource.get(self, LUID)
-
-        #recover the page name from the full LUID string
-        pagename = LUID.replace(MoinMoinDataSource.WIKI_ADDRESS,"")
-
-        #get the page meta info, name, modified, etc
-        pageinfo = self.srcwiki.getPageInfo(pagename)
+        DataProvider.TwoWay.get(self, LUID)
+        data = self._get_data(LUID)
+        #datatypes can be shared between modules. For this reason it is
+        #necessary tp explicity set parameters like the LUID
+        data.set_UID(LUID)
+        data.set_open_URI("file:///home/")
+        return data
+
+    def put(self, data, overwrite, LUID):
+        """
+        @returns: The Rid of the page at location LUID
+        """
+        DataProvider.TwoWay.put(self, data, overwrite, LUID)
+        #If LUID is None, then we have once-upon-a-time uploaded this data
+        if LUID != None:
+            #Check if the remote data exists (i.e. has it been deleted)
+            if self._data_exists(LUID):
+                #The remote page exists
+                if overwrite == False:
+                    #Only replace the data if it is newer than the remote one
+                    oldData = self._get_data(LUID)
+                    comp = data.compare(oldData)
+                    if comp == conduit.datatypes.COMPARISON_NEWER:
+                        return self._replace_data(LUID, data)
+                    elif comp == conduit.datatypes.COMPARISON_EQUAL:
+                        #We are the same, so return either rid
+                        return oldData.get_rid()
+                    else:
+                        #If we are older that the remote page, or if the two could not
+                        #be compared, then we must ask the user what to do via a conflict
+                        raise Exceptions.SynchronizeConflictError(comp, data, oldData)
 
-        #Make a new page data type
-        page = WikiPageDataType(
-                            uri=LUID,
-                            name=pageinfo["name"],
-                            modified=pageinfo["lastModified"],
-                            contents=self.srcwiki.getPage(pagename)
-                            )
+        #If we get here then the data is new
+        return self._put_data(data)
 
-        #datatypes can be shared between modules. For this reason it is
-        #always good to explicity set parameters like the LUID
-        #even though in this case (we are the only one using the wikipage datatype)
-        #they are set in the constructor of the dataype itself
-        page.set_UID(LUID)
-        page.set_open_URI(LUID)
-        return page
+    def delete(self, LUID):
+        """
+        Not all dataproviders support delete
+        """
+        DataProvider.TwoWay.delete(self, LUID)
             
     def get_configuration(self):
         """
@@ -155,73 +183,66 @@
         internal variable that should be restored when the user saves
         their settings. 
         """
-        return {"pages" : self.pages}
+        return {"foo" : self.foo}
+
+    def set_configuration(self, config):
+        """
+        If you override this function then you are responsible for 
+        checking the sanity of values in the config dict, including setting
+        any instance variables to sane defaults
+        """
+        self.foo = config.get("foo",ExampleDataProviderTwoWay.DEFAULT_FOO_VALUE)
+
+    def is_configured(self, isSource, isTwoWay):
+        """
+        @returns: True if this instance has been correctly configured, and data
+        can be retrieved/stored into it
+        """
+        return self.foo != 0
 
     def get_UID(self):
         """
         @returns: A string uniquely representing this dataprovider.
         """
-        return MoinMoinDataSource.WIKI_ADDRESS
+        return "Example UID %s" % self.foo
         
-class WikiPageDataType(DataType.DataType):
+class ExampleDataType(DataType.DataType):
     """
     A sample L{conduit.DataType.DataType} used to represent a page from
     the GNOME wiki.
 
     DataSources should try to used the supplied types (Note, File, etc) but
     if they must define their own then this class shows how. 
-
-    @ivar self.contents: The raw HTML page contents
-    @type self.contents: C{string}
-    @ivar self.name: The page name
-    @type self.name: C{string}
-    @ivar self.modified: The date the page was modified
-    @type self.modified: C{string}
     """
     
-    _name_ = "wikipage"
+    _name_ = "exampledata"
 
     def __init__(self, uri, **kwargs):
         """
-        Derived DataTypes should always call the base constructor 
-        with a string represting the name of the new datatype.
-
-        This name shoud should correspond to that specified in the MODULES dict
+        It is recommended to have compulsory parameters and then
+        kwargs as arguments to the constructor
         """
         DataType.DataType.__init__(self)
-                            
-        #Instance variables
-        self.contents = kwargs.get("contents","")
-        self.name = kwargs.get("name", "")
-        self.modified = kwargs.get("modified",None)
-
-        #In the constructor of datatypes remember to call the following
-        #base constructor functions. This allows certain information to be
-        #preserved through conversions and comparison
-        self.set_open_URI(uri)
-        self.set_mtime(self.modified)
+        self.data = kwargs.get("data",0)
 
-    def get_wikipage_string(self):
+    def __str__(self):
         """
-        Returns the raw HTML for the page
+        The result of str may be shown to the user if there is a conflict.
+        It should represent a small descriptive snippet of the Datatype.
         """
-        return self.contents
+        return self.get_string()
 
-    def get_wikipage_name(self):
+    def get_hash(self):
         """
-        Returns the page name
+        The hash should be able to detect if the data has been modified, irrespective
+        of the mtime - i.e. use the page contents directly
         """
-        return self.name
+        return hash(self.data)
 
-    def __str__(self):
-        """
-        The result of str may be shown to the user. It should represent a
-        small descriptive snippet of the Datatype. It does not necessarily need
-        to be the entire raw textual representation of the data
-        """
-        return self.name
-        
-class WikiPageConverter:
+    def get_string(self):
+        return "string %d" % self.data
+
+class ExampleConverter:
     """
     An example showing how to convert data from one type to another
     
@@ -230,12 +251,6 @@
     such as the ones that ship with conduit will not know how to deal with
     the new DataType.
 
-    The absolute minimum is to define a conversion to text as this will make
-    one way sync with most datasinks possible. This conversion will generally
-    lose information so in general it is better to define many conversion
-    functions so that as much information is preserved when the data is
-    passed to the sunsequent DataSink
-
     @ivar self.conversions: A dictionary mapping conversions to functions
     which perform the conversion
     """
@@ -251,18 +266,16 @@
                                 }
         """
         self.conversions =  {    
-                            "wikipage,file"   : self.wikipage_to_file
+                            "exampledata,file"   : self.exampledata_to_file
                             }
                             
 
-    def wikipage_to_file(self, page, **kwargs):
+    def exampledata_to_file(self, data, **kwargs):
         """
-        The conversion function for converting wikipages to raw text. Does
-        not do anythong particuarly smart.
+        Converts exampledata to a file containing the text
         """
         f = Utils.new_tempfile(
-                        contents=page.get_wikipage_string()
+                        contents=data.get_string()
                         )
-        f.force_new_filename(page.get_wikipage_name())
         return f
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]