Current File : /home/jvzmxxx/wiki1/extensions/EventLogging/server/eventlogging/factory.py
# -*- coding: utf-8 -*-
"""
  eventlogging.factory
  ~~~~~~~~~~~~~~~~~~~~

  This module implements a factory-like map of URI scheme handlers.

"""
import contextlib
import inspect

from .compat import items, parse_qsl, urisplit

__all__ = ('apply_safe', 'drive', 'get_reader', 'get_writer', 'handle',
           'reads', 'writes')

_writers = {}
_readers = {}


def cast_string(v):
    """
    If the string v looks like it should be a
    bool, int or float, convert it to the builtin
    Python type
    """

    if type(v) not in (str, unicode):
        return v

    # attempt to convert v to a bool
    v = {
        'true':  True,
        'false': False
    }.get(v.lower(), v)

    # Else try to convert v to an int or float
    if type(v) is not bool:
        try:
            v = int(v)
        except ValueError:
            try:
                v = float(v)
            except ValueError:
                pass
    return v


def apply_safe(f, kwargs):
    """Apply a function with only those arguments that it would accept."""
    # If the function takes a '**' arg, all keyword args are safe.
    # If it doesn't, we have to remove any arguments that are not
    # present in the function's signature.
    sig = inspect.getargspec(f)
    if sig.keywords is None:
        kwargs = {k: v for k, v in items(kwargs) if k in sig.args}
    if sig.defaults is not None:
        args = [kwargs.pop(k) for k in sig.args[:-len(sig.defaults)]]
    else:
        args = [kwargs.pop(k) for k in sig.args]

    # Since kwargs come in as strings from URI
    # query params, attempt to cast ones that
    # look like builtin types.  E.g.
    # 'True' => True, '0.1' => 0.1, etc.
    for k, v in items(kwargs):
        kwargs[k] = cast_string(v)

    return f(*args, **kwargs)


def handle(handlers, uri):
    """Use a URI to look up a handler and then invoke the handler with
    the parts and params of a URI as kwargs."""
    parts = urisplit(uri)
    handler = handlers[parts.scheme]
    kwargs = dict(parse_qsl(parts.query), uri=uri)
    for k in 'hostname', 'port', 'path':
        kwargs[k] = getattr(parts, k)
    return apply_safe(handler, kwargs)


def writes(*schemes):
    """Decorator that takes URI schemes as parameters and registers the
    decorated function as an event writer for those schemes."""
    def decorator(f):
        _writers.update((scheme, f) for scheme in schemes)
        return f
    return decorator


def reads(*schemes):
    """Decorator that takes URI schemes as parameters and registers the
    decorated function as an event reader for those schemes."""
    def decorator(f):
        _readers.update((scheme, f) for scheme in schemes)
        return f
    return decorator


def get_writer(uri):
    """Given a writer URI (representing, for example, a database
    connection), invoke and initialize the appropriate handler."""
    coroutine = handle(_writers, uri)
    next(coroutine)
    return coroutine


def get_reader(uri):
    """Given a reader URI (representing the address of an input stream),
    invoke and initialize a generator that will yield values from that
    stream."""
    iterator = handle(_readers, uri)
    return iterator


def drive(in_url, out_url):
    """Impel data from a reader into a writer."""
    reader = get_reader(in_url)
    writer = get_writer(out_url)

    with contextlib.closing(reader), contextlib.closing(writer):
        for event in reader:
            writer.send(event)