Beispiel #1
0
def wrap_function(cache_store, func_):
    attr_name = "_cache_for_" + func_.__name__

    func_args = get_function_arguments(func_)
    if len(func_args) > 0 and func_args[0] == "self":
        using_self = True
        func = lambda self, *args: func_(self, *args)
    else:
        using_self = False
        func = lambda self, *args: func_(*args)

    def output(*args, **kwargs):
        if kwargs:
            Log.error("Sorry, caching only works with ordered parameter, not keyword arguments")

        with cache_store.locker:
            if using_self:
                self = args[0]
                args = args[1:]
            else:
                self = cache_store

            now = Date.now()
            try:
                _cache = getattr(self, attr_name)
            except Exception:
                _cache = {}
                setattr(self, attr_name, _cache)

            if Random.int(100) == 0:
                # REMOVE OLD CACHE
                _cache = {k: v for k, v in _cache.items() if v.timeout == None or v.timeout > now}
                setattr(self, attr_name, _cache)

            timeout, key, value, exception = _cache.get(args, (Null, Null, Null, Null))

        if now >= timeout:
            value = func(self, *args)
            with cache_store.locker:
                _cache[args] = CacheElement(now + cache_store.timeout, args, value, None)
            return value

        if value == None:
            if exception == None:
                try:
                    value = func(self, *args)
                    with cache_store.locker:
                        _cache[args] = CacheElement(now + cache_store.timeout, args, value, None)
                    return value
                except Exception as e:
                    e = Except.wrap(e)
                    with cache_store.locker:
                        _cache[args] = CacheElement(now + cache_store.timeout, args, None, e)
                    raise e
            else:
                raise exception
        else:
            return value

    return output
Beispiel #2
0
    def __call__(self, *args, **kwargs):
        settings = wrap(kwargs).settings

        params = get_function_arguments(self.constructor)[1:]
        func_defaults = get_function_defaults(self.constructor)
        if not func_defaults:
            defaults = {}
        else:
            defaults = {k: v for k, v in zip(reversed(params), reversed(func_defaults))}

        ordered_params = dict(zip(params, args))

        output = self.class_(**params_pack(params, ordered_params, kwargs, settings, defaults))
        return DataObject(output)
Beispiel #3
0
    def __call__(self, *args, **kwargs):
        settings = wrap(kwargs).settings

        params = get_function_arguments(self.constructor)[1:]
        func_defaults = get_function_defaults(self.constructor)
        if not func_defaults:
            defaults = {}
        else:
            defaults = {k: v for k, v in zip(reversed(params), reversed(func_defaults))}

        ordered_params = dict(zip(params, args))

        output = self.class_(**params_pack(params, ordered_params, kwargs, settings, defaults))
        return DataObject(output)
Beispiel #4
0
        def w_settings(*args, **kwargs):
            settings = kwargs.get("kwargs")

            params = get_function_arguments(func)
            if not get_function_defaults(func):
                defaults = {}
            else:
                defaults = {
                    k: v
                    for k, v in zip(reversed(params),
                                    reversed(get_function_defaults(func)))
                }

            ordered_params = dict(zip(params, args))

            return func(**params_pack(params, ordered_params, kwargs, settings,
                                      defaults))
Beispiel #5
0
def override(func):
    """
    THIS DECORATOR WILL PUT ALL PARAMETERS INTO THE `kwargs` PARAMETER AND
    THEN PUT ALL `kwargs` PARAMETERS INTO THE FUNCTION PARAMETERS. THIS HAS
    THE BENEFIT OF HAVING ALL PARAMETERS IN ONE PLACE (kwargs), PLUS ALL
    PARAMETERS ARE EXPLICIT FOR CLARITY.

    OF COURSE, THIS MEANS PARAMETER ASSIGNMENT MAY NOT BE UNIQUE: VALUES CAN
    COME FROM EXPLICIT CALL PARAMETERS, OR FROM THE kwargs PARAMETER. IN
    THESE CASES, PARAMETER VALUES ARE CHOSEN IN THE FOLLOWING ORDER:
    1) EXPLICT CALL PARAMETERS
    2) PARAMETERS FOUND IN kwargs
    3) DEFAULT VALUES ASSIGNED IN FUNCTION DEFINITION
    """

    func_name = get_function_name(func)
    params = get_function_arguments(func)
    if not get_function_defaults(func):
        defaults = {}
    else:
        defaults = {
            k: v
            for k, v in zip(reversed(params), reversed(get_function_defaults(func)))
        }

    def raise_error(e, a, k):
        packed = set_default(dict(zip(params, a)), k)
        err = text(e)
        e = Except.wrap(e)
        if err.startswith(func_name) and (
            "takes at least" in err
            or "takes exactly " in err
            or "required positional argument" in err
        ):
            missing = [p for p in params if str(p) not in packed]
            given = [p for p in params if str(p) in packed]
            if not missing:
                raise e
            else:
                get_logger().error(
                    "Problem calling {{func_name}}:  Expecting parameter {{missing}}, given {{given}}",
                    func_name=func_name,
                    missing=missing,
                    given=given,
                    stack_depth=2,
                    cause=e,
                )
        raise e

    if KWARGS not in params:
        # ADDING A kwargs PARAMETER TO SOME REGULAR METHOD
        def wo_kwargs(*args, **kwargs):
            settings = kwargs.get(KWARGS, {})
            ordered_params = dict(zip(params, args))
            a, k = params_pack(params, defaults, settings, kwargs, ordered_params)
            try:
                return func(*a, **k)
            except TypeError as e:
                raise_error(e, a, k)

        return update_wrapper(wo_kwargs, func)

    elif func_name in ("__init__", "__new__") or params[0] in ("self", "cls"):

        def w_bound_method(*args, **kwargs):
            if len(args) == 2 and len(kwargs) == 0 and is_data(args[1]):
                # ASSUME SECOND UNNAMED PARAM IS kwargs
                a, k = params_pack(
                    params, defaults, args[1], {params[0]: args[0]}, kwargs
                )
            elif KWARGS in kwargs and is_data(kwargs[KWARGS]):
                # PUT args INTO kwargs
                a, k = params_pack(
                    params, defaults, kwargs[KWARGS], dict_zip(params, args), kwargs
                )
            else:
                a, k = params_pack(params, defaults, dict_zip(params, args), kwargs)
            try:
                return func(*a, **k)
            except TypeError as e:
                raise_error(e, a, k)

        return update_wrapper(w_bound_method, func)

    else:

        def w_kwargs(*args, **kwargs):
            if len(args) == 1 and len(kwargs) == 0 and is_data(args[0]):
                # ASSUME SINGLE PARAMETER IS kwargs
                a, k = params_pack(params, defaults, args[0])
            elif KWARGS in kwargs and is_data(kwargs[KWARGS]):
                # PUT args INTO kwargs
                a, k = params_pack(
                    params, defaults, kwargs[KWARGS], dict_zip(params, args), kwargs
                )
            else:
                # PULL kwargs OUT INTO PARAMS
                a, k = params_pack(params, defaults, dict_zip(params, args), kwargs)
            try:
                return func(*a, **k)
            except TypeError as e:
                raise_error(e, a, k)

        return update_wrapper(w_kwargs, func)
Beispiel #6
0
def override(func):
    """
    THIS DECORATOR WILL PUT ALL PARAMETERS INTO THE `kwargs` PARAMETER AND
    THEN PUT ALL `kwargs` PARAMETERS INTO THE FUNCTION PARAMETERS. THIS HAS
    THE BENEFIT OF HAVING ALL PARAMETERS IN ONE PLACE (kwargs), PLUS ALL
    PARAMETERS ARE EXPLICIT FOR CLARITY.

    OF COURSE, THIS MEANS PARAMETER ASSIGNMENT MAY NOT BE UNIQUE: VALUES CAN
    COME FROM EXPLICIT CALL PARAMETERS, OR FROM THE kwargs PARAMETER. IN
    THESE CASES, PARAMETER VALUES ARE CHOSEN IN THE FOLLOWING ORDER:
    1) EXPLICT CALL PARAMETERS
    2) PARAMETERS FOUND IN kwargs
    3) DEFAULT VALUES ASSIGNED IN FUNCTION DEFINITION
    """

    func_name = get_function_name(func)
    params = get_function_arguments(func)
    if not get_function_defaults(func):
        defaults = {}
    else:
        defaults = {k: v for k, v in zip(reversed(params), reversed(get_function_defaults(func)))}

    def raise_error(e, packed):
        err = text_type(e)
        e = Except.wrap(e)
        if err.startswith(func_name) and ("takes at least" in err or "required positional argument" in err):
            missing = [p for p in params if str(p) not in packed]
            given = [p for p in params if str(p) in packed]
            if not missing:
                raise e
            else:
                get_logger().error(
                    "Problem calling {{func_name}}:  Expecting parameter {{missing}}, given {{given}}",
                    func_name=func_name,
                    missing=missing,
                    given=given,
                    stack_depth=2,
                    cause=e
                )
        raise e

    if "kwargs" not in params:
        # WE ASSUME WE ARE ONLY ADDING A kwargs PARAMETER TO SOME REGULAR METHOD
        def wo_kwargs(*args, **kwargs):
            settings = kwargs.get("kwargs")
            ordered_params = dict(zip(params, args))
            packed = params_pack(params, ordered_params, kwargs, settings, defaults)
            try:
                return func(**packed)
            except TypeError as e:
                raise_error(e, packed)
        return wo_kwargs

    elif func_name in ("__init__", "__new__"):
        def w_constructor(*args, **kwargs):
            if "kwargs" in kwargs:
                packed = params_pack(params, dict_zip(params[1:], args[1:]), kwargs, kwargs["kwargs"], defaults)
            elif len(args) == 2 and len(kwargs) == 0 and is_data(args[1]):
                # ASSUME SECOND UNNAMED PARAM IS kwargs
                packed = params_pack(params, args[1], defaults)
            else:
                # DO NOT INCLUDE self IN kwargs
                packed = params_pack(params, dict_zip(params[1:], args[1:]), kwargs, defaults)
            try:
                return func(args[0], **packed)
            except TypeError as e:
                packed['self'] = args[0]  # DO NOT SAY IS MISSING
                raise_error(e, packed)
        return w_constructor

    elif params[0] == "self":
        def w_bound_method(*args, **kwargs):
            if len(args) == 2 and len(kwargs) == 0 and is_data(args[1]):
                # ASSUME SECOND UNNAMED PARAM IS kwargs
                packed = params_pack(params, args[1], defaults)
            elif "kwargs" in kwargs and is_data(kwargs["kwargs"]):
                # PUT args INTO kwargs
                packed = params_pack(params, kwargs, dict_zip(params[1:], args[1:]), kwargs["kwargs"], defaults)
            else:
                packed = params_pack(params, kwargs, dict_zip(params[1:], args[1:]), defaults)
            try:
                return func(args[0], **packed)
            except TypeError as e:
                raise_error(e, packed)
        return w_bound_method

    else:
        def w_kwargs(*args, **kwargs):
            if len(args) == 1 and len(kwargs) == 0 and is_data(args[0]):
                # ASSUME SINGLE PARAMETER IS kwargs
                packed = params_pack(params, args[0], defaults)
            elif "kwargs" in kwargs and is_data(kwargs["kwargs"]):
                # PUT args INTO kwargs
                packed = params_pack(params, kwargs, dict_zip(params, args), kwargs["kwargs"], defaults)
            else:
                # PULL kwargs OUT INTO PARAMS
                packed = params_pack(params, kwargs, dict_zip(params, args), defaults)
            try:
                return func(**packed)
            except TypeError as e:
                raise_error(e, packed)
        return w_kwargs
Beispiel #7
0
    def output(func):
        func_name = get_function_name(func)
        params = get_function_arguments(func)
        if not get_function_defaults(func):
            defaults = {}
        else:
            defaults = {
                k: v
                for k, v in zip(reversed(params),
                                reversed(get_function_defaults(func)))
            }

        def raise_error(e, a, k):
            packed = set_default(dict(zip(params, a)), k)
            err = text(e)
            e = Except.wrap(e)
            if err.startswith(func_name) and (
                    "takes at least" in err or "takes exactly " in err
                    or "required positional argument" in err):
                missing = [p for p in params if str(p) not in packed]
                given = [p for p in params if str(p) in packed]
                if not missing:
                    raise e
                else:
                    get_logger().error(
                        "Problem calling {{func_name}}:  Expecting parameter {{missing}}, given {{given}}",
                        func_name=func_name,
                        missing=missing,
                        given=given,
                        stack_depth=2,
                        cause=e,
                    )
            raise e

        if kwargs not in params:
            # ADDING A kwargs PARAMETER TO SOME REGULAR METHOD
            def wo_kwargs(*given_args, **given_kwargs):
                settings = given_kwargs.get(kwargs, {})
                ordered_params = dict(zip(params, given_args))
                a, k = params_pack(params, defaults, settings, given_kwargs,
                                   ordered_params)
                try:
                    return func(*a, **k)
                except TypeError as e:
                    raise_error(e, a, k)

            return update_wrapper(wo_kwargs, func)

        elif func_name in ("__init__", "__new__") or params[0] in ("self",
                                                                   "cls"):

            def w_bound_method(*given_args, **given_kwargs):
                if len(given_args) == 2 and len(given_kwargs) == 0 and is_data(
                        given_args[1]):
                    # ASSUME SECOND UNNAMED PARAM IS kwargs
                    a, k = params_pack(params, defaults, given_args[1],
                                       {params[0]: given_args[0]},
                                       given_kwargs)
                elif kwargs in given_kwargs and is_data(given_kwargs[kwargs]):
                    # PUT args INTO given_kwargs
                    a, k = params_pack(params, defaults, given_kwargs[kwargs],
                                       dict_zip(params, given_args),
                                       given_kwargs)
                else:
                    a, k = params_pack(params, defaults,
                                       dict_zip(params, given_args),
                                       given_kwargs)
                try:
                    return func(*a, **k)
                except TypeError as e:
                    raise_error(e, a, k)

            return update_wrapper(w_bound_method, func)

        else:

            def w_kwargs(*given_args, **given_kwargs):
                if len(given_args) == 1 and len(given_kwargs) == 0 and is_data(
                        given_args[0]):
                    # ASSUME SINGLE PARAMETER IS kwargs
                    a, k = params_pack(params, defaults, given_args[0])
                elif kwargs in given_kwargs and is_data(given_kwargs[kwargs]):
                    # PUT given_args INTO given_kwargs
                    a, k = params_pack(params, defaults, given_kwargs[kwargs],
                                       dict_zip(params, given_args),
                                       given_kwargs)
                else:
                    # PULL kwargs OUT INTO PARAMS
                    a, k = params_pack(params, defaults,
                                       dict_zip(params, given_args),
                                       given_kwargs)
                try:
                    return func(*a, **k)
                except TypeError as e:
                    raise_error(e, a, k)

            return update_wrapper(w_kwargs, func)
Beispiel #8
0
def override(func):
    """
    THIS DECORATOR WILL PUT ALL PARAMETERS INTO THE `kwargs` PARAMETER AND
    THEN PUT ALL `kwargs` PARAMETERS INTO THE FUNCTION PARAMETERS. THIS HAS
    THE BENEFIT OF HAVING ALL PARAMETERS IN ONE PLACE (kwargs), PLUS ALL
    PARAMETERS ARE EXPLICIT FOR CLARITY.

    OF COURSE, THIS MEANS PARAMETER ASSIGNMENT MAY NOT BE UNIQUE: VALUES CAN
    COME FROM EXPLICIT CALL PARAMETERS, OR FROM THE kwargs PARAMETER. IN
    THESE CASES, PARAMETER VALUES ARE CHOSEN IN THE FOLLOWING ORDER:
    1) EXPLICT CALL PARAMETERS
    2) PARAMETERS FOUND IN kwargs
    3) DEFAULT VALUES ASSIGNED IN FUNCTION DEFINITION
    """

    func_name = get_function_name(func)
    params = get_function_arguments(func)
    if not get_function_defaults(func):
        defaults = {}
    else:
        defaults = {
            k: v
            for k, v in zip(reversed(params),
                            reversed(get_function_defaults(func)))
        }

    def raise_error(e, packed):
        err = text_type(e)
        e = Except.wrap(e)
        if err.startswith(func_name) and ("takes at least" in err
                                          or "required positional argument"
                                          in err):
            missing = [p for p in params if str(p) not in packed]
            given = [p for p in params if str(p) in packed]
            get_logger().error(
                "Problem calling {{func_name}}:  Expecting parameter {{missing}}, given {{given}}",
                func_name=func_name,
                missing=missing,
                given=given,
                stack_depth=2)
        get_logger().error("Error dispatching call", e)

    if "kwargs" not in params:
        # WE ASSUME WE ARE ONLY ADDING A kwargs PARAMETER TO SOME REGULAR METHOD
        def wo_kwargs(*args, **kwargs):
            settings = kwargs.get("kwargs")
            ordered_params = dict(zip(params, args))
            packed = params_pack(params, ordered_params, kwargs, settings,
                                 defaults)
            try:
                return func(**packed)
            except TypeError as e:
                raise_error(e, packed)

        return wo_kwargs

    elif func_name in ("__init__", "__new__"):

        def w_constructor(*args, **kwargs):
            if "kwargs" in kwargs:
                packed = params_pack(params, kwargs,
                                     dict_zip(params[1:], args[1:]),
                                     kwargs["kwargs"], defaults)
            elif len(args) == 2 and len(kwargs) == 0 and isinstance(
                    args[1], Mapping):
                # ASSUME SECOND UNNAMED PARAM IS kwargs
                packed = params_pack(params, args[1], defaults)
            else:
                # DO NOT INCLUDE self IN kwargs
                packed = params_pack(params, kwargs,
                                     dict_zip(params[1:], args[1:]), defaults)
            try:
                return func(args[0], **packed)
            except TypeError as e:
                raise_error(e, packed)

        return w_constructor

    elif params[0] == "self":

        def w_bound_method(*args, **kwargs):
            if len(args) == 2 and len(kwargs) == 0 and isinstance(
                    args[1], Mapping):
                # ASSUME SECOND UNNAMED PARAM IS kwargs
                packed = params_pack(params, args[1], defaults)
            elif "kwargs" in kwargs and isinstance(kwargs["kwargs"], Mapping):
                # PUT args INTO kwargs
                packed = params_pack(params, kwargs,
                                     dict_zip(params[1:], args[1:]),
                                     kwargs["kwargs"], defaults)
            else:
                packed = params_pack(params, kwargs,
                                     dict_zip(params[1:], args[1:]), defaults)
            try:
                return func(args[0], **packed)
            except TypeError as e:
                raise_error(e, packed)

        return w_bound_method

    else:

        def w_kwargs(*args, **kwargs):
            if len(args) == 1 and len(kwargs) == 0 and isinstance(
                    args[0], Mapping):
                # ASSUME SINGLE PARAMETER IS kwargs
                packed = params_pack(params, args[0], defaults)
            elif "kwargs" in kwargs and isinstance(kwargs["kwargs"], Mapping):
                # PUT args INTO kwargs
                packed = params_pack(params, kwargs, dict_zip(params, args),
                                     kwargs["kwargs"], defaults)
            else:
                # PULL kwargs OUT INTO PARAMS
                packed = params_pack(params, kwargs, dict_zip(params, args),
                                     defaults)
            try:
                return func(**packed)
            except TypeError as e:
                raise_error(e, packed)

        return w_kwargs
Beispiel #9
0
    def register_ops(self, module_vars):
        global JX

        if self.name != "JX":
            self.ops = copy(JX.ops)  # A COPY, IF ONLY TO KNOW IT WAS REPLACED

            double_dispatch_methods = tuple(
                sorted(set(self.ops[1].lookups.keys())))
        else:
            num_ops = 1 + max(obj.get_id() for obj in module_vars.values()
                              if isinstance(obj, type) and hasattr(obj, ID))
            self.ops = [None] * num_ops

            # FIND ALL DOUBLE-DISPATCH METHODS
            double_dispatch_methods = set()
            for _, new_op in list(module_vars.items()):
                if is_Expression(new_op):
                    for name, member in vars(new_op).items():
                        try:
                            args = get_function_arguments(member)
                            if args[:2] == ("self", "lang"):
                                double_dispatch_methods.add(name)
                        except Exception as cause:
                            pass
            double_dispatch_methods = tuple(sorted(double_dispatch_methods))

        for _, new_op in list(module_vars.items()):
            if is_Expression(new_op):
                op_id = new_op.get_id()
                jx_op = JX.ops[op_id]
                # LET EACH LANGUAGE POINT TO OP CLASS
                self.ops[op_id] = new_op
                new_op.lang = self

                # ENSURE THE partial_eval IS REGISTERED
                if jx_op is None:
                    for dd_method in double_dispatch_methods:
                        member = extract_method(new_op, dd_method)
                        args = get_function_arguments(member)
                        if args[:2] != ("self", "lang"):
                            Log.error(
                                "{{module}}.{{clazz}}.{{name}} is expecting (self, lang) parameters, minimum",
                                module=new_op.__module__,
                                clazz=new_op.__name__,
                                name=dd_method)
                        new_op.lookups[dd_method] = [member]
                elif jx_op.__name__ != new_op.__name__:
                    Log.error("Logic error")
                else:
                    new_op.lookups = jx_op.lookups
                    for dd_method in double_dispatch_methods:
                        member = extract_method(new_op, dd_method)
                        jx_op.lookups[dd_method] += [member]

                    # COPY OTHER DEFINED METHODS
                    others = list(vars(new_op).items())
                    for n, v in others:
                        if v is not None:
                            o = getattr(jx_op, n, None)
                            if o is None:
                                setattr(jx_op, n, v)
        if self.name == 'JX':
            # FINALLY, SWAP OUT THE BASE METHODS
            for dd_method in double_dispatch_methods:
                existing = getattr(BaseExpression, dd_method, None)
                if existing:
                    # USE BaseExpression WHEN AVAILABLE
                    setattr(Expression, dd_method, existing)
                else:
                    # MAKE A DISPATCHER, IF NOT ONE ALREADY
                    setattr(Expression, dd_method,
                            get_dispatcher_for(dd_method))

        else:
            # ENSURE THE ALL OPS ARE DEFINED ON THE NEW LANGUAGE
            for base_op, new_op in transpose(JX.ops, self.ops):
                if base_op and new_op is base_op:
                    # MISSED DEFINITION, ADD ONE
                    new_op = type(base_op.__name__, (base_op, ), {})
                    self.ops[new_op.get_id()] = new_op
                    setattr(new_op, "lookups", base_op.lookups)
                    for n, v in base_op.lookups.items():
                        v += v[-1:]

        # ENSURE THIS LANGUAGE INSTANCE POINTS TO ALL THE OPS BY NAME
        for o in self.ops[1:]:
            setattr(self, o.__name__, o)