Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Vinet <vince.vinet@gmail.com>2009-10-26 20:24:02 (GMT)
committer Vincent Vinet <vince.vinet@gmail.com>2009-10-26 20:24:02 (GMT)
commit4755ddff4c490c22ada880a26225e8bd72805ffb (patch)
tree5fcb84a8a8fc5ef5664c716b08436616fc35afa7
parent704e35494433a11ecdcf675fff7cfccaa8bbd2ec (diff)
new UAM, archive it and forget itUAM
-rw-r--r--tests/uamtests.py23
-rw-r--r--tutorius/uam/__init__.py170
-rw-r--r--tutorius/uam/gobjectparser.py7
-rw-r--r--tutorius/uam/gtkparser.py18
4 files changed, 161 insertions, 57 deletions
diff --git a/tests/uamtests.py b/tests/uamtests.py
index b2a5901..d1b18c4 100644
--- a/tests/uamtests.py
+++ b/tests/uamtests.py
@@ -18,13 +18,13 @@
import unittest
-from sugar.tutorius.uam import parse_uri, SchemeError
+from sugar.tutorius.uam import URI, SchemeError
PARSE_SUITE={
#URI SCHEME HOST PARAMS PATH QUERY FRAGMENT
-"tap://act.tut.org/": ["tap", "act.tut.org","", "/", "", ""],
-"tap.gtk://a.t.o/0/1": ["tap.gtk","a.t.o","","/0/1","","",""],
-"tap.gobject://a.t.o/Timer?timeout=5":["tap.gobject","a.t.o","","/Timer","timeout=5",""],
+"tap://act.tut.org/": ["tap", "act.tut.org","", "/", dict(), ""],
+"tap.gtk://a.t.o/0/1": ["tap.gtk","a.t.o","","/0/1", dict(), ""],
+"tap.gobject://a.t.o/Timer?timeout=5":["tap.gobject","a.t.o","","/Timer",dict(timeout=["5"]),""],
}
class ParseUriTests(unittest.TestCase):
@@ -32,25 +32,26 @@ class ParseUriTests(unittest.TestCase):
def test_parse_uri(self):
"""Test parsing results"""
for uri, test in PARSE_SUITE.items():
- res = parse_uri(uri)
+ res = URI(uri)
+ assert res.uri == uri, "%s : Expected uri %s, got %s" % (uri, uri, res.uri)
assert res.scheme == test[0], "%s : Expected scheme %s, got %s" % (uri, test[0], res.scheme)
- assert res.netloc == test[1], "%s : Expected netloc %s, got %s" % (uri, test[1], res.netloc)
- assert res.params == test[2], "%s : Expected params %s, got %s" % (uri, test[2], res.params)
+ assert res.activity == test[1], "%s : Expected netloc %s, got %s" % (uri, test[1], res.netloc)
+ #Unused, assert res.params == test[2], "%s : Expected params %s, got %s" % (uri, test[2], res.params)
assert res.path == test[3], "%s : Expected path %s, got %s" % (uri, test[3], res.path)
- assert res.query == test[4], "%s : Expected query %s, got %s" % (uri, test[4], res.query)
- assert res.fragment == test[5], "%s : Expected fragment %s, got %s" % (uri, test[5], res.fragment)
+ assert res.query == test[4], "%s : Expected query %s, got %s" % (uri, test[4], str(res.query))
+ assert res.addon == test[5], "%s : Expected fragment %s, got %s" % (uri, test[5], res.fragment)
def test_errors(self):
"""Test exceptions"""
try:
- parse_uri("http://something.org/path")
+ URI("http://something.org/path")
assert False, "Parsing http should fail"
except SchemeError:
pass
try:
- parse_uri("tap.notarealsubscheme://something.org/path")
+ URI("tap.notarealsubscheme://something.org/path")
assert False, "Invalid Subscheme should fail"
except SchemeError:
pass
diff --git a/tutorius/uam/__init__.py b/tutorius/uam/__init__.py
index bcd67e1..babb1d8 100644
--- a/tutorius/uam/__init__.py
+++ b/tutorius/uam/__init__.py
@@ -18,22 +18,52 @@
Universal Addressing Mechanism module
Allows addressing Events, signals, widgets, etc for supported platforms
+
+Different subschemes must implement a parser in the form
+
+ from . import UAMParser
+
+ class MyParser(UAMParser):
+ @classmethod
+ def getAddon(self, uri):
+ ...
+
+ where getAddon accepts a single parameter which is a URI as defined here
+
+A base parser, UAMParser, should be sufficient for most uses
+The base parser will attempt to create any addon according to this uri format:
+
+<scheme>://<activity>/?<query>#<addon>
+
+where:
+
+<scheme> is the base scheme
+
+<activity> is the activity's dns identifier, such as battleship.tutorius.org
+
+<query> is a list of key=value attributes to pass to the constructor. If
+ multiple values are passed for the same key, the last one will prevail
+
+<addon> is the addon to use, and passed directly to addon.create()
"""
from urllib2 import urlparse
+from .. import addon
-import gtkparser
-import gobjectparser
+SCHEME="tap" #Tutorius Adressing Protocol
+_parsers = {}
-SCHEME="tap" #Tutorius Adressing Protocol
+def addParser(name, cls):
+ """ Reconfigure urlparse to accept an additional scheme
+ @param name schema to add
+ """
+ #Check if abstract. If so, ignore
+ if getattr(cls, "__abstract__", False):
+ return
-__parsers = {
- gtkparser.SCHEME:gtkparser.parse_gtk,
- gobjectparser.SCHEME:gobjectparser.parse_gobject,
-}
+ _parsers[name] = cls
-def __add_to_urlparse(name):
#Add to uses_netloc
if not name in urlparse.uses_netloc:
urlparse.uses_netloc.append(name)
@@ -42,9 +72,9 @@ def __add_to_urlparse(name):
if not name in urlparse.uses_relative:
urlparse.uses_relative.append(name)
-# #Add to uses_params
-# if not name in urlparse.uses_params:
-# urlparse.uses_params.append(name)
+ ##Add to uses_params
+ #if not name in urlparse.uses_params:
+ # urlparse.uses_params.append(name)
#Add to uses_query
if not name in urlparse.uses_query:
@@ -53,14 +83,59 @@ def __add_to_urlparse(name):
#Add to uses_frament
if not name in urlparse.uses_fragment:
urlparse.uses_fragment.append(name)
-
-
-#Add schemes to urlparse
-__add_to_urlparse(SCHEME)
-
-for subscheme in [".".join([SCHEME,s]) for s in __parsers]:
- __add_to_urlparse(subscheme)
+class UAMParserMeta(type):
+ """
+ UAM Parsers should have this as a Metaclass in order to
+ automatically register with urlparse.
+ """
+ def __new__(cls, name, bases, attrs):
+ """ Type pre-constructor
+ @param cls This metaclass
+ @param name name of the new class
+ @param bases list of bases for the new class
+ @param attrs dictionary of attributes
+ """
+ # Generate the scheme and subscheme if possible
+ #FIXME Keep the parent scheme if we don't have one?
+ if "__scheme__" in attrs:
+ scheme = attrs["__scheme__"]
+ for base in bases:
+ if hasattr(base, "__scheme__"):
+ scheme = getattr(base, "__scheme__") + "." + scheme
+ attrs["__scheme__"] = scheme
+ return type.__new__(cls, name, bases, attrs)
+
+ def __init__(cls, name, bases, attrs):
+ """ Type constructor
+ @param cls constructed class
+ @param name name of the new class
+ @param bases list of bases for the new class
+ @param attrs dictionary of attributes
+ """
+ if "__scheme__" in attrs:
+ #Register the parser in the module and urlparse
+ addParser(attrs["__scheme__"], cls)
+
+class UAMParser(object):
+ __metaclass__ = UAMParserMeta
+ __scheme__ = SCHEME
+ __abstract__ = False #Only there to show it exists
+
+ @classmethod
+ def getAddon(cls, uri):
+ """Parse an uri
+ @param uri URI object
+ """
+ params = UAMParser.stripQueryLists(uri.query)
+ return addon.create(uri.addon, **params)
+
+ @staticmethod
+ def stripQueryLists(querydict):
+ newdict = {}
+ for key, value in querydict.items():
+ newdict[key] = urlparse.unquote(value[-1])
+ return newdict
class SchemeError(Exception):
def __init__(self, message):
@@ -68,22 +143,45 @@ class SchemeError(Exception):
## Commenting this line as it is causing an error in the tests
##self.message = message
-
-def parse_uri(uri):
- res = urlparse.urlparse(uri)
-
- scheme = res.scheme.split(".")[0]
- subscheme = ".".join(res.scheme.split(".")[1:])
- if not scheme == SCHEME:
- raise SchemeError("Scheme %s not supported" % scheme)
-
- if subscheme != "" and not subscheme in __parsers:
- raise SchemeError("SubScheme %s not supported" % subscheme)
-
- if subscheme:
- return __parsers[subscheme](res)
-
- return res
-
-
+class ParserError(Exception):
+ pass
+
+class URI(object):
+ def __init__(self, uri):
+ self._uri = None
+ self._set_uri(uri)
+
+ def _get_uri(self):
+ return self._uri.geturl()
+ def _set_uri(self, uri):
+ if isinstance(uri, urlparse.ParseResult):
+ self._uri = uri
+ else:
+ self._uri = urlparse.urlparse(uri)
+ #Ensure we only use valid schemes
+ if self.scheme not in _parsers:
+ raise SchemeError("Scheme not supported: %s" % self.scheme)
+
+ uri = property(fset=_set_uri, fget=_get_uri)
+ activity = property(lambda self: self._uri.hostname)
+ scheme = property(lambda self: self._uri.scheme)
+ addon = property(lambda self: self._uri.fragment)
+ path = property(lambda self: self._uri.path)
+ #params = property(lambda self: urlparse.parse_qs(self._uri.params))
+ def _get_querydict(self):
+ return urlparse.parse_qs(self._uri.query)
+ query = property(_get_querydict)
+
+ #Serialization functions
+ def __getstate__(self):
+ return dict(uri=self.uri)
+ def __setstate__(self, state):
+ self.uri = state["uri"]
+
+ def getAddon(self):
+ return _parsers[self.scheme].getAddon(self)
+
+#Import the different parsers that we know about
+import gtkparser
+import gobjectparser
diff --git a/tutorius/uam/gobjectparser.py b/tutorius/uam/gobjectparser.py
index c1fba3d..767b5ea 100644
--- a/tutorius/uam/gobjectparser.py
+++ b/tutorius/uam/gobjectparser.py
@@ -19,9 +19,8 @@ UAM Parser for gobject subscheme
To be completed
"""
+from . import UAMParser
-SCHEME="gobject"
+class GObjectParser(UAMParser):
+ __scheme__ = "gobject"
-def parse_gobject(parsed_uri):
- """Do nothing for now"""
- return parsed_uri
diff --git a/tutorius/uam/gtkparser.py b/tutorius/uam/gtkparser.py
index ede2f03..3da852a 100644
--- a/tutorius/uam/gtkparser.py
+++ b/tutorius/uam/gtkparser.py
@@ -25,8 +25,6 @@ The gtk subscheme for tutorius is
where:
-<scheme> is the uam.SCHEME + "." + SCHEME
-
<activity> is the activity's dns identifier, such as battleship.tutorius.org
<path> is the Hierarchical path to the widget, where 0 is the activity, such as /0/0/1/0/1/0
@@ -36,9 +34,17 @@ where:
<ptype> must be used with params to specify which action or eventfilter to use, such as "DialogMessage"
"""
+from . import UAMParser, addon
+
-SCHEME="gtk"
+class GtkParser(UAMParser):
+ __scheme__ = "gtk"
-def parse_gtk(parsed_uri):
- """Do nothing for now"""
- return parsed_uri
+ @classmethod
+ def getAddon(cls, uri):
+ """Parse an uri
+ @param uri URI object
+ """
+ params = UAMParser.stripQueryLists(uri.query)
+ path = uri.path.replace("/",".")
+ return addon.create(uri.addon, object_id=uri.path, **params)