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
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
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
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
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