Ejemplo n.º 1
0
    def __new__(cls, name, bases, attrs):
        klass = super().__new__(cls, name, bases, attrs)

        if name == "ServicePartBase":
            return klass

        if len(bases) == 1 and bases[0].__name__ == "ServicePartBase":
            return klass

        for base in bases:
            if any(b.__name__ == "ServicePartBase" for b in base.__bases__):
                break
        else:
            raise RuntimeError(f"Could not find ServicePartBase among bases of these classes: {bases!r}")

        for name, original_method in inspect.getmembers(base, predicate=inspect.isfunction):
            new_method = attrs.get(name)
            if new_method is None:
                raise RuntimeError(f"{klass!r} does not define method {name!r} that is defined in it's base {base!r}")

            if hasattr(original_method, "wraps"):
                original_argspec = inspect.getfullargspec(original_method.wraps)
            else:
                original_argspec = inspect.getfullargspec(original_method)
            if original_argspec != inspect.getfullargspec(new_method):
                raise RuntimeError(f"Signature for method {name!r} does not match between {klass!r} and it's base "
                                   f"{base!r}")

            copy_function_metadata(original_method, new_method)

            if hasattr(original_method, "wrap"):
                new_method = original_method.wrap(new_method)
                setattr(klass, name, new_method)

        return klass
Ejemplo n.º 2
0
    def returns_internal(f):
        if asyncio.iscoroutinefunction(f):

            async def nf(*args, **kwargs):
                res = await f(*args, **kwargs)
                if conf.debug_mode:
                    validate_return_type(f, res, nf.returns)
                return res
        else:

            def nf(*args, **kwargs):
                res = f(*args, **kwargs)
                if conf.debug_mode:
                    validate_return_type(f, res, nf.returns)
                return res

        from middlewared.utils.type import copy_function_metadata
        copy_function_metadata(f, nf)
        nf.wraps = f
        for s in list(schema):
            s.name = s.name or f.__name__
            if hasattr(s, 'title'):
                s.title = s.title or s.name
        nf.returns = list(schema)
        return nf
Ejemplo n.º 3
0
    def wrap(func):
        f = func.wraps if hasattr(func, 'wraps') else func
        if inspect.getfullargspec(f).defaults:
            raise ValueError("All public method default arguments should be specified in @accepts()")

        # Make sure number of schemas is same as method argument
        args_index = 0
        if f.__code__.co_argcount >= 1 and f.__code__.co_varnames[0] == 'self':
            args_index += 1
        if hasattr(f, '_pass_app'):
            args_index += 1
        if hasattr(f, '_job'):
            args_index += 1
        if hasattr(f, '_skip_arg'):
            args_index += f._skip_arg
        assert len(schema) == f.__code__.co_argcount - args_index  # -1 for self

        def clean_and_validate_args(args, kwargs):
            args = list(args)

            common_args = args[:args_index]
            signature_args = args[args_index:]

            had_warning = False
            for check, adapt in deprecated:
                if check(signature_args):
                    if not had_warning:
                        warnings.warn(f"Method {f!r} was called with a deprecated signature", DeprecationWarning)
                        had_warning = True
                    signature_args = adapt(*signature_args)

            args = common_args + copy.deepcopy(signature_args)
            kwargs = copy.deepcopy(kwargs)

            verrors = ValidationErrors()

            # Iterate over positional args first, excluding self
            i = 0
            if len(args[args_index:]) > len(nf.accepts):
                raise CallError(f'Too many arguments (expected {len(nf.accepts)}, found {len(args[args_index:])})')
            for _ in args[args_index:]:
                args[args_index + i] = clean_and_validate_arg(verrors, nf.accepts[i], args[args_index + i])
                i += 1

            # Use i counter to map keyword argument to rpc positional
            for x in list(range(i + args_index, f.__code__.co_argcount)):
                kwarg = f.__code__.co_varnames[x]

                if kwarg in kwargs:
                    attr = nf.accepts[i]
                    i += 1

                    value = kwargs[kwarg]
                elif len(nf.accepts) >= i + 1:
                    attr = nf.accepts[i]
                    i += 1
                    value = NOT_PROVIDED
                else:
                    i += 1
                    continue

                kwargs[kwarg] = clean_and_validate_arg(verrors, attr, value)

            if verrors:
                raise verrors

            return args, kwargs

        if asyncio.iscoroutinefunction(func):
            async def nf(*args, **kwargs):
                args, kwargs = clean_and_validate_args(args, kwargs)
                return await func(*args, **kwargs)
        else:
            def nf(*args, **kwargs):
                args, kwargs = clean_and_validate_args(args, kwargs)
                return func(*args, **kwargs)

        from middlewared.utils.type import copy_function_metadata
        copy_function_metadata(f, nf)
        nf.accepts = list(schema)
        if hasattr(func, 'returns'):
            nf.returns = func.returns
        nf.wraps = f
        nf.wrap = wrap

        return nf
Ejemplo n.º 4
0
    def wrap(f):
        if inspect.getfullargspec(f).defaults:
            raise ValueError(
                "All public method default arguments should be specified in @accepts()"
            )

        # Make sure number of schemas is same as method argument
        args_index = 0
        if f.__code__.co_argcount >= 1 and f.__code__.co_varnames[0] == 'self':
            args_index += 1
        if hasattr(f, '_pass_app'):
            args_index += 1
        if hasattr(f, '_job'):
            args_index += 1
        if hasattr(f, '_skip_arg'):
            args_index += f._skip_arg
        assert len(
            schema) == f.__code__.co_argcount - args_index  # -1 for self

        def clean_and_validate_args(args, kwargs):
            args = list(args)
            args = args[:args_index] + copy.deepcopy(args[args_index:])
            kwargs = copy.deepcopy(kwargs)

            verrors = ValidationErrors()

            def clean_and_validate_arg(attr, arg):
                try:
                    value = attr.clean(arg)
                    attr.validate(value)
                    return value
                except Error as e:
                    verrors.add(e.attribute, e.errmsg, e.errno)
                except ValidationErrors as e:
                    verrors.extend(e)

            # Iterate over positional args first, excluding self
            i = 0
            for _ in args[args_index:]:
                args[args_index + i] = clean_and_validate_arg(
                    nf.accepts[i], args[args_index + i])
                i += 1

            # Use i counter to map keyword argument to rpc positional
            for x in list(range(i + args_index, f.__code__.co_argcount)):
                kwarg = f.__code__.co_varnames[x]

                if kwarg in kwargs:
                    attr = nf.accepts[i]
                    i += 1

                    value = kwargs[kwarg]
                elif len(nf.accepts) >= i + 1:
                    attr = nf.accepts[i]
                    i += 1
                    value = NOT_PROVIDED
                else:
                    i += 1
                    continue

                kwargs[kwarg] = clean_and_validate_arg(attr, value)

            if verrors:
                raise verrors

            return args, kwargs

        if asyncio.iscoroutinefunction(f):

            async def nf(*args, **kwargs):
                args, kwargs = clean_and_validate_args(args, kwargs)
                return await f(*args, **kwargs)
        else:

            def nf(*args, **kwargs):
                args, kwargs = clean_and_validate_args(args, kwargs)
                return f(*args, **kwargs)

        from middlewared.utils.type import copy_function_metadata
        copy_function_metadata(f, nf)
        nf.accepts = list(schema)
        nf.wraps = f
        nf.wrap = wrap

        return nf
Ejemplo n.º 5
0
    def wrap(f):
        # Make sure number of schemas is same as method argument
        args_index = 1
        if hasattr(f, '_pass_app'):
            args_index += 1
        if hasattr(f, '_job'):
            args_index += 1
        if hasattr(f, '_skip_arg'):
            args_index += f._skip_arg
        assert len(schema) == f.__code__.co_argcount - args_index  # -1 for self

        def clean_and_validate_args(args, kwargs):
            args = list(args)
            args = args[:args_index] + copy.deepcopy(args[args_index:])
            kwargs = copy.deepcopy(kwargs)

            verrors = ValidationErrors()

            # Iterate over positional args first, excluding self
            i = 0
            for _ in args[args_index:]:
                attr = nf.accepts[i]

                value = attr.clean(args[args_index + i])
                args[args_index + i] = value

                try:
                    attr.validate(value)
                except ValidationErrors as e:
                    verrors.extend(e)

                i += 1

            # Use i counter to map keyword argument to rpc positional
            for x in list(range(i + args_index, f.__code__.co_argcount)):
                kwarg = f.__code__.co_varnames[x]

                if kwarg in kwargs:
                    attr = nf.accepts[i]
                    i += 1

                    value = kwargs[kwarg]
                elif len(nf.accepts) >= i + 1:
                    attr = nf.accepts[i]
                    i += 1
                    value = NOT_PROVIDED
                else:
                    i += 1
                    continue

                value = attr.clean(value)
                kwargs[kwarg] = value

                try:
                    attr.validate(value)
                except ValidationErrors as e:
                    verrors.extend(e)

            if verrors:
                raise verrors

            return args, kwargs

        if asyncio.iscoroutinefunction(f):
            async def nf(*args, **kwargs):
                args, kwargs = clean_and_validate_args(args, kwargs)
                return await f(*args, **kwargs)
        else:
            def nf(*args, **kwargs):
                args, kwargs = clean_and_validate_args(args, kwargs)
                return f(*args, **kwargs)

        from middlewared.utils.type import copy_function_metadata
        copy_function_metadata(f, nf)
        nf.accepts = list(schema)
        nf.wraps = f
        nf.wrap = wrap

        return nf