コード例 #1
0
 def testAssign(self):
     a = AttributeDictionary()
     a['ciao'] = 5
     self.assertEqual(a.ciao, 5)
     self.assertEqual(a['ciao'], 5)
     self.assertEqual(list(a.values()), [5])
     self.assertEqual(list(a.items()), [('ciao', 5)])
コード例 #2
0
ファイル: routers.py プロジェクト: japaks/pulsar
 def __init__(self, rule, *routes, **parameters):
     Router._creation_count += 1
     self._creation_count = Router._creation_count
     if not isinstance(rule, Route):
         rule = Route(rule)
     self.route = rule
     self._name = parameters.pop('name', rule.rule)
     self.routes = []
     for router in routes:
         self.add_child(router)
     # copy parameters
     self.parameters = AttributeDictionary(self.parameters)
     for name, rule_method in self.rule_methods.items():
         rule, method, params, _, _ = rule_method
         rparameters = params.copy()
         handler = getattr(self, name)
         if rparameters.pop('async', False):  # asynchronous method
             handler = async ()(handler)
             handler.rule_method = rule_method
         router = self.add_child(Router(rule, **rparameters))
         setattr(router, method, handler)
     for name, value in parameters.items():
         if name in self.parameters:
             self.parameters[name] = value
         else:
             setattr(self, name, value)
コード例 #3
0
ファイル: structures.py プロジェクト: BazookaShao/pulsar
 def testAssign(self):
     a = AttributeDictionary()
     a['ciao'] = 5
     self.assertEqual(a.ciao, 5)
     self.assertEqual(a['ciao'], 5)
     self.assertEqual(list(a.values()), [5])
     self.assertEqual(list(a.items()), [('ciao',5)])
コード例 #4
0
ファイル: backends.py プロジェクト: victor3rc/lux
 def get_session(self, request, key):
     session = request.app.cache_server.get_json(self._key(key))
     if session:
         session = AttributeDictionary(session)
         if session.user_id:
             session.user = self.get_user(request, user_id=session.user_id)
         return session
コード例 #5
0
 def items(self, request):
     cms = request.app.cms
     for item in cms.all(request, self.name):
         html_url = request.absolute_uri(item['path'])
         if html_url.endswith('/index'):
             html_url = html_url[:-6]
         page = AttributeDictionary(loc=html_url,
                                    lastmod=item.get('modified'))
         if cms.set_priority:
             page.priority = item.get('priority', 1)
         yield page
コード例 #6
0
ファイル: backends.py プロジェクト: victor3rc/lux
 def session_create(self, request, id=None, user=None, expiry=None):
     '''Create a new session
     '''
     if not id:
         id = uuid.uuid4().hex
     session = AttributeDictionary(id=id)
     if expiry:
         session.expiry = expiry.isoformat()
     if user:
         session.user_id = user.id
         session.user = user
     return session
コード例 #7
0
ファイル: contents.py プロジェクト: pvanderlinden/lux
 def __init__(self, app, content, metadata, path, src=None, **params):
     self._app = app
     self._content = content
     self._path = path
     self._src = src
     self._meta = AttributeDictionary(params)
     self._update_meta(metadata)
     if not self._meta.modified:
         if src:
             self._meta.modified = modified_datetime(src)
         else:
             self._meta.modified = datetime.now()
     self._meta.name = slugify(self._path, separator='_')
コード例 #8
0
 def process_request(self, request):
     from django.http import HttpResponse
     data = AttributeDictionary(request.__dict__)
     environ = data.pop('environ')
     environ['django.cache'] = data
     response = self._web_socket(environ, None)
     if response is not None:
         # Convert to django response
         if is_failure(response):
             response.throw()
         resp = HttpResponse(status=response.status_code,
                             content_type=response.content_type)
         for header, value in response.headers:
             resp[header] = value
         return resp
コード例 #9
0
ファイル: views.py プロジェクト: xmnlab/minilab
 def process_request(self, request):
     from django.http import HttpResponse
     data = AttributeDictionary(request.__dict__)
     environ = data.pop('environ')
     environ['django.cache'] = data
     response = self._web_socket(environ, None)
     if response is not None:
         # Convert to django response
         if is_failure(response):
             response.throw()
         resp = HttpResponse(status=response.status_code,
                             content_type=response.content_type)
         for header, value in response.headers:
             resp[header] = value
         return resp
コード例 #10
0
 def __test_pickle(self):
     # TODO: this fails at times
     a = AttributeDictionary()
     a['ciao'] = 5
     b = pickle.dumps(a)
     c = pickle.loads(b)
     self.assertEqual(a, c)
コード例 #11
0
ファイル: routers.py プロジェクト: BazookaShao/pulsar
 def __init__(self, rule, *routes, **parameters):
     Router._creation_count += 1
     self._creation_count = Router._creation_count
     if not isinstance(rule, Route):
         rule = Route(rule)
     self.route = rule
     self._name = parameters.pop('name', rule.rule)
     self.routes = []
     for router in routes:
         self.add_child(router)
     # copy parameters
     self.parameters = AttributeDictionary(self.parameters)
     for name, rule_method in self.rule_methods.items():
         rule, method, params, _, _ = rule_method
         rparameters = params.copy()
         handler = getattr(self, name)
         if rparameters.pop('async', False):  # asynchronous method
             handler = async()(handler)
             handler.rule_method = rule_method
         router = self.add_child(Router(rule, **rparameters))
         setattr(router, method, handler)
     for name, value in parameters.items():
         if name in self.parameters:
             self.parameters[name] = value
         else:
             setattr(self, name, value)
コード例 #12
0
 def __init__(self, environ, name=None):
     self.environ = environ
     if 'pulsar.cache' not in environ:
         environ['pulsar.cache'] = AttributeDictionary()
         self.cache.mixins = {}
     if name:
         self.cache.mixins[name] = self
コード例 #13
0
ファイル: views.py プロジェクト: pvanderlinden/lux
 def items(self, request):
     for index, map in enumerate(self.cms.sitemaps):
         if not index:
             continue
         url = request.absolute_uri(str(map.route))
         _, last_modified = map.sitemap(request)
         yield AttributeDictionary(loc=url, lastmod=last_modified)
コード例 #14
0
 def items(self, request):
     middleware = request.app._handler.middleware
     for map in middleware:
         if isinstance(map, RouterMap):
             url = request.absolute_uri(str(map.route))
             _, last_modified = map.sitemap(request)
             yield AttributeDictionary(loc=url, lastmod=last_modified)
コード例 #15
0
 def __init__(self, url, version=None, data=None,
              full_response=False, **kw):
     self.__url = url
     self.__version = version or self.__class__.default_version
     self._full_response = full_response
     self.__data = data if data is not None else {}
     self.local = AttributeDictionary()
     self.setup(**kw)
コード例 #16
0
ファイル: result.py プロジェクト: japaks/pulsar
 def before_test_function_run(self, test):
     '''Called before the test run, in the test process domain.'''
     test.plugins = plugins = {}
     for p in self.plugins:
         local = AttributeDictionary()
         plugins[p.name] = local
         test = p.before_test_function_run(test, local) or test
     return test
コード例 #17
0
ファイル: wrappers.py プロジェクト: ZhHong/pulsar
 def __init__(self, environ, name=None):
     self.environ = environ
     if pulsar_cache not in environ:
         environ[pulsar_cache] = AttributeDictionary()
         self.cache.mixins = {}
         self.cache.logger = LOGGER
     if name:
         self.cache.mixins[name] = self
コード例 #18
0
    def init_parameters(self, tag=None, **parameters):
        '''Called at the and of initialisation.

        It fills the :attr:`parameters` attribute.
        It can be overwritten to customise behaviour.
        '''
        self.tag = tag or self.tag
        self.parameters = AttributeDictionary(parameters)
コード例 #19
0
 def before_test_function_run(self, test):
     '''Called just before the test is run'''
     test.plugins = plugins = {}
     for p in self.plugins:
         local = AttributeDictionary()
         plugins[p.name] = local
         test = p.before_test_function_run(test, local) or test
     return test
コード例 #20
0
ファイル: jsonrpc.py プロジェクト: ilmiacs/pulsar
 def __init__(self, url, name=None, version=None, id=None, data=None,
              **kwargs):
     self.__url = url
     self.__name = name
     self.__version = version or self.__class__.default_version
     self.__id = id
     self.__data = data if data is not None else {}
     self.local = AttributeDictionary()
     self.setup(**kwargs)
コード例 #21
0
    def inner_html(self, request, page, self_comp=''):
        '''Build page html content using json layout.
        :param layout: json (with rows and components) e.g.
            layout = {
                'rows': [
                    {},
                    {cols: ['col-md-6', 'col-md-6']},
                    {cols: ['col-md-6', 'col-md-6']}
                ],
                'components': [
                    {'type': 'text', 'id': 1, 'row': 0, 'col': 0, 'pos': 0},
                    {'type': 'gallery', 'id': 2, 'row': 1, 'col': 1, 'pos': 0}
                ]
            }
        :return: raw html
            <div class="row">
                <div class="col-md-6">
                    <render-component id="1" text></render-component>
                </div>
                <div class="col-md-6"></div>
            </div>
            <div class="row">
                    <div class="col-md-6"></div>
                    <div class="col-md-6">
                        <render-component id="2" gallery></render-component>
                    </div>
            </div>
        '''
        layout = page.layout
        if layout:
            try:
                layout = json.loads(layout)
            except Exception:
                request.app.logger.exception('Could not parse layout')
                layout = None

        if not layout:
            layout = dict(rows=[{}])

        components = layout.get('components') or []
        if not components:
            components.append(dict(type='self'))

        inner = Html(None)

        # Loop over rows
        for row_idx, row in enumerate(layout.get('rows', ())):
            row = AttributeDictionary(row)
            if row.cols:
                html = self._row(row, components, self_comp)
            else:
                html = self._component(components[0], self_comp)
                html = super().inner_html(request, page, html)

            inner.append(html)

        return inner.render(request)
コード例 #22
0
ファイル: contents.py プロジェクト: pvanderlinden/lux
 def __init__(self, app, content, metadata, path, src=None, **params):
     self._app = app
     self._content = content
     self._path = path
     self._src = src
     self._meta = AttributeDictionary(params)
     self._update_meta(metadata)
     if not self._meta.modified:
         if src:
             self._meta.modified = modified_datetime(src)
         else:
             self._meta.modified = datetime.now()
     self._meta.name = slugify(self._path, separator='_')
コード例 #23
0
ファイル: contents.py プロジェクト: tourist/lux
 def __init__(self, app, content, metadata, src, path=None, context=None,
              **params):
     self._app = app
     self._content = content
     self._context_for = context
     self._additional_context = {}
     self._src = src
     self._path = path or src
     self._meta = AttributeDictionary(params)
     if src:
         self._meta.modified = modified_datetime(src)
     else:
         self._meta.modified = datetime.now()
     # Get the site meta data dictionary.
     # Used to render Content metadata
     self._update_meta(metadata)
     meta = self._meta
     if self.is_html:
         dir, slug = os.path.split(self._path)
         if not slug:
             slug = self._path
             dir = None
         if not meta.slug:
             meta.slug = slugify(slug, separator='_')
         if dir:
             meta.slug = '%s/%s' % (dir, meta.slug)
     else:
         if self.suffix:  # Any other file
             suffix = '.%s' % self.suffix
             if not self._path.endswith(suffix):
                 self._path = self._path + suffix
         if not meta.slug:
             meta.slug = self._path
     meta.name = slugify(meta.slug, separator='_')
     for name in self.mandatory_properties:
         if not meta.get(name):
             raise BuildError("Property '%s' not available in %s"
                              % (name, self))
コード例 #24
0
ファイル: routers.py プロジェクト: azazel75/pulsar
 def __init__(self, rule, *routes, **parameters):
     Router._creation_count += 1
     self._creation_count = Router._creation_count
     if not isinstance(rule, Route):
         rule = Route(rule)
     self._route = rule
     self._name = parameters.pop('name', rule.name)
     self.routes = []
     # add routes specified via the initialiser first
     for router in routes:
         self.add_child(router)
     # copy parameters
     self.parameters = AttributeDictionary(self.parameters)
     for name, rule_method in self.rule_methods.items():
         rule, method, params, _, _ = rule_method
         rparameters = params.copy()
         handler = getattr(self, name)
         router = self.add_child(self.make_router(rule, **rparameters))
         setattr(router, method, handler)
     for name, value in parameters.items():
         if name in self.parameters:
             self.parameters[name] = value
         else:
             setattr(self, slugify(name, separator='_'), value)
コード例 #25
0
ファイル: routers.py プロジェクト: huobao36/pulsar
 def __init__(self, rule, *routes, **parameters):
     Router._creation_count += 1
     self._creation_count = Router._creation_count
     if not isinstance(rule, Route):
         rule = Route(rule)
     self._route = rule
     self._name = parameters.pop('name', rule.rule)
     self.routes = []
     # add routes specified via the initialiser
     for router in routes:
         self.add_child(router)
     # copy parameters
     self.parameters = AttributeDictionary(self.parameters)
     for name, rule_method in self.rule_methods.items():
         rule, method, params, _, _ = rule_method
         rparameters = params.copy()
         handler = getattr(self, name)
         router = self.add_child(Router(rule, **rparameters))
         setattr(router, method, handler)
     for name, value in parameters.items():
         if name in self.parameters:
             self.parameters[name] = value
         else:
             setattr(self, name, value)
コード例 #26
0
ファイル: routers.py プロジェクト: imclab/pulsar
class Router(RouterType('RouterBase', (object,), {})):
    '''A :ref:`WSGI middleware <wsgi-middleware>` to handle client requests
    on multiple :ref:`routes <apps-wsgi-route>`.

    The user must implement the HTTP methods
    required by the application. For example if the route needs to
    serve a ``GET`` request, the ``get(self, request)`` method must
    be implemented.

    :param rule: String used for creating the :attr:`route` of this
        :class:`Router`.
    :param routes: Optional :class:`Router` instances which are added to the
        children :attr:`routes` of this router.
    :param parameters: Optional parameters for this router.
        They are stored in the :attr:`parameters` attribute with the
        exception of :attr:`response_content_types` and
        :attr:`response_wrapper`

    .. attribute:: rule_methods

        A class attribute built during class creation. It is an ordered
        dictionary mapping method names with a five-elements tuple
        containing information
        about a child route (See the :class:`.route` decorator).

    .. attribute:: routes

        List of children :class:`Router` of this :class:`Router`.

    .. attribute:: parent

        The parent :class:`Router` of this :class:`Router`.

    .. attribute:: response_content_types

        A list/tuple of possible content types of a response to a
        client request.

        The client request must accept at least one of the response content
        types, otherwise an HTTP ``415`` exception occurs.

    .. attribute:: response_wrapper

        Optional function which wraps all handlers of this :class:`.Router`.
        The function must accept two parameters, the original handler
        and the :class:`.WsgiRequest`::

            def response_wrapper(handler, request):
                ...
                return handler(request)

    .. attribute:: parameters

        A :class:`.AttributeDictionary` of parameters for
        this :class:`Router`. Parameters are created at initialisation from
        the ``parameters`` class attribute and the key-valued parameters
        passed to the ``__init__`` method which are available in the
        class ``parameters`` attribute.
    '''
    _creation_count = 0
    _parent = None
    _name = None

    response_content_types = RouterParam(None)
    response_wrapper = RouterParam(None)

    def __init__(self, rule, *routes, **parameters):
        Router._creation_count += 1
        self._creation_count = Router._creation_count
        if not isinstance(rule, Route):
            rule = Route(rule)
        self._route = rule
        self._name = parameters.pop('name', rule.name)
        self.routes = []
        # add routes specified via the initialiser first
        for router in routes:
            self.add_child(router)
        # copy parameters
        self.parameters = AttributeDictionary(self.parameters)
        for name, rule_method in self.rule_methods.items():
            rule, method, params, _, _ = rule_method
            rparameters = params.copy()
            handler = getattr(self, name)
            router = self.add_child(self.make_router(rule, **rparameters))
            setattr(router, method, handler)
        for name, value in parameters.items():
            if name in self.parameters:
                self.parameters[name] = value
            else:
                setattr(self, slugify(name, separator='_'), value)

    @property
    def route(self):
        '''The relative :class:`.Route` served by this
        :class:`Router`.
        '''
        parent = self._parent
        if parent and parent._route.is_leaf:
            return parent.route + self._route
        else:
            return self._route

    @property
    def full_route(self):
        '''The full :attr:`route` for this :class:`.Router`.

        It includes the :attr:`parent` portion of the route if a parent
        router is available.
        '''
        if self._parent:
            return self._parent.full_route + self._route
        else:
            return self._route

    @property
    def name(self):
        '''The name of this :class:`Router`.

        This attribute can be specified during initialisation.
        If available, it can be used to retrieve a child router
        by name via the :meth:`get_route` method.
        '''
        return self._name

    @property
    def root(self):
        '''The root :class:`Router` for this :class:`Router`.'''
        if self.parent:
            return self.parent.root
        else:
            return self

    @property
    def parent(self):
        return self._parent

    @property
    def creation_count(self):
        '''Integer for sorting :class:`Router` by creation.

        Auto-generated during initialisation.'''
        return self._creation_count

    @property
    def rule(self):
        '''The full ``rule`` string for this :class:`Router`.

        It includes the :attr:`parent` portion of the rule if a :attr:`parent`
        router is available.
        '''
        return self.full_route.rule

    def path(self, **urlargs):
        '''The full path of this :class:`Router`.

        It includes the :attr:`parent` portion of url if a parent router
        is available.
        '''
        return self.full_route.url(**urlargs)

    def getparam(self, name, default=None):
        '''A parameter in this :class:`.Router`
        '''
        try:
            return getattr(self, name)
        except AttributeError:
            return default

    def __getattr__(self, name):
        '''Check the value of a :attr:`parameters` ``name``.

        If the parameter is not available, retrieve the parameter from the
        :attr:`parent` :class:`Router` if it exists.
        '''
        if not name.startswith('_'):
            return self._get_router_parameter(name, False)
        self._no_param(name)

    def content_type(self, request):
        '''Evaluate the content type for the response to a client ``request``.

        The method uses the :attr:`response_content_types` parameter of
        accepted content types and the content types accepted by the client
        ``request`` and figures out the best match.
        '''
        response_content_types = self.response_content_types
        request_content_types = request.content_types
        if request_content_types:
            ct = request_content_types.best_match(response_content_types)
            if ct and '*' in ct:
                ct = None
            if not ct and response_content_types:
                raise HttpException(status=415, msg=request_content_types)
            return ct

    def __repr__(self):
        return self.route.__repr__()

    def __call__(self, environ, start_response=None):
        path = environ.get('PATH_INFO') or '/'
        path = path[1:]
        router_args = self.resolve(path)
        if router_args:
            router, args = router_args
            return router.response(environ, args)

    def resolve(self, path, urlargs=None):
        '''Resolve a path and return a ``(handler, urlargs)`` tuple or
        ``None`` if the path could not be resolved.
        '''
        match = self.route.match(path)
        if match is None:
            if not self.route.is_leaf:  # no match
                return
        elif '__remaining__' in match:
            path = match.pop('__remaining__')
            urlargs = update_args(urlargs, match)
        else:
            return self, update_args(urlargs, match)
        #
        for handler in self.routes:
            view_args = handler.resolve(path, urlargs)
            if view_args is None:
                continue
            return view_args

    def response(self, environ, args):
        '''Once the :meth:`resolve` method has matched the correct
        :class:`Router` for serving the request, this matched router invokes
        this method to produce the WSGI response.
        '''
        request = wsgi_request(environ, self, args)
        request.response.content_type = self.content_type(request)
        method = request.method.lower()
        callable = getattr(self, method, None)
        if callable is None:
            raise HttpException(status=405)
        response_wrapper = self.response_wrapper
        if response_wrapper:
            return response_wrapper(callable, request)
        return callable(request)

    def add_child(self, router):
        '''Add a new :class:`Router` to the :attr:`routes` list.
        '''
        assert isinstance(router, Router), 'Not a valid Router'
        assert router is not self, 'cannot add self to children'
        #
        # Remove from previous parent
        if router.parent:
            router.parent.remove_child(router)
        router._parent = self
        # Loop over available routers to check it the router
        # is already available
        for r in self.routes:
            if r.route == router.route:
                r.parameters.update(router.parameters)
                return r
        self.routes.append(router)
        return router

    def remove_child(self, router):
        '''remove a :class:`Router` from the :attr:`routes` list.'''
        if router in self.routes:
            self.routes.remove(router)
            router._parent = None

    def get_route(self, name):
        '''Get a child :class:`Router` by its :attr:`name`.

        This method search child routes recursively.
        '''
        for route in self.routes:
            if route.name == name:
                return route
        for child in self.routes:
            route = child.get_route(name)
            if route:
                return route

    def link(self, *args, **urlargs):
        '''Return an anchor :class:`Html` element with the `href` attribute
        set to the url of this :class:`Router`.'''
        if len(args) > 1:
            raise ValueError
        url = self.route.url(**urlargs)
        if len(args) == 1:
            text = args[0]
        else:
            text = url
        return Html('a', text, href=url)

    def has_parent(self, router):
        '''Check if ``router`` is ``self`` or a parent or ``self``
        '''
        parent = self
        while parent and parent is not router:
            parent = parent._parent
        return parent is not None

    def make_router(self, rule, cls=None, **params):
        '''Create a new :class:`.Router` from a ``rule`` and parameters.

        This method is used during initialisation when building child
        Routers from the :attr:`rule_methods`.
        '''
        cls = cls or Router
        return cls(rule, **params)

    def _no_param(self, name):
        raise AttributeError("'%s' object has no attribute '%s'" %
                             (self.__class__.__name__, name))

    def _get_router_parameter(self, name, safe=True):
        value = self.parameters.get(name)
        if value is None:
            if self._parent:
                return self._parent._get_router_parameter(name, safe)
            elif name in self.parameters:
                return value
            elif not safe:
                self._no_param(name)
        else:
            return value
コード例 #27
0
ファイル: routers.py プロジェクト: japaks/pulsar
class Router(RouterType('RouterBase', (object, ), {})):
    '''A :ref:`WSGI middleware <wsgi-middleware>` to handle client requests
on multiple :ref:`routes <apps-wsgi-route>`.

The user must implement the HTTP methods
required by the application. For example if the route needs to serve a ``GET``
request, the ``get(self, request)`` method must be implemented.

:param rule: String used for creating the :attr:`route` of this
    :class:`Router`.
:param routes: Optional :class:`Router` instances which are added to the
    children :attr:`routes` of this router.
:param parameters: Optional parameters for this router. They are stored in the
    :attr:`parameters` attribute. If a ``response_content_types`` value is
    passed, it overrides the :attr:`response_content_types` attribute.

.. attribute:: route

    The :ref:`Route <apps-wsgi-route>` served by this :class:`Router`.

.. attribute:: routes

    List of children :class:`Router` of this :class:`Router`.

.. attribute:: parent

    The parent :class:`Router` of this :class:`Router`.

.. attribute:: response_content_types

    a list/tuple of possible content types of a response to a client request.

    The client request must accept at least one of the response content
    types, otherwise an HTTP ``415`` exception occurs.

.. attribute:: parameters

    A :class:`.AttributeDictionary` of parameters for
    this :class:`Router`. Parameters are created at initialisation from
    the ``parameters`` class attribute and the key-valued parameters
    passed to the ``__init__`` method for which the value is not callable.
'''
    _creation_count = 0
    _parent = None
    _name = None

    response_content_types = RouterParam(None)

    def __init__(self, rule, *routes, **parameters):
        Router._creation_count += 1
        self._creation_count = Router._creation_count
        if not isinstance(rule, Route):
            rule = Route(rule)
        self.route = rule
        self._name = parameters.pop('name', rule.rule)
        self.routes = []
        for router in routes:
            self.add_child(router)
        # copy parameters
        self.parameters = AttributeDictionary(self.parameters)
        for name, rule_method in self.rule_methods.items():
            rule, method, params, _, _ = rule_method
            rparameters = params.copy()
            handler = getattr(self, name)
            if rparameters.pop('async', False):  # asynchronous method
                handler = async ()(handler)
                handler.rule_method = rule_method
            router = self.add_child(Router(rule, **rparameters))
            setattr(router, method, handler)
        for name, value in parameters.items():
            if name in self.parameters:
                self.parameters[name] = value
            else:
                setattr(self, name, value)

    @property
    def name(self):
        '''The name of this :class:`Router`.

        This attribute can be specified during initialisation.
        If available, it can be used to retrieve a child router
        by name via the :meth:`get_route` method.
        '''
        return self._name

    @property
    def root(self):
        '''The root :class:`Router` for this :class:`Router`.'''
        if self.parent:
            return self.parent.root
        else:
            return self

    @property
    def parent(self):
        return self._parent

    @property
    def default_content_type(self):
        '''The default content type for responses. This is the first element
in the :attr:`response_content_types` list.'''
        ct = self.response_content_types
        return ct[0] if ct else None

    @property
    def creation_count(self):
        '''Integer for sorting :class:`Router` by creation.

        Auto-generated during initialisation.'''
        return self._creation_count

    @property
    def full_route(self):
        '''The full :attr:`route` for this :class:`Router`. It includes the
:attr:`parent` portion of the route if a parent router is available.'''
        route = self.route
        if self._parent:
            route = self._parent.route + route
        return route

    @property
    def rule(self):
        '''The full ``rule`` string for this :class:`Router`. It includes the
:attr:`parent` portion of rule if a parent router is available.'''
        return self.full_route.rule

    def path(self, **urlargs):
        '''The full path of this :class:`Router`. It includes the
:attr:`parent` portion of url if a parent router is available.'''
        route = self.route
        if self._parent:
            route = self._parent.route + route
        return route.url(**urlargs)

    def __getattr__(self, name):
        '''Check the value of a :attr:`parameters` ``name``.

        If the parameter is not available, retrieve the parameter from the
        :attr:`parent` :class:`Router` if it exists.
        '''
        if not name.startswith('_'):
            return self.get_parameter(name, False)
        self.no_param(name)

    def get_parameter(self, name, safe=True):
        value = self.parameters.get(name)
        if value is None:
            if self._parent:
                return self._parent.get_parameter(name, safe)
            elif name in self.parameters:
                return value
            elif not safe:
                self.no_param(name)
        else:
            return value

    def no_param(self, name):
        raise AttributeError("'%s' object has no attribute '%s'" %
                             (self.__class__.__name__, name))

    def content_type(self, request):
        '''Evaluate the content type for the response to a client ``request``.

        The method uses the :attr:`response_content_types` parameter of
        accepted content types and the content types accepted by the client
        and figure out the best match.
        '''
        response_content_types = self.response_content_types
        if response_content_types:
            return request.content_types.best_match(response_content_types)

    def accept_content_type(self, content_type):
        '''Check if ``content_type`` is accepted by this :class:`Router`.

        Return the best mach or ``None`` if not accepted.'''
        response_content_types = self.response_content_types
        if response_content_types:
            return ContentAccept([(content_type, 1)
                                  ]).best_match(response_content_types)

    def __repr__(self):
        return self.route.__repr__()

    def __call__(self, environ, start_response=None):
        path = environ.get('PATH_INFO') or '/'
        path = path[1:]
        router_args = self.resolve(path)
        if router_args:
            router, args = router_args
            return router.response(environ, args)
        else:
            if self.route.is_leaf:
                if path.endswith('/'):
                    router_args = self.resolve(path[:-1])
                    if router_args is not None:
                        return self.redirect(environ, '/%s' % path[:-1])
            else:
                if not path.endswith('/'):
                    router_args = self.resolve('%s/' % path)
                    if router_args is not None:
                        return self.redirect(environ, '/%s/' % path)

    def resolve(self, path, urlargs=None):
        '''Resolve a path and return a ``(handler, urlargs)`` tuple or
``None`` if the path could not be resolved.'''
        urlargs = urlargs if urlargs is not None else {}
        match = self.route.match(path)
        if match is None:
            return
        if '__remaining__' in match:
            remaining_path = match['__remaining__']
            for handler in self.routes:
                view_args = handler.resolve(remaining_path, urlargs)
                if view_args is None:
                    continue
                #remaining_path = match.pop('__remaining__','')
                #urlargs.update(match)
                return view_args
        else:
            return self, match

    @async (get_result=True)
    def response(self, environ, args):
        '''Once the :meth:`resolve` method has matched the correct
:class:`Router` for serving the request, this matched router invokes
this method to produce the WSGI response.'''
        request = wsgi_request(environ, self, args)
        # Set the response content type
        request.response.content_type = self.content_type(request)
        method = request.method.lower()
        callable = getattr(self, method, None)
        if callable is None:
            raise HttpException(status=405,
                                msg='Method "%s" not allowed' % method)
        # make sure cache does not contain asynchronous data
        async_cache = multi_async(request.cache, raise_on_error=False)
        cache = yield async_cache
        if async_cache.num_failures:
            for key, value in list(cache.items()):
                if isinstance(value, Failure):
                    cache.pop(key)
            environ['pulsar.cache'] = cache
            yield async_cache.failures
        else:
            environ['pulsar.cache'] = cache
            yield callable(request)

    @async (get_result=True)
    def redirect(self, environ, path):
        request = wsgi_request(environ, self)
        environ['pulsar.cache'] = yield multi_async(request.cache)
        raise HttpRedirect(path)

    def add_child(self, router):
        '''Add a new :class:`Router` to the :attr:`routes` list. If this
:class:`Router` is a leaf route, add a slash to the url.'''
        assert isinstance(router, Router), 'Not a valid Router'
        assert router is not self, 'cannot add self to children'
        if self.route.is_leaf:
            self.route = Route('%s/' % self.route.rule)
        for r in self.routes:
            if r.route == router.route:
                r.parameters.update(router.parameters)
                return r
        if router.parent:
            router.parent.remove_child(router)
        router._parent = self
        self.routes.append(router)
        return router

    def remove_child(self, router):
        '''remove a :class:`Router` from the :attr:`routes` list.'''
        if router in self.routes:
            self.routes.remove(router)
            router._parent = None

    def get_route(self, name):
        '''Get a child :class:`Router` by its :attr:`name`.'''
        for route in self.routes:
            if route.name == name:
                return route

    def link(self, *args, **urlargs):
        '''Return an anchor :class:`Html` element with the `href` attribute
set to the url of this :class:`Router`.'''
        if len(args) > 1:
            raise ValueError
        url = self.route.url(**urlargs)
        if len(args) == 1:
            text = args[0]
        else:
            text = url
        return Html('a', text, href=url)

    def sitemap(self, root=None):
        '''This utility method returns a sitemap starting at root.
If *root* is ``None`` it starts from this :class:`Router`.

:param request: a :ref:`wsgi request wrapper <app-wsgi-request>`
:param root: Optional url path where to start the sitemap.
    By default it starts from this :class:`Router`. Pass `"/"` to
    start from the root :class:`Router`.
:param levels: Number of nested levels to include.
:return: A list of children
'''
        if not root:
            root = self
        else:
            handler_urlargs = self.root.resolve(root[1:])
            if handler_urlargs:
                root, urlargs = handler_urlargs
            else:
                return []
        return list(self.routes)

    def encoding(self, request):
        '''The encoding to use for the response. By default it
returns ``utf-8``.'''
        return 'utf-8'
コード例 #28
0
 def __init__(self, *children, **params):
     self.as_list = params.pop('as_list', False)
     self.parameters = AttributeDictionary(params)
     for child in children:
         self.append(child)
コード例 #29
0
ファイル: routers.py プロジェクト: azazel75/pulsar
class Router(RouterType('RouterBase', (object, ), {})):
    '''A :ref:`WSGI middleware <wsgi-middleware>` to handle client requests
    on multiple :ref:`routes <apps-wsgi-route>`.

    The user must implement the HTTP methods
    required by the application. For example if the route needs to
    serve a ``GET`` request, the ``get(self, request)`` method must
    be implemented.

    :param rule: String used for creating the :attr:`route` of this
        :class:`Router`.
    :param routes: Optional :class:`Router` instances which are added to the
        children :attr:`routes` of this router.
    :param parameters: Optional parameters for this router.
        They are stored in the :attr:`parameters` attribute with the
        exception of :attr:`response_content_types` and
        :attr:`response_wrapper`

    .. attribute:: rule_methods

        A class attribute built during class creation. It is an ordered
        dictionary mapping method names with a five-elements tuple
        containing information
        about a child route (See the :class:`.route` decorator).

    .. attribute:: routes

        List of children :class:`Router` of this :class:`Router`.

    .. attribute:: parent

        The parent :class:`Router` of this :class:`Router`.

    .. attribute:: response_content_types

        A list/tuple of possible content types of a response to a
        client request.

        The client request must accept at least one of the response content
        types, otherwise an HTTP ``415`` exception occurs.

    .. attribute:: response_wrapper

        Optional function which wraps all handlers of this :class:`.Router`.
        The function must accept two parameters, the original handler
        and the :class:`.WsgiRequest`::

            def response_wrapper(handler, request):
                ...
                return handler(request)

    .. attribute:: parameters

        A :class:`.AttributeDictionary` of parameters for
        this :class:`Router`. Parameters are created at initialisation from
        the ``parameters`` class attribute and the key-valued parameters
        passed to the ``__init__`` method which are available in the
        class ``parameters`` attribute.
    '''
    _creation_count = 0
    _parent = None
    _name = None

    response_content_types = RouterParam(None)
    response_wrapper = RouterParam(None)

    def __init__(self, rule, *routes, **parameters):
        Router._creation_count += 1
        self._creation_count = Router._creation_count
        if not isinstance(rule, Route):
            rule = Route(rule)
        self._route = rule
        self._name = parameters.pop('name', rule.name)
        self.routes = []
        # add routes specified via the initialiser first
        for router in routes:
            self.add_child(router)
        # copy parameters
        self.parameters = AttributeDictionary(self.parameters)
        for name, rule_method in self.rule_methods.items():
            rule, method, params, _, _ = rule_method
            rparameters = params.copy()
            handler = getattr(self, name)
            router = self.add_child(self.make_router(rule, **rparameters))
            setattr(router, method, handler)
        for name, value in parameters.items():
            if name in self.parameters:
                self.parameters[name] = value
            else:
                setattr(self, slugify(name, separator='_'), value)

    @property
    def route(self):
        '''The relative :class:`.Route` served by this
        :class:`Router`.
        '''
        parent = self._parent
        if parent and parent._route.is_leaf:
            return parent.route + self._route
        else:
            return self._route

    @property
    def full_route(self):
        '''The full :attr:`route` for this :class:`.Router`.

        It includes the :attr:`parent` portion of the route if a parent
        router is available.
        '''
        if self._parent:
            return self._parent.full_route + self._route
        else:
            return self._route

    @property
    def name(self):
        '''The name of this :class:`Router`.

        This attribute can be specified during initialisation.
        If available, it can be used to retrieve a child router
        by name via the :meth:`get_route` method.
        '''
        return self._name

    @property
    def root(self):
        '''The root :class:`Router` for this :class:`Router`.'''
        if self.parent:
            return self.parent.root
        else:
            return self

    @property
    def parent(self):
        return self._parent

    @property
    def creation_count(self):
        '''Integer for sorting :class:`Router` by creation.

        Auto-generated during initialisation.'''
        return self._creation_count

    @property
    def rule(self):
        '''The full ``rule`` string for this :class:`Router`.

        It includes the :attr:`parent` portion of the rule if a :attr:`parent`
        router is available.
        '''
        return self.full_route.rule

    def path(self, **urlargs):
        '''The full path of this :class:`Router`.

        It includes the :attr:`parent` portion of url if a parent router
        is available.
        '''
        return self.full_route.url(**urlargs)

    def getparam(self, name, default=None):
        '''A parameter in this :class:`.Router`
        '''
        try:
            return getattr(self, name)
        except AttributeError:
            return default

    def __getattr__(self, name):
        '''Check the value of a :attr:`parameters` ``name``.

        If the parameter is not available, retrieve the parameter from the
        :attr:`parent` :class:`Router` if it exists.
        '''
        if not name.startswith('_'):
            return self._get_router_parameter(name, False)
        self._no_param(name)

    def content_type(self, request):
        '''Evaluate the content type for the response to a client ``request``.

        The method uses the :attr:`response_content_types` parameter of
        accepted content types and the content types accepted by the client
        ``request`` and figures out the best match.
        '''
        content_types = self.response_content_types
        ct = request.content_types.best_match(content_types)
        if ct and '*' in ct:
            ct = None
        if not ct and content_types:
            raise HttpException(status=415, msg=request.content_types)
        return ct

    def __repr__(self):
        return self.route.__repr__()

    def __call__(self, environ, start_response=None):
        path = environ.get('PATH_INFO') or '/'
        path = path[1:]
        router_args = self.resolve(path)
        if router_args:
            router, args = router_args
            return router.response(environ, args)

    def resolve(self, path, urlargs=None):
        '''Resolve a path and return a ``(handler, urlargs)`` tuple or
        ``None`` if the path could not be resolved.
        '''
        match = self.route.match(path)
        if match is None:
            if not self.route.is_leaf:  # no match
                return
        elif '__remaining__' in match:
            path = match.pop('__remaining__')
            urlargs = update_args(urlargs, match)
        else:
            return self, update_args(urlargs, match)
        #
        for handler in self.routes:
            view_args = handler.resolve(path, urlargs)
            if view_args is None:
                continue
            return view_args

    def response(self, environ, args):
        '''Once the :meth:`resolve` method has matched the correct
        :class:`Router` for serving the request, this matched router invokes
        this method to produce the WSGI response.
        '''
        request = wsgi_request(environ, self, args)
        request.response.content_type = self.content_type(request)
        method = request.method.lower()
        callable = getattr(self, method, None)
        if callable is None:
            raise HttpException(status=405)
        response_wrapper = self.response_wrapper
        if response_wrapper:
            return response_wrapper(callable, request)
        return callable(request)

    def add_child(self, router):
        '''Add a new :class:`Router` to the :attr:`routes` list.
        '''
        assert isinstance(router, Router), 'Not a valid Router'
        assert router is not self, 'cannot add self to children'
        #
        # Remove from previous parent
        if router.parent:
            router.parent.remove_child(router)
        router._parent = self
        # Loop over available routers to check it the router
        # is already available
        for r in self.routes:
            if r.route == router.route:
                r.parameters.update(router.parameters)
                return r
        self.routes.append(router)
        return router

    def remove_child(self, router):
        '''remove a :class:`Router` from the :attr:`routes` list.'''
        if router in self.routes:
            self.routes.remove(router)
            router._parent = None

    def get_route(self, name):
        '''Get a child :class:`Router` by its :attr:`name`.

        This method search child routes recursively.
        '''
        for route in self.routes:
            if route.name == name:
                return route
        for child in self.routes:
            route = child.get_route(name)
            if route:
                return route

    def link(self, *args, **urlargs):
        '''Return an anchor :class:`Html` element with the `href` attribute
        set to the url of this :class:`Router`.'''
        if len(args) > 1:
            raise ValueError
        url = self.route.url(**urlargs)
        if len(args) == 1:
            text = args[0]
        else:
            text = url
        return Html('a', text, href=url)

    def has_parent(self, router):
        '''Check if ``router`` is ``self`` or a parent or ``self``
        '''
        parent = self
        while parent and parent is not router:
            parent = parent._parent
        return parent is not None

    def make_router(self, rule, cls=None, **params):
        '''Create a new :class:`.Router` from a ``rule`` and parameters.

        This method is used during initialisation when building child
        Routers from the :attr:`rule_methods`.
        '''
        cls = cls or Router
        return cls(rule, **params)

    def _no_param(self, name):
        raise AttributeError("'%s' object has no attribute '%s'" %
                             (self.__class__.__name__, name))

    def _get_router_parameter(self, name, safe=True):
        value = self.parameters.get(name)
        if value is None:
            if self._parent:
                return self._parent._get_router_parameter(name, safe)
            elif name in self.parameters:
                return value
            elif not safe:
                self._no_param(name)
        else:
            return value
コード例 #30
0
 def testInit(self):
     self.assertRaises(TypeError, AttributeDictionary, {}, {})
     a = AttributeDictionary({'bla': 1}, foo='pippo')
     self.assertEqual(dict(a), {'bla': 1, 'foo': 'pippo'})
     self.assertEqual(len(a), 2)
コード例 #31
0
ファイル: consts.py プロジェクト: Danzeer/pulsar
'''
Constants used throughout pulsar.
'''
from pulsar.utils.structures import AttributeDictionary

# LOW LEVEL CONSTANTS - NO NEED TO CHANGE THOSE ###########################
ACTOR_STATES = AttributeDictionary(INITIAL=0X0,
                                   INACTIVE=0X1,
                                   STARTING=0x2,
                                   RUN=0x3,
                                   STOPPING=0x4,
                                   CLOSE=0x5,
                                   TERMINATE=0x6)
'''
.. _actor-states:

Actor state constants are access via::

    from pulsar import ACTOR_STATES

They are:

* ``ACTOR_STATES.INITIAL = 0`` when an actor is just created, before the
  :class:`pulsar.Actor.start` method is called.
* ``ACTOR_STATES.STARTING = 2`` when :class:`pulsar.Actor.start` method
  is called.
* ``ACTOR_STATES.RUN = 3`` when :class:`pulsar.Actor._loop` is up
  and running.
* ``ACTOR_STATES.STOPPING = 4`` when :class:`pulsar.Actor.stop` has been
  called for the first time and the actor is running.
'''
コード例 #32
0
ファイル: contents.py プロジェクト: pvanderlinden/lux
class Content(Cacheable):
    '''A class for managing a file-based content
    '''
    template = None
    template_engine = None

    def __init__(self, app, content, metadata, path, src=None, **params):
        self._app = app
        self._content = content
        self._path = path
        self._src = src
        self._meta = AttributeDictionary(params)
        self._update_meta(metadata)
        if not self._meta.modified:
            if src:
                self._meta.modified = modified_datetime(src)
            else:
                self._meta.modified = datetime.now()
        self._meta.name = slugify(self._path, separator='_')

    @property
    def app(self):
        return self._app

    @property
    def content_type(self):
        return self._meta.content_type

    @property
    def is_text(self):
        return self._meta.content_type in CONTENT_EXTENSIONS

    @property
    def is_html(self):
        return is_html(self._meta.content_type)

    @property
    def suffix(self):
        return CONTENT_EXTENSIONS.get(self._meta.content_type)

    @property
    def path(self):
        return self._path

    @property
    def reldate(self):
        return self._meta.date or self._meta.modified

    @property
    def year(self):
        return self.reldate.year

    @property
    def month(self):
        return self.reldate.month

    @property
    def month2(self):
        return self.reldate.strftime('%m')

    @property
    def month3(self):
        return self.reldate.strftime('%b').lower()

    @property
    def id(self):
        if self.is_html:
            return '%s.json' % self._path

    def cache_key(self, app):
        return self._meta.name

    def __repr__(self):
        return self._path
    __str__ = __repr__

    def key(self, name=None):
        '''The key for a context dictionary
        '''
        name = name or self.name
        suffix = self.suffix
        return '%s_%s' % (suffix, name) if suffix else name

    def context(self, context=None):
        '''Extract the context dictionary for server side template rendering
        '''
        ctx = dict(self._flatten(self._meta))
        if context:
            ctx.update(context)
        return ctx

    def urlparams(self, names=None):
        urlparams = {}
        if names:
            for name in names:
                value = self._meta.get(name) or getattr(self, name, None)
                if value in (None, ''):
                    if name == 'id':
                        raise SkipBuild
                    elif names:
                        raise KeyError("%s could not obtain url variable '%s'"
                                       % (self, name))
                urlparams[name] = value
        return urlparams

    def render(self, context=None):
        '''Render the content
        '''
        if self.is_html:
            context = self.context(context)
            content = self._engine(self._content, context)
            if self.template:
                template = self._app.template_full_path(self.template)
                if template:
                    context[self.key('main')] = content
                    with open(template, 'r') as file:
                        template_str = file.read()
                    content = self._engine(template_str, context)
            return content
        else:
            return self._content

    def raw(self, request):
        return self._content

    @cached
    def json(self, request):
        '''Convert the content into a Json dictionary for the API
        '''
        if self.is_html:
            context = self._app.context(request)
            context = self.context(context)
            #
            data = self._to_json(request, self._meta)
            text = data.get(self.suffix) or {}
            data[self.suffix] = text
            text['main'] = self.render(context)
            #
            head = {}
            for key in HEAD_META:
                value = data.get(key)
                if value:
                    head[key] = value
            #
            if 'head' in data:
                head.update(data['head'])

            data['url'] = request.absolute_uri(self._path)
            data['head'] = head
            return data

    def html(self, request):
        '''Build the ``html_main`` key for this content and set
        content specific values to the ``head`` tag of the
        HTML5 document.
        '''
        if not self.is_html:
            raise Unsupported
        # The JSON data for this page
        data = self.json(request)
        doc = request.html_document
        doc.jscontext['page'] = dict(page_info(data))
        #
        image = absolute_uri(request, data.get('image'))
        doc.meta.update({'og:image': image,
                         'og:published_time': data.get('date'),
                         'og:modified_time': data.get('modified')})
        doc.meta.update(data['head'])
        #
        if not request.config.get('HTML5_NAVIGATION'):
            for css in data.get('require_css') or ():
                doc.head.links.append(css)
            doc.head.scripts.require.extend(data.get('require_js') or ())
        #
        if request.cache.uirouter is False:
            doc.head.scripts.require.extend(data.get('require_js') or ())

        self.on_html(doc)
        return data[self.suffix]['main']

    def on_html(self, doc):
        pass

    @classmethod
    def as_draft(cls):
        mp = tuple((a for a in cls.mandatory_properties
                    if a not in no_draft_field))
        return cls.__class__('Draft', (cls,), {'mandatory_properties': mp})

    # INTERNALS
    def _update_meta(self, metadata):
        meta = self._meta
        meta.site = {}
        for name in ('template_engine', 'template'):
            default = getattr(self, name)
            value = metadata.pop(name, default)
            meta.site[name] = value
            setattr(self, name, value)

        context = self.context(self.app.config)
        self._engine = self._app.template_engine(self.template_engine)
        meta.update(((key, self._render_meta(value, context))
                    for key, value in metadata.items()))

    def _flatten(self, meta):
        for key, value in mapping_iterator(meta):
            if isinstance(value, Mapping):
                for child, value in self._flatten(value):
                    yield '%s_%s' % (key, child), value
            else:
                yield key, self._to_string(value)

    def _to_string(self, value):
        if isinstance(value, Mapping):
            raise BuildError('A dictionary found when coverting to string')
        elif isinstance(value, (list, tuple)):
            return ', '.join(self._to_string(v) for v in value)
        elif isinstance(value, date):
            return iso8601(value)
        else:
            return to_string(value)

    def _render_meta(self, value, context):
        if isinstance(value, Mapping):
            return dict(((k, self._render_meta(v, context))
                         for k, v in value.items()))
        elif isinstance(value, (list, tuple)):
            return [self._render_meta(v, context) for v in value]
        elif isinstance(value, str):
            return self._engine(to_string(value), context)
        else:
            return value

    def _to_json(self, request, value):
        if isinstance(value, Mapping):
            return dict(((k, self._to_json(request, v))
                         for k, v in value.items()))
        elif isinstance(value, (list, tuple)):
            return [self._to_json(request, v) for v in value]
        elif isinstance(value, date):
            return iso8601(value)
        elif isinstance(value, URLWrapper):
            return value.to_json(request)
        else:
            return value
コード例 #33
0
ファイル: consts.py プロジェクト: Bhajju2510/SupervisedML
'''
Constants used throughout pulsar.
'''
from pulsar.utils.structures import AttributeDictionary

# LOW LEVEL CONSTANTS - NO NEED TO CHANGE THOSE ###########################
ACTOR_STATES = AttributeDictionary(INITIAL=0X0,
                                   INACTIVE=0X1,
                                   STARTING=0x2,
                                   RUN=0x3,
                                   STOPPING=0x4,
                                   CLOSE=0x5,
                                   TERMINATE=0x6)
'''
.. _actor-states:

Actor state constants are access via::

    from pulsar.api import ACTOR_STATES

They are:

* ``ACTOR_STATES.INITIAL = 0`` when an actor is just created, before the
  :class:`pulsar.Actor.start` method is called.
* ``ACTOR_STATES.STARTING = 2`` when :class:`pulsar.Actor.start` method
  is called.
* ``ACTOR_STATES.RUN = 3`` when :class:`pulsar.Actor._loop` is up
  and running.
* ``ACTOR_STATES.STOPPING = 4`` when :class:`pulsar.Actor.stop` has been
  called for the first time and the actor is running.
'''
コード例 #34
0
ファイル: test_structures.py プロジェクト: quantmind/pulsar
 def testCopy(self):
     a = AttributeDictionary(foo=5, bla='ciao')
     self.assertEqual(len(a), 2)
     b = a.copy()
     self.assertEqual(a, b)
     self.assertNotEqual(id(a), id(b))
コード例 #35
0
ファイル: contents.py プロジェクト: tourist/lux
class Content(object):
    template = None
    template_engine = None
    _json_dict = None
    _loc = None
    '''Template engine to render this content. Overwritten my metadata.
    If not available, the application default engine is used'''
    mandatory_properties = ()

    def __init__(self, app, content, metadata, src, path=None, context=None,
                 **params):
        self._app = app
        self._content = content
        self._context_for = context
        self._additional_context = {}
        self._src = src
        self._path = path or src
        self._meta = AttributeDictionary(params)
        if src:
            self._meta.modified = modified_datetime(src)
        else:
            self._meta.modified = datetime.now()
        # Get the site meta data dictionary.
        # Used to render Content metadata
        self._update_meta(metadata)
        meta = self._meta
        if self.is_html:
            dir, slug = os.path.split(self._path)
            if not slug:
                slug = self._path
                dir = None
            if not meta.slug:
                meta.slug = slugify(slug, separator='_')
            if dir:
                meta.slug = '%s/%s' % (dir, meta.slug)
        else:
            if self.suffix:  # Any other file
                suffix = '.%s' % self.suffix
                if not self._path.endswith(suffix):
                    self._path = self._path + suffix
            if not meta.slug:
                meta.slug = self._path
        meta.name = slugify(meta.slug, separator='_')
        for name in self.mandatory_properties:
            if not meta.get(name):
                raise BuildError("Property '%s' not available in %s"
                                 % (name, self))

    @property
    def name(self):
        return self._meta.name

    @property
    def src(self):
        return self._src

    @property
    def loc(self):
        return self._loc or self._src

    @loc.setter
    def loc(self, value):
        self._loc = value

    @property
    def content_type(self):
        return self._meta.content_type

    @property
    def is_text(self):
        return self._meta.content_type in CONTENT_EXTENSIONS

    @property
    def is_html(self):
        return is_html(self._meta.content_type)

    @property
    def suffix(self):
        return CONTENT_EXTENSIONS.get(self._meta.content_type)

    @property
    def path(self):
        return self._path

    @property
    def reldate(self):
        return self._meta.date or self._meta.modified

    @property
    def year(self):
        return self.reldate.year

    @property
    def month(self):
        return self.reldate.month

    @property
    def month2(self):
        return self.reldate.strftime('%m')

    @property
    def month3(self):
        return self.reldate.strftime('%b').lower()

    @property
    def id(self):
        if self.is_html:
            return '%s.json' % self._meta.slug

    @property
    def context_for(self):
        '''A list of contents names for which this snippet is required
        in the context dictionary
        '''
        return self._context_for

    @property
    def additional_context(self):
        '''Dictionary of key and :class:`.Snippet` providing additional
        keys for this content
        '''
        return self._additional_context

    def __repr__(self):
        return self._src
    __str__ = __repr__

    def key(self, name=None):
        '''The key for a context dictionary
        '''
        name = name or self.name
        return 'html_%s' % name if self.is_html else name

    def context(self, context=None):
        '''Extract the context dictionary for server side template rendering
        '''
        ctx = dict(self._flatten(self._meta))
        if context:
            ctx.update(context)
        return ctx

    def urlparams(self, names=None):
        urlparams = {}
        if names:
            for name in names:
                value = self._meta.get(name) or getattr(self, name, None)
                if value in (None, ''):
                    if name == 'id':
                        raise SkipBuild
                    elif names:
                        raise KeyError("%s could not obtain url variable '%s'"
                                       % (self, name))
                urlparams[name] = value
        return urlparams

    def render(self, context=None):
        '''Render the content
        '''
        if self.is_html:
            context = self.context(context)
            content = self._engine(self._content, context)
            if self.template:
                template = self._app.template_full_path(self.template)
                if template:
                    context[self.key('main')] = content
                    with open(template, 'r') as file:
                        template_str = file.read()
                    raw = self._engine(template_str, context)
                    reader = get_reader(self._app, template)
                    ct = reader.process(raw, template)
                    content = ct._content
            return content
        else:
            return self._content

    def json(self, request):
        '''Convert the content into a Json dictionary for the API
        '''
        if not self._json_dict and self.is_html:
            context = self._app.context(request)
            context = self.context(context)
            # Add additional context keys
            if self.additional_context:
                for key, ct in self.additional_context.items():
                    if isinstance(ct, Content):
                        key = ct.key(key)
                        ct = ct.render(context)
                    context[key] = ct
            #
            assert self.suffix
            data = self._to_json(self._meta)
            text = data.get(self.suffix) or {}
            data[self.suffix] = text
            text['main'] = self.render(context)
            #
            head = {}
            for key in HEAD_META:
                value = data.get(key)
                if value:
                    head[key] = value
            #
            require_css = data.get('require_css')
            if require_css:
                data['require_css'] = []
                cfg = request.config
                links = Links(cfg['MEDIA_URL'],
                              minified=cfg['MINIFIED_MEDIA'])
                for css in require_css:
                    css = CssLibraries.get(css, css)
                    links.append(css)
                for link in links.children:
                    link = link.split("href=")
                    if len(link) == 2:
                        href = link[1]
                        c = href[0]
                        href = href[1:]
                        link = href[:href.find(c)]
                        data['require_css'].append(link)
            #
            if 'head' in data:
                head.update(data['head'])

            data['head'] = head
            self._json_dict = data
        return self._json_dict

    def html(self, request):
        '''Build the ``html_main`` key for this content and set
        content specific values to the ``head`` tag of the
        HTML5 document.
        '''
        if not self.is_html:
            raise Unsupported
        # The JSON data for this page
        data = self.json(request)
        doc = request.html_document
        doc.jscontext['page'] = dict(page_info(data))
        #
        doc.meta.update({'og:image': data.get('image'),
                         'og:published_time': data.get('date'),
                         'og:modified_time': data.get('modified')})
        doc.meta.update(data['head'])
        #
        if not request.config['ANGULAR_UI_ROUTER']:
            for css in data.get('require_css') or ():
                doc.head.links.append(css)
            doc.head.scripts.require.extend(data.get('require_js') or ())
        #
        if request.cache.uirouter is False:
            doc.head.scripts.require.extend(data.get('require_js') or ())

        self.on_html(doc)
        return data[self.suffix]['main']

    def on_html(self, doc):
        pass

    @classmethod
    def as_draft(cls):
        mp = tuple((a for a in cls.mandatory_properties
                    if a not in no_draft_field))
        return cls.__class__('Draft', (cls,), {'mandatory_properties': mp})

    # INTERNALS
    def _update_meta(self, metadata):
        meta = self._meta
        meta.site = self._app.extensions['static'].build_info(self._app)
        context = self.context()
        for name in ('template_engine', 'template'):
            default = getattr(self, name)
            value = metadata.pop(name, default)
            meta.site[name] = value
            setattr(self, name, value)
        self._engine = engine = self._app.template_engine(self.template_engine)
        meta.update(((key, self._render_meta(value, context))
                    for key, value in metadata.items()))

    def _flatten(self, meta):
        for key, value in mapping_iterator(meta):
            if isinstance(value, Mapping):
                for child, value in self._flatten(value):
                    yield '%s_%s' % (key, child), value
            else:
                yield key, self._to_string(value)

    def _to_string(self, value):
        if isinstance(value, Mapping):
            raise BuildError('A dictionary found when coverting to string')
        elif isinstance(value, (list, tuple)):
            return ', '.join(self._to_string(v) for v in value)
        elif isinstance(value, date):
            return iso8601(value)
        else:
            return to_string(value)

    def _render_meta(self, value, context):
        if isinstance(value, Mapping):
            return dict(((k, self._render_meta(v, context))
                         for k, v in value.items()))
        elif isinstance(value, (list, tuple)):
            return [self._render_meta(v, context) for v in value]
        elif isinstance(value, date):
            return value
        elif value is not None:
            return self._engine(to_string(value), context)

    def _to_json(self, value):
        if isinstance(value, Mapping):
            return dict(((k, self._to_json(v)) for k, v in value.items()))
        elif isinstance(value, (list, tuple)):
            return [self._to_json(v) for v in value]
        elif isinstance(value, date):
            return iso8601(value)
        else:
            return value
コード例 #36
0
ファイル: contents.py プロジェクト: pvanderlinden/lux
class Content(Cacheable):
    '''A class for managing a file-based content
    '''
    template = None
    template_engine = None

    def __init__(self, app, content, metadata, path, src=None, **params):
        self._app = app
        self._content = content
        self._path = path
        self._src = src
        self._meta = AttributeDictionary(params)
        self._update_meta(metadata)
        if not self._meta.modified:
            if src:
                self._meta.modified = modified_datetime(src)
            else:
                self._meta.modified = datetime.now()
        self._meta.name = slugify(self._path, separator='_')

    @property
    def app(self):
        return self._app

    @property
    def content_type(self):
        return self._meta.content_type

    @property
    def is_text(self):
        return self._meta.content_type in CONTENT_EXTENSIONS

    @property
    def is_html(self):
        return is_html(self._meta.content_type)

    @property
    def suffix(self):
        return CONTENT_EXTENSIONS.get(self._meta.content_type)

    @property
    def path(self):
        return self._path

    @property
    def reldate(self):
        return self._meta.date or self._meta.modified

    @property
    def year(self):
        return self.reldate.year

    @property
    def month(self):
        return self.reldate.month

    @property
    def month2(self):
        return self.reldate.strftime('%m')

    @property
    def month3(self):
        return self.reldate.strftime('%b').lower()

    @property
    def id(self):
        if self.is_html:
            return '%s.json' % self._path

    def cache_key(self, app):
        return self._meta.name

    def __repr__(self):
        return self._path

    __str__ = __repr__

    def key(self, name=None):
        '''The key for a context dictionary
        '''
        name = name or self.name
        suffix = self.suffix
        return '%s_%s' % (suffix, name) if suffix else name

    def context(self, context=None):
        '''Extract the context dictionary for server side template rendering
        '''
        ctx = dict(self._flatten(self._meta))
        if context:
            ctx.update(context)
        return ctx

    def urlparams(self, names=None):
        urlparams = {}
        if names:
            for name in names:
                value = self._meta.get(name) or getattr(self, name, None)
                if value in (None, ''):
                    if name == 'id':
                        raise SkipBuild
                    elif names:
                        raise KeyError(
                            "%s could not obtain url variable '%s'" %
                            (self, name))
                urlparams[name] = value
        return urlparams

    def render(self, context=None):
        '''Render the content
        '''
        if self.is_html:
            context = self.context(context)
            content = self._engine(self._content, context)
            if self.template:
                template = self._app.template_full_path(self.template)
                if template:
                    context[self.key('main')] = content
                    with open(template, 'r') as file:
                        template_str = file.read()
                    content = self._engine(template_str, context)
            return content
        else:
            return self._content

    def raw(self, request):
        return self._content

    @cached
    def json(self, request):
        '''Convert the content into a Json dictionary for the API
        '''
        if self.is_html:
            context = self._app.context(request)
            context = self.context(context)
            #
            data = self._to_json(request, self._meta)
            text = data.get(self.suffix) or {}
            data[self.suffix] = text
            text['main'] = self.render(context)
            #
            head = {}
            for key in HEAD_META:
                value = data.get(key)
                if value:
                    head[key] = value
            #
            if 'head' in data:
                head.update(data['head'])

            data['url'] = request.absolute_uri(self._path)
            data['head'] = head
            return data

    def html(self, request):
        '''Build the ``html_main`` key for this content and set
        content specific values to the ``head`` tag of the
        HTML5 document.
        '''
        if not self.is_html:
            raise Unsupported
        # The JSON data for this page
        data = self.json(request)
        doc = request.html_document
        doc.jscontext['page'] = dict(page_info(data))
        #
        image = absolute_uri(request, data.get('image'))
        doc.meta.update({
            'og:image': image,
            'og:published_time': data.get('date'),
            'og:modified_time': data.get('modified')
        })
        doc.meta.update(data['head'])
        #
        if not request.config.get('HTML5_NAVIGATION'):
            for css in data.get('require_css') or ():
                doc.head.links.append(css)
            doc.head.scripts.require.extend(data.get('require_js') or ())
        #
        if request.cache.uirouter is False:
            doc.head.scripts.require.extend(data.get('require_js') or ())

        self.on_html(doc)
        return data[self.suffix]['main']

    def on_html(self, doc):
        pass

    @classmethod
    def as_draft(cls):
        mp = tuple(
            (a for a in cls.mandatory_properties if a not in no_draft_field))
        return cls.__class__('Draft', (cls, ), {'mandatory_properties': mp})

    # INTERNALS
    def _update_meta(self, metadata):
        meta = self._meta
        meta.site = {}
        for name in ('template_engine', 'template'):
            default = getattr(self, name)
            value = metadata.pop(name, default)
            meta.site[name] = value
            setattr(self, name, value)

        context = self.context(self.app.config)
        self._engine = self._app.template_engine(self.template_engine)
        meta.update(((key, self._render_meta(value, context))
                     for key, value in metadata.items()))

    def _flatten(self, meta):
        for key, value in mapping_iterator(meta):
            if isinstance(value, Mapping):
                for child, value in self._flatten(value):
                    yield '%s_%s' % (key, child), value
            else:
                yield key, self._to_string(value)

    def _to_string(self, value):
        if isinstance(value, Mapping):
            raise BuildError('A dictionary found when coverting to string')
        elif isinstance(value, (list, tuple)):
            return ', '.join(self._to_string(v) for v in value)
        elif isinstance(value, date):
            return iso8601(value)
        else:
            return to_string(value)

    def _render_meta(self, value, context):
        if isinstance(value, Mapping):
            return dict(
                ((k, self._render_meta(v, context)) for k, v in value.items()))
        elif isinstance(value, (list, tuple)):
            return [self._render_meta(v, context) for v in value]
        elif isinstance(value, str):
            return self._engine(to_string(value), context)
        else:
            return value

    def _to_json(self, request, value):
        if isinstance(value, Mapping):
            return dict(
                ((k, self._to_json(request, v)) for k, v in value.items()))
        elif isinstance(value, (list, tuple)):
            return [self._to_json(request, v) for v in value]
        elif isinstance(value, date):
            return iso8601(value)
        elif isinstance(value, URLWrapper):
            return value.to_json(request)
        else:
            return value
コード例 #37
0
ファイル: routers.py プロジェクト: huobao36/pulsar
class Router(RouterType('RouterBase', (object,), {})):
    '''A :ref:`WSGI middleware <wsgi-middleware>` to handle client requests
    on multiple :ref:`routes <apps-wsgi-route>`.

    The user must implement the HTTP methods
    required by the application. For example if the route needs to
    serve a ``GET`` request, the ``get(self, request)`` method must
    be implemented.

    :param rule: String used for creating the :attr:`route` of this
        :class:`Router`.
    :param routes: Optional :class:`Router` instances which are added to the
        children :attr:`routes` of this router.
    :param parameters: Optional parameters for this router.
        They are stored in the :attr:`parameters` attribute.
        If a ``response_content_types`` value is
        passed, it overrides the :attr:`response_content_types` attribute.

    .. attribute:: routes

        List of children :class:`Router` of this :class:`Router`.

    .. attribute:: parent

        The parent :class:`Router` of this :class:`Router`.

    .. attribute:: response_content_types

        a list/tuple of possible content types of a response to a
        client request.

        The client request must accept at least one of the response content
        types, otherwise an HTTP ``415`` exception occurs.

    .. attribute:: allows_redirects

        boolean indicating if this router can redirect requests to valid urls
        within this router and its children. For example, if a router serves
        the '/echo' url but not the ``/echo/`` one, a request on ``/echo/``
        will be redirected to ``/echo``.

        Default: ``False``

    .. attribute:: parameters

        A :class:`.AttributeDictionary` of parameters for
        this :class:`Router`. Parameters are created at initialisation from
        the ``parameters`` class attribute and the key-valued parameters
        passed to the ``__init__`` method for which the value is not callable.
    '''
    _creation_count = 0
    _parent = None
    _name = None

    response_content_types = RouterParam(None)
    allows_redirects = RouterParam(False)

    def __init__(self, rule, *routes, **parameters):
        Router._creation_count += 1
        self._creation_count = Router._creation_count
        if not isinstance(rule, Route):
            rule = Route(rule)
        self._route = rule
        self._name = parameters.pop('name', rule.rule)
        self.routes = []
        # add routes specified via the initialiser
        for router in routes:
            self.add_child(router)
        # copy parameters
        self.parameters = AttributeDictionary(self.parameters)
        for name, rule_method in self.rule_methods.items():
            rule, method, params, _, _ = rule_method
            rparameters = params.copy()
            handler = getattr(self, name)
            router = self.add_child(Router(rule, **rparameters))
            setattr(router, method, handler)
        for name, value in parameters.items():
            if name in self.parameters:
                self.parameters[name] = value
            else:
                setattr(self, name, value)

    @property
    def route(self):
        '''The relative :class:`.Route` served by this
        :class:`Router`.
        '''
        parent = self._parent
        if parent and parent._route.is_leaf:
            return parent.route + self._route
        else:
            return self._route

    @property
    def full_route(self):
        '''The full :attr:`route` for this :class:`.Router`.

        It includes the :attr:`parent` portion of the route if a parent
        router is available.
        '''
        if self._parent:
            return self._parent.full_route + self._route
        else:
            return self._route

    @property
    def name(self):
        '''The name of this :class:`Router`.

        This attribute can be specified during initialisation.
        If available, it can be used to retrieve a child router
        by name via the :meth:`get_route` method.
        '''
        return self._name

    @property
    def root(self):
        '''The root :class:`Router` for this :class:`Router`.'''
        if self.parent:
            return self.parent.root
        else:
            return self

    @property
    def parent(self):
        return self._parent

    @property
    def default_content_type(self):
        '''The default content type for responses.

        This is the first element in the :attr:`response_content_types` list.
        '''
        ct = self.response_content_types
        return ct[0] if ct else None

    @property
    def creation_count(self):
        '''Integer for sorting :class:`Router` by creation.

        Auto-generated during initialisation.'''
        return self._creation_count

    @property
    def rule(self):
        '''The full ``rule`` string for this :class:`Router`.

        It includes the :attr:`parent` portion of the rule if a :attr:`parent`
        router is available.
        '''
        return self.full_route.rule

    def path(self, **urlargs):
        '''The full path of this :class:`Router`.

        It includes the :attr:`parent` portion of url if a parent router
        is available.
        '''
        return self.full_route.url(**urlargs)

    def __getattr__(self, name):
        '''Check the value of a :attr:`parameters` ``name``.

        If the parameter is not available, retrieve the parameter from the
        :attr:`parent` :class:`Router` if it exists.
        '''
        if not name.startswith('_'):
            return self.get_parameter(name, False)
        self.no_param(name)

    def get_parameter(self, name, safe=True):
        value = self.parameters.get(name)
        if value is None:
            if self._parent:
                return self._parent.get_parameter(name, safe)
            elif name in self.parameters:
                return value
            elif not safe:
                self.no_param(name)
        else:
            return value

    def no_param(self, name):
        raise AttributeError("'%s' object has no attribute '%s'" %
                             (self.__class__.__name__, name))

    def content_type(self, request):
        '''Evaluate the content type for the response to a client ``request``.

        The method uses the :attr:`response_content_types` parameter of
        accepted content types and the content types accepted by the client
        and figure out the best match.
        '''
        return request.content_types.best_match(self.response_content_types)

    def accept_content_type(self, content_type):
        '''Check if ``content_type`` is accepted by this :class:`Router`.

        Return the best mach or ``None`` if not accepted.'''
        response_content_types = self.response_content_types
        if response_content_types:
            return ContentAccept(
                [(content_type, 1)]).best_match(response_content_types)

    def __repr__(self):
        return self.route.__repr__()

    def __call__(self, environ, start_response=None):
        path = environ.get('PATH_INFO') or '/'
        path = path[1:]
        router_args = self.resolve(path)
        if router_args:
            router, args = router_args
            return router.response(environ, args)
        elif self.allows_redirects:
            if self.route.is_leaf:
                if path.endswith('/'):
                    router_args = self.resolve(path[:-1])
                    if router_args is not None:
                        return self.redirect(environ, '/%s' % path[:-1])
            else:
                if not path.endswith('/'):
                    router_args = self.resolve('%s/' % path)
                    if router_args is not None:
                        return self.redirect(environ, '/%s/' % path)

    def resolve(self, path, urlargs=None):
        '''Resolve a path and return a ``(handler, urlargs)`` tuple or
        ``None`` if the path could not be resolved.
        '''
        match = self.route.match(path)
        if match is None:
            if not self.route.is_leaf:  # no match
                return
        elif '__remaining__' in match:
            path = match.pop('__remaining__')
            urlargs = update_args(urlargs, match)
        else:
            return self, update_args(urlargs, match)
        #
        for handler in self.routes:
            view_args = handler.resolve(path, urlargs)
            if view_args is None:
                continue
            return view_args

    def response(self, environ, args):
        '''Once the :meth:`resolve` method has matched the correct
        :class:`Router` for serving the request, this matched router invokes
        this method to produce the WSGI response.
        '''
        request = wsgi_request(environ, self, args)
        # Set the response content type
        request.response.content_type = self.content_type(request)
        method = request.method.lower()
        callable = getattr(self, method, None)
        if callable is None:
            raise HttpException(status=405,
                                msg='Method "%s" not allowed' % method)
        return callable(request)

    def redirect(self, environ, path):
        raise HttpRedirect(path)

    def add_child(self, router):
        '''Add a new :class:`Router` to the :attr:`routes` list.
        '''
        assert isinstance(router, Router), 'Not a valid Router'
        assert router is not self, 'cannot add self to children'
        # Loop over available routers to check it the router
        # is already available
        for r in self.routes:
            if r.route == router.route:
                r.parameters.update(router.parameters)
                return r
        if router.parent:
            router.parent.remove_child(router)
        router._parent = self
        self.routes.append(router)
        return router

    def remove_child(self, router):
        '''remove a :class:`Router` from the :attr:`routes` list.'''
        if router in self.routes:
            self.routes.remove(router)
            router._parent = None

    def get_route(self, name):
        '''Get a child :class:`Router` by its :attr:`name`.'''
        for route in self.routes:
            if route.name == name:
                return route

    def link(self, *args, **urlargs):
        '''Return an anchor :class:`Html` element with the `href` attribute
        set to the url of this :class:`Router`.'''
        if len(args) > 1:
            raise ValueError
        url = self.route.url(**urlargs)
        if len(args) == 1:
            text = args[0]
        else:
            text = url
        return Html('a', text, href=url)

    def sitemap(self, root=None):
        '''This utility method returns a sitemap starting at root.

        If *root* is ``None`` it starts from this :class:`Router`.

        :param request: a :ref:`wsgi request wrapper <app-wsgi-request>`
        :param root: Optional url path where to start the sitemap.
            By default it starts from this :class:`Router`. Pass `"/"` to
            start from the root :class:`Router`.
        :param levels: Number of nested levels to include.
        :return: A list of children
        '''
        if not root:
            root = self
        else:
            handler_urlargs = self.root.resolve(root[1:])
            if handler_urlargs:
                root, urlargs = handler_urlargs
            else:
                return []
        return list(self.routes)

    def encoding(self, request):
        '''The encoding to use for the response.

        By default it returns ``utf-8``.'''
        return 'utf-8'
コード例 #38
0
ファイル: views.py プロジェクト: pvanderlinden/lux
 def items(self, request):
     model = self.content_router.model(request)
     for item in model.all(request):
         yield AttributeDictionary(loc=item['url'],
                                   lastmod=item['modified'],
                                   priority=item['priority'])
コード例 #39
0
 def testCopy(self):
     a = AttributeDictionary(foo=5, bla='ciao')
     self.assertEqual(len(a), 2)
     b = a.copy()
     self.assertEqual(a, b)
     self.assertNotEqual(id(a), id(b))
コード例 #40
0
ファイル: jsonrpc.py プロジェクト: ilmiacs/pulsar
class JsonProxy(object):
    '''A python Proxy class for :class:`JSONRPC` Servers.

:param url: server location
:param version: JSONRPC server version. Default ``2.0``
:param id: optional request id, generated if not provided. Default ``None``.
:param data: Extra data to include in all requests. Default ``None``.
:param http: optional http opener. If provided it must have the ``request``
    method available which must be of the form::

        http.request(url, body=..., method=...)

    Default ``None``.

Lets say your RPC server is running at ``http://domain.name.com/``::

    >>> a = JsonProxy('http://domain.name.com/')
    >>> a.add(3,4)
    7
    >>> a.ping()
    'pong'

'''
    separator  = '.'
    rawprefix  = 'raw'
    default_version = '2.0'
    default_timeout = 3
    _json = JsonToolkit

    def __init__(self, url, name=None, version=None, id=None, data=None,
                 **kwargs):
        self.__url = url
        self.__name = name
        self.__version = version or self.__class__.default_version
        self.__id = id
        self.__data = data if data is not None else {}
        self.local = AttributeDictionary()
        self.setup(**kwargs)

    def setup(self, http=None, timeout=None, **kwargs):
        if not http:
            timeout = timeout if timeout is not None else self.default_timeout
            http = HttpClient(timeout=timeout, **kwargs)
        self.local.http = http

    @property
    def url(self):
        return self.__url

    @property
    def http(self):
        return self.local.http

    @property
    def path(self):
        return self.__name

    def makeid(self):
        '''Can be re-implemented by your own Proxy'''
        return gen_unique_id()

    def __str__(self):
        return self.__repr__()

    def __repr__(self):
        if self.__id:
            d = '%s - %s' % (self.__url,self.__id)
        else:
            d = self.__url
        return 'JSONRPCProxy(%s)' % d

    def __getattr__(self, name):
        if self.__name != None:
            name = "%s%s%s" % (self.__name, self.separator, name)
        id = self.makeid()
        return self.__class__(self.__url, name=name, version=self.__version,
                              id=id, data=self.__data, **self.local.all())

    def timeit(self, func, times, *args, **kwargs):
        '''Usefull little utility for timing responses from server. The
usage is simple::

    >>> from pulsar.apps import rpc
    >>> p = rpc.JsonProxy('http://127.0.0.1:8060')
    >>> p.timeit('ping',10)
    0.56...
    >>> _
    '''
        r = range(times)
        func = getattr(self,func)
        start = default_timer()
        for t in r:
            func(*args, **kwargs)
        return default_timer() - start

    def _get_data(self, *args, **kwargs):
        func_name = self.__name
        fs = func_name.split('_')
        raw = False
        if len(fs) > 1 and fs[0] == self.rawprefix:
            raw = True
            fs.pop(0)
            func_name = '_'.join(fs)
        params = self.get_params(*args, **kwargs)
        data = {'method': func_name, 'params': params, 'id': self.__id,
                'jsonrpc': self.__version}
        return data, raw

    def __call__(self, *args, **kwargs):
        data, raw = self._get_data(*args, **kwargs)
        body = self._json.dumps(data).encode('latin-1')
        # Always make sure the content-type is application/json
        self.http.headers['content-type'] = 'application/json'
        resp = self.http.post(self.__url, data=body)
        if is_async(resp):
            return resp.add_callback(lambda r: self._end_call(r, raw))
        else:
            return self._end_call(resp, raw)
    
    def _end_call(self, resp, raw):
        content = resp.content.decode('utf-8')
        if resp.is_error:
            if 'error' in content:
                return self.loads(content)
            else:
                resp.raise_for_status()
        else:
            if raw:
                return content
            else:
                return self.loads(content)

    def get_params(self, *args, **kwargs):
        '''
        Create an array or positional or named parameters
        Mixing positional and named parameters in one
        call is not possible.
        '''
        kwargs.update(self.__data)
        if args and kwargs:
            raise ValueError('Cannot mix positional and named parameters')
        if args:
            return list(args)
        else:
            return kwargs

    def loads(self, obj):
        res = self._json.loads(obj)
        if isinstance(res, dict):
            if 'error' in res:
                error = res['error']
                code    = error['code']
                message = error['message']
                raise exception(code, message)
            else:
                return res.get('result',None)
        return res