Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tutorius/uam/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'tutorius/uam/__init__.py')
-rw-r--r--tutorius/uam/__init__.py170
1 files changed, 134 insertions, 36 deletions
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