Source code for docker_leash.action_mapper

'''
Action
======
'''

import re
import urlparse

from ..exceptions import InvalidRequestException
from .routes import routes


[docs]class Action(object): ''' :var method: HTTP method used :var query: unparsed query :var name: parsed name (i.e.: containersList, imagesBuild, ...) :var version: API version call, if present :var querystring: parsed querystring :var namespace_name: (i.e.: containers, images, ...) ''' # raw data method = None query = None # one parsed name = None namespace_name = None version = None querystring = None _namespace_map = {} __namespace = None _r_parse = re.compile( r''' ^( (?:/v(?P<version>[0-9.]+))? (?P<unparsed>/.*?)? (?:[?](?P<qs>.*?))? (?:[#](?P<fragment>.*))? )$ ''', re.X ) def __init__(self, method, query): ''' :param str method: uppercase HTTP method of the request :param str query: path and optional query string :raise: InvalidRequestException ''' self.method = method self.query = query try: self._parse() except Exception as error: raise InvalidRequestException( error.message, )
[docs] def is_readonly(self): '''Can the action affect the state of a resource. :rtype: bool ''' return self.method in {'GET', 'HEAD'}
@property def namespace(self): '''Initialize and return a Namespace object when required :rtype: Namespace instance ''' if self.__namespace: return self.__namespace self.__namespace = self._namespace_map.get( self.namespace_name, Namespace, )(self) return self.__namespace
[docs] def _parse(self): ''' :raise: InvalidRequestException ''' try: result = self._r_parse.match(self.query).groupdict() except AttributeError: raise InvalidRequestException( 'unable to parse query: {}'.format(self.query) ) self.version = result['version'] if result['qs']: self.querystring = urlparse.parse_qs(result['qs']) try: result = routes.find(self.method, result['unparsed']) except ValueError as error: raise InvalidRequestException( 'unable to parse query: {}, error: {}'.format( self.query, error.message, ) ) self.namespace_name = result.namespace self.name = result.name
def __repr__(self): return 'Action({!r}, {!r})'.format( self.method, self.query, )
[docs] @classmethod def namespace_register(cls, arg): '''A decorator to register Namespace for a given namespace name If no namespace name is provided, it will be derivated from the class name. :param Action cls: :param arg: :type arg: str or Namespace instance ''' def register(obj): '''internal function for the decorator ''' assert arg not in cls._namespace_map cls._namespace_map[arg] = obj return obj if hasattr(arg, '__bases__'): arg, obj = arg.__name__.lower(), arg return register(obj) return register
[docs]class Namespace(object): '''Generic namespace :var action: link to (parent) action ''' action = None def __init__(self, action): '''Initialize the object ''' assert isinstance(action, Action) self.action = action
[docs]@Action.namespace_register('images') class Image(Namespace): '''Proof of concept for Namespace subclasses '''
[docs] def names(self): ''' :rtype: list or None ''' return self.action.querystring.get('names')