Пример #1
0
    def __init__(self, module: BaseEstimator):
        """

        Parameters
        ----------
        module : :class:`sklearn.base.BaseEstimator`
            the module to wrap
        """

        super().__init__()

        self.module = module

        # forwards methods to self.module if necessary

        for key in ["fit", "partial_fit", "predict"]:
            if hasattr(self.module, key):
                setattr(self, key, getattr(self.module, key))

        # if estimator is build dynamically based on input, classes have to
        # be passed at least at first time (we pass it every time), because
        # not every class is present in  every batch
        # variable is initialized here, but feeded during the training
        if (self.iterative_training
                and "classes" in get_signature(self.partial_fit).parameters):
            self.classes = None
Пример #2
0
def patch_endpoint_signature(
    endpoint: Callable,
    handler: Callable = None,
    dependencies: Iterable[Tuple[str, Type]] = None,
) -> Callable:
    signature = get_signature(endpoint)
    parameters = chain(
        _build_dependencies_parameters(dependencies or ()),
        _get_signature_parameters(signature),
        _get_signature_parameters(get_signature(handler)) if handler else [],
    )
    # Parameters defined in handler function can overlap predefined ones from dependencies,
    # so we need to filter it out, as dependency/endpoint params have greater priority
    unique_parameters: List[Parameter] = []
    pos_param_index = 0
    for param in distinct(parameters, attrgetter('name')):
        if param.kind in _POS_PARAM_KINDS:
            unique_parameters.insert(pos_param_index, param)
            pos_param_index += 1
        else:
            unique_parameters.append(param)
    endpoint.__signature__ = signature.replace(parameters=unique_parameters)  # type: ignore
    return endpoint
Пример #3
0
def xf_api(f, name=None):
    """decorator to apply to the entry points of the transforms module"""
    api_call = name if name is not None else f.__name__

    if not api_call in API:
        raise RuntimeError("'%s' is not part of the transforms API.")

    try:
        fn_def = globals()['DEF_' + api_call]
    except KeyError:
        # This happens if there is no definition for the decorated function
        raise RuntimeError("'%s' definition not found." % api_call)

    try:
        # python 2
        _string_type = basestring
    except NameError:
        # This will happen on python 3
        _string_type = str

    try:
        if not (isinstance(fn_def.__doc__, _string_type)
                and callable(fn_def._PRECOND) and callable(fn_def._POSTCOND)
                and callable(fn_def._signature)):
            raise Exception()
    except Exception:
        # A valid definition requires a string doc, and callable _PRECOND,
        # _POSTCOND and _signature.
        #
        # __doc__ will become the decorated function's documentation.
        # _PRECOND will be run on every call with args and kwargs
        # _POSTCOND will be run on every call with result, args and kwargs
        # _signature will be used to enforce a signature on implementations.
        #
        # _PRECOND and _POSTCOND will only be called if CHECK_API is enabled,
        # as they will slow down execution.
        raise RuntimeError("'{0}' definition error.".format(api_call))

    # Sanity check: make sure the decorated function has the expected signature.
    if get_signature is not None:
        # Check that the function has the right signature
        if get_signature(fn_def._signature) != get_signature(f):
            raise RuntimeError("'{0}' signature mismatch.".format(api_call))

    # At this point use a wrapper that calls pre and post conditions if checking
    # is enabled, otherwise leave the function "as is".
    if CHECK_API:

        @functools.wraps(f, assigned={"__doc__": fn_def.__doc__})
        def wrapper(*args, **kwargs):
            fn_def._PRECOND(*args, **kwargs)
            result = f(*args, **kwargs)
            fn_def._POSTCOND(result, *args, **kwargs)
            return result

        return wrapper
    else:
        # just try to put the right documentation on the function
        try:
            f.__doc__ = fn_def.__doc__
        except Exception:
            pass
        return f
Пример #4
0
def _syntax_rule(f, transformer, debug):
    mangle = str(time()).replace(".", "_")

    assert isinstance(f, FunctionType)
    sio = StringIO()

    code_deparse(f.__code__, out=sio)
    func_body_codestr = sio.getvalue()

    # `func_body_codestr` has no info of function head,
    # thus we should get the header manually.
    signature = get_signature(f)

    # for Python 3.6-, we should get the
    # correct order of function parameters.
    varnames = f.__code__.co_varnames
    params = sorted(signature.parameters.items(),
                    key=lambda pair: varnames.index(pair[0]))

    # Now, note that not all default value of a parameter
    # can be represented(via `repr`) directly. Say,
    #
    # ```
    # class S: pass
    # def f(a=S()):
    #   pass
    # ```
    #
    # in above codes you just cannot deparse the code object
    # into source code like
    #   `def f(a=<__main__.S object at 0x7f8c8c1692e8>): ...
    #
    # Also similar issues get raised up if any free variable here.
    #
    # As a result, please check my following codes for resolutions.

    freevars = {}
    for (name, param) in params:
        can_have_objects = ("default", "annotation")
        for obj_name in can_have_objects:
            obj = getattr(param, obj_name)
            if obj is not empty:
                # mangling here
                var_name = "_%s_%d" % (mangle, len(freevars))
                freevars[var_name] = obj
                setattr(param, "_" + obj_name, Var(var_name))

    for name, freevar in zip(f.__code__.co_freevars, f.__closure__ or ()):
        freevars[name] = freevar.cell_contents

    # the function header
    header = "def {name}{sig}:".format(name=f.__name__, sig=str(signature))
    func_def_codestr = header + "\n" + indent(func_body_codestr,
                                              prefix=" " * 2)

    fn_ast = ast.parse(func_def_codestr).body[0]
    if debug:
        print_ast(fn_ast)

    # perform your transformation on the function's AST.
    fn_ast = transformer(fn_ast)

    # debug
    if debug:
        ast.fix_missing_locations(fn_ast)
        print_ast(fn_ast)

    # Now we have all code piece for the function definition, but we
    # should handle the closures/default args.
    freevars = list(freevars.items())

    ast_for_all = ast.FunctionDef(
        # also mangling here
        name=".closure_func",
        args=ast.arguments(
            args=[
                ast.arg(arg=freevar_name, annotation=None)
                for (freevar_name, _) in freevars
            ],
            vararg=None,
            kwonlyargs=[],
            kw_defaults=[],
            kwarg=None,
            defaults=[],
        ),
        body=[fn_ast, ast.Return(ast.Name(f.__name__, ctx=ast.Load()))],
        decorator_list=[],
        returns=None,
    )
    ast.fix_missing_locations(ast_for_all)

    code = compile(ast.Module([ast_for_all]), f.__code__.co_filename, "exec")

    exec(code, f.__globals__)
    closure_func = f.__globals__['.closure_func']
    del f.__globals__['.closure_func']
    return closure_func(*[var for (_, var) in freevars])