# Copyright (C) 2009, Tutorius.org # Copyright (C) 2009, Vincent Vinet # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ 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: :///?# where: is the base scheme is the activity's dns identifier, such as battleship.tutorius.org 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 is the addon to use, and passed directly to addon.create() """ from urllib2 import urlparse from .. import addon SCHEME="tap" #Tutorius Adressing Protocol _parsers = {} 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[name] = cls #Add to uses_netloc if not name in urlparse.uses_netloc: urlparse.uses_netloc.append(name) #Add to uses_relative 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_query if not name in urlparse.uses_query: urlparse.uses_query.append(name) #Add to uses_frament if not name in urlparse.uses_fragment: urlparse.uses_fragment.append(name) 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): Exception.__init__(self, message) ## Commenting this line as it is causing an error in the tests ##self.message = message 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