from typing import Union from inspect import Parameter, Signature from ..primitives import Str, Float, Int, Bool, NoneType from ..array import Array, MaskedArray, Scalar, DType from ..containers import List, Tuple, Slice EMPTY = Parameter.empty VAR_P = Parameter.VAR_POSITIONAL VAR_KW = Parameter.VAR_KEYWORD KW_ONLY = Parameter.KEYWORD_ONLY Param = lambda name, annotation=None, default=EMPTY, kind=Parameter.POSITIONAL_OR_KEYWORD: Parameter( # noqa: E731 name, kind=kind, default=default, annotation=annotation) Sig = lambda parameters, return_annotation: Signature( # noqa: E731 parameters=parameters, return_annotation=return_annotation) # TODO: Once interpret-time compute is available, change Scalar return types to # more specific types, if possible NUMPY_SIGNATURES = { "all": [ Sig([Param("a", Array), Param("axis", Union[Int, List[Int]], None)], Array), Sig( [ Param("a", Union[Array, MaskedArray]), Param("axis", NoneType, None) ], Scalar, # TODO: Bool ),
def render(self, scene, camera): content = { "type": "render", "scene": to_json(scene, None), "camera": to_json(camera, None) } self.send(content) def freeze(self): content = {"type": "freeze"} self.send(content) if six.PY3: from inspect import Signature, Parameter # Include explicit signature since the metaclass screws it up parameters = [ Parameter('scene', Parameter.POSITIONAL_OR_KEYWORD), Parameter('camera', Parameter.POSITIONAL_OR_KEYWORD), Parameter('controls', Parameter.POSITIONAL_OR_KEYWORD, default=None), ] for name in ('width', 'height', 'background', 'background_opacity'): parameters.append( Parameter(name, Parameter.KEYWORD_ONLY, default=getattr(Renderer, name).default_value)) parameters.append(Parameter('kwargs', Parameter.VAR_KEYWORD)) Renderer.__signature__ = Signature(parameters=tuple(parameters)) del parameters
def make_signature(names): signature = Signature(Parameter(name, Parameter.POSITIONAL_OR_KEYWORD) for name in names) return signature
def _handleFunctionDef(self, node: Union[ast.AsyncFunctionDef, ast.FunctionDef], is_async: bool ) -> None: # Ignore inner functions. parent = self.builder.current if isinstance(parent, model.Function): return lineno = node.lineno if node.decorator_list: lineno = node.decorator_list[0].lineno docstring: Optional[ast.Str] = None if len(node.body) > 0 and isinstance(node.body[0], ast.Expr) \ and isinstance(node.body[0].value, ast.Str): docstring = node.body[0].value func_name = node.name is_property = False is_classmethod = False is_staticmethod = False if isinstance(parent, model.Class) and node.decorator_list: for d in node.decorator_list: if isinstance(d, ast.Call): deco_name = node2dottedname(d.func) else: deco_name = node2dottedname(d) if deco_name is None: continue if deco_name[-1].endswith('property') or deco_name[-1].endswith('Property'): is_property = True elif deco_name == ['classmethod']: is_classmethod = True elif deco_name == ['staticmethod']: is_staticmethod = True elif len(deco_name) >= 2 and deco_name[-1] in ('setter', 'deleter'): # Rename the setter/deleter, so it doesn't replace # the property object. func_name = '.'.join(deco_name[-2:]) if is_property: attr = self._handlePropertyDef(node, docstring, lineno) if is_classmethod: attr.report(f'{attr.fullName()} is both property and classmethod') if is_staticmethod: attr.report(f'{attr.fullName()} is both property and staticmethod') return func = self.builder.pushFunction(func_name, lineno) func.is_async = is_async if docstring is not None: func.setDocstring(docstring) func.decorators = node.decorator_list if is_staticmethod: if is_classmethod: func.report(f'{func.fullName()} is both classmethod and staticmethod') else: func.kind = 'Static Method' elif is_classmethod: func.kind = 'Class Method' # Position-only arguments were introduced in Python 3.8. posonlyargs: Sequence[ast.arg] = getattr(node.args, 'posonlyargs', ()) num_pos_args = len(posonlyargs) + len(node.args.args) defaults = node.args.defaults default_offset = num_pos_args - len(defaults) def get_default(index: int) -> Optional[ast.expr]: assert 0 <= index < num_pos_args, index index -= default_offset return None if index < 0 else defaults[index] parameters = [] def add_arg(name: str, kind: Any, default: Optional[ast.expr]) -> None: default_val = Parameter.empty if default is None else _ValueFormatter(default) parameters.append(Parameter(name, kind, default=default_val)) for index, arg in enumerate(posonlyargs): add_arg(arg.arg, Parameter.POSITIONAL_ONLY, get_default(index)) for index, arg in enumerate(node.args.args, start=len(posonlyargs)): add_arg(arg.arg, Parameter.POSITIONAL_OR_KEYWORD, get_default(index)) vararg = node.args.vararg if vararg is not None: add_arg(vararg.arg, Parameter.VAR_POSITIONAL, None) assert len(node.args.kwonlyargs) == len(node.args.kw_defaults) for arg, default in zip(node.args.kwonlyargs, node.args.kw_defaults): add_arg(arg.arg, Parameter.KEYWORD_ONLY, default) kwarg = node.args.kwarg if kwarg is not None: add_arg(kwarg.arg, Parameter.VAR_KEYWORD, None) try: signature = Signature(parameters) except ValueError as ex: func.report(f'{func.fullName()} has invalid parameters: {ex}') signature = Signature() func.signature = signature func.annotations = self._annotations_from_function(node) self.default(node) self.builder.popFunction()
def _make_foreach_signature(iterator_name: str, constant_params: tuple): params = [Parameter(name=iterator_name, kind=Parameter.KEYWORD_ONLY)] for param in constant_params: params.append(Parameter(name=param, kind=Parameter.KEYWORD_ONLY)) return Signature(parameters=params, return_annotation=tuple)
class TogglEntity(metaclass=TogglEntityMeta): """ Base class for all Toggl Entities. Simplest Entities consists only of fields declaration (eq. TogglField and its subclasses), but it is also possible to implement custom class or instance methods for specific tasks. This class handles serialization, saving new instances, updating the existing one, deletion etc. Support for these operation can be customized using _can_* attributes, by default everything is enabled. """ __signature__ = Signature() __fields__ = OrderedDict() _validate_workspace = True _can_create = True _can_update = True _can_delete = True _can_get_detail = True _can_get_list = True id = model_fields.IntegerField(required=False, default=None) objects = None # type: TogglSet def __init__(self, config=None, **kwargs): self._config = config or utils.Config.factory() self.__change_dict__ = {} for field in self.__fields__.values(): if field.name in {'id'}: continue if isinstance(field, model_fields.MappingField): # User supplied most probably the whole mapped object if field.name in kwargs: field.init(self, kwargs.get(field.name)) continue # Most probably converting API call with direct ID of the object if field.mapped_field in kwargs: field.init(self, kwargs.get(field.mapped_field)) continue if field.default is model_fields.NOTSET and field.required: raise TypeError('We need \'{}\' attribute!'.format( field.mapped_field)) continue if field.name not in kwargs: if field.default is model_fields.NOTSET and field.required: raise TypeError('We need \'{}\' attribute!'.format( field.name)) else: # Set the attribute only when there is some value to set, so default values could work properly field.init(self, kwargs[field.name]) def save(self, config=None): # type: (utils.Config) -> None """ Main method for saving the entity. If it is a new entity (eq. entity.id is not set), then calling this method will result in creation of new object using POST call. If this is already existing entity, then calling this method will result in updating of the object using PUT call. For updating the entity, only changed fields are sent (this is tracked using self.__change_dict__). Before the API call validations are performed on the instance and only after successful validation, the call is made. :raises exceptions.TogglNotAllowedException: When action (create/update) is not allowed. """ if not self._can_update and self.id is not None: raise exceptions.TogglNotAllowedException( 'Updating this entity is not allowed!') if not self._can_create and self.id is None: raise exceptions.TogglNotAllowedException( 'Creating this entity is not allowed!') config = config or self._config self.validate() if self.id is not None: # Update utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'put', self.json(update=True), config=config) self.__change_dict__ = {} # Reset tracking changes else: # Create data = utils.toggl('/{}'.format(self.get_url()), 'post', self.json(), config=config) self.id = data['data']['id'] # Store the returned ID def delete(self, config=None): # type: (utils.Config) -> None """ Method for deletion of the entity through API using DELETE call. This will not delete the instance's object in Python, therefore calling save() method after deletion will result in new object created using POST call. :raises exceptions.TogglNotAllowedException: When action is not allowed. """ if not self._can_delete: raise exceptions.TogglNotAllowedException( 'Deleting this entity is not allowed!') if not self.id: raise exceptions.TogglException( 'This instance has not been saved yet!') utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'delete', config=config or self._config) self.id = None # Invalidate the object, so when save() is called after delete a new object is created def json(self, update=False): # type: (bool) -> str """ Serialize the entity into JSON string. :param update: Specifies if the resulted JSON should contain only changed fields (for PUT call) or whole entity. """ return json.dumps({ self.get_name(): self.to_dict(serialized=True, changes_only=update) }) def validate(self): # type: () -> None """ Performs validation across all Entity's fields. If overloading then don't forget to call super().validate()! """ for field in self.__fields__.values(): try: value = field._get_value(self) except AttributeError: value = None field.validate(value, self) def to_dict(self, serialized=False, changes_only=False): # type: (bool, bool) -> typing.Dict """ Method that returns dict representing the instance. :param serialized: If True, the returned dict contains only Python primitive types and no objects (eq. so JSON serialization could happen) :param changes_only: If True, the returned dict contains only changes to the instance since last call of save() method. """ source_dict = self.__change_dict__ if changes_only else self.__fields__ entity_dict = {} for field_name in source_dict.keys(): try: field = self.__fields__[field_name] except KeyError: field = self.__mapped_fields__[field_name] try: value = field._get_value(self) except AttributeError: value = None if serialized: try: entity_dict[field.mapped_field] = field.serialize(value) except AttributeError: entity_dict[field.name] = field.serialize(value) else: entity_dict[field.name] = value return entity_dict def __eq__(self, other): # type: (typing.Generic[Entity]) -> bool if not isinstance(other, self.__class__): return False if self.id is None or other.id is None: raise RuntimeError( 'One of the instances was not yet saved! We can\'t compere unsaved instances!' ) return self.id == other.id # TODO: [Q/Design] Problem with unique field's. Copy ==> making invalid option ==> Some validation? def __copy__(self): # type: () -> typing.Generic[Entity] cls = self.__class__ new_instance = cls.__new__(cls) new_instance.__dict__.update(self.__dict__) new_instance.id = None # New instance was never saved ==> no ID for it yet return new_instance def __str__(self): # type: () -> str return '{} (#{})'.format( getattr(self, 'name', None) or self.__class__.__name__, self.id) @classmethod def get_name(cls, verbose=False): # type: (bool) -> str name = cls.__name__ name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower() if verbose: return name.replace('_', ' ').capitalize() return name @classmethod def get_url(cls): # type: () -> str return cls.get_name() + 's' @classmethod def deserialize( cls, config=None, **kwargs ): # type: (utils.Config, **typing.Any) -> typing.Generic[Entity] """ Method which takes kwargs as dict representing the Entity's data and return actuall instance of the Entity. """ try: kwargs.pop('at') except KeyError: pass instance = cls.__new__(cls) instance._config = config instance.__change_dict__ = {} for key, field in instance.__fields__.items(): try: value = kwargs[key] except KeyError: try: value = kwargs[field.mapped_field] except (KeyError, AttributeError): continue field.init(instance, value) return instance
def _create_signature(self, alg_name): from inspect import Signature return Signature(self._create_parameters(alg_name))
def helper_self(func): assert func.__text_signature__ == "($self)" assert signature(func) == Signature( [Parameter("self", Parameter.POSITIONAL_ONLY)])
def helper_offset(func): assert func.__text_signature__ == "($self, offset=0)" assert signature(func) == Signature([ Parameter("self", Parameter.POSITIONAL_ONLY), Parameter("offset", Parameter.POSITIONAL_OR_KEYWORD, default=0), ])
def make_signature(names): # Build a function signature object return Signature( Parameter(name, Parameter.POSITIONAL_OR_KEYWORD) for name in names)
def helper_single_param(func, *, param_name: str): """Check text_signature and signature for function with one parameter (except `self`)""" assert func.__text_signature__ == "({})".format(param_name) assert signature(func) == Signature( [Parameter(param_name, Parameter.POSITIONAL_OR_KEYWORD)])
a = Spam() b = Spam() a is b # True # 16.*args 和 kwargs 的强制签名 """ 使用 inspect 模块的 Signature 和 Parameter 来进行参数检查 """ # 首先使用 signature 创建签名对象 from inspect import Signature, Parameter params = [ Parameter('x', Parameter.POSITIONAL_OR_KEYWORD), Parameter('y', Parameter.POSITIONAL_OR_KEYWORD, default=42), Parameter('z', Parameter.KEYWORD_ONLY, default=None) ] sig = Signature(params) print(sig) # (x, y=42, *, z=None) # 使用 def func(*args, **kwargs): bind_value = sig.bind(*args, **kwargs) for name, value in bind_value.arguments.items(): print(name, value) func(1, 2, 3) func(1, 2, 3, 4) # ERROR # 强制所有子类必须提供特定参数签名的例子
def test_instance_method(): r"""Ensure instance methods' signature.""" assert hasattr(ResRNNBlock, '__init__') assert inspect.signature(ResRNNBlock.__init__) == Signature( parameters=[ Parameter( name='self', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, ), Parameter( name='d_hid', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='p_hid', kind=Parameter.KEYWORD_ONLY, annotation=float, default=Parameter.empty, ), Parameter( name='kwargs', kind=Parameter.VAR_KEYWORD, annotation=Optional[Dict], ), ], return_annotation=Signature.empty, ) assert hasattr(ResRNNBlock, 'forward') assert inspect.signature(ResRNNBlock.forward) == Signature( parameters=[ Parameter( name='self', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, ), Parameter( name='batch_tk_reps', kind=Parameter.POSITIONAL_OR_KEYWORD, annotation=torch.Tensor, default=Parameter.empty, ), ], return_annotation=torch.Tensor, ) assert hasattr(ResRNNModel, '__init__') assert inspect.signature(ResRNNModel.__init__) == Signature( parameters=[ Parameter( name='self', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, ), Parameter( name='d_emb', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='d_hid', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_post_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_pre_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='p_emb', kind=Parameter.KEYWORD_ONLY, annotation=float, default=Parameter.empty, ), Parameter( name='p_hid', kind=Parameter.KEYWORD_ONLY, annotation=float, default=Parameter.empty, ), Parameter( name='tknzr', kind=Parameter.KEYWORD_ONLY, annotation=BaseTknzr, default=Parameter.empty, ), Parameter( name='kwargs', kind=Parameter.VAR_KEYWORD, annotation=Optional[Dict], ), ], return_annotation=Signature.empty, )
from inspect import signature, Signature, Parameter def func(a, b=42, *args, d=None, **kwargs): pass if __name__ == '__main__': sig1 = signature(func) print(sig1) parms = [ Parameter('a', Parameter.POSITIONAL_OR_KEYWORD), Parameter('b', Parameter.POSITIONAL_OR_KEYWORD, default=42), Parameter('args', Parameter.VAR_POSITIONAL), Parameter('d', Parameter.KEYWORD_ONLY, default=None), Parameter('kwargs', Parameter.VAR_KEYWORD) ] sig2 = Signature(parms) print(sig2) print(f'sig1 == sig2: {sig1 == sig2}')
def test_instance_method(): r"""Ensure instance methods' signature.""" assert hasattr(SAttnLSTMBlock, '__init__') assert inspect.signature(SAttnLSTMBlock.__init__) == Signature(parameters=[ Parameter( name='self', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, ), Parameter( name='d_hid', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='p_hid', kind=Parameter.KEYWORD_ONLY, annotation=float, default=Parameter.empty, ), Parameter( name='kwargs', kind=Parameter.VAR_KEYWORD, annotation=Optional[Dict], ), ], ) assert hasattr(SAttnLSTMModel, '__init__') assert inspect.signature(SAttnLSTMModel.__init__) == Signature(parameters=[ Parameter( name='self', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, ), Parameter( name='d_emb', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='d_hid', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_post_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='n_pre_hid_lyr', kind=Parameter.KEYWORD_ONLY, annotation=int, default=Parameter.empty, ), Parameter( name='p_emb', kind=Parameter.KEYWORD_ONLY, annotation=float, default=Parameter.empty, ), Parameter( name='p_hid', kind=Parameter.KEYWORD_ONLY, annotation=float, default=Parameter.empty, ), Parameter( name='tknzr', kind=Parameter.KEYWORD_ONLY, annotation=BaseTknzr, default=Parameter.empty, ), Parameter( name='kwargs', kind=Parameter.VAR_KEYWORD, annotation=Optional[Dict], ), ], )
def ufunc(np_ufunc, return_type_override=None): if not isinstance(np_ufunc, np.ufunc): raise TypeError("Must be an instance of `np.ufunc`, got {}".format( type(np_ufunc))) def wf_ufunc(*args): if len(args) != np_ufunc.nin: raise TypeError( "Invalid number of arguments to function `{}`".format( np_ufunc.__name__)) # Since typecheck_promote doesn't support variadic arguments, manually # attempt to promote each argument to an Array or scalar promoted = [] for i, arg in enumerate(args): try: if isinstance(arg, BaseArray): promoted.append(arg) elif isinstance(arg, np.ma.core.MaskedArray): promoted.append(MaskedArray._promote(arg)) elif isinstance(arg, np.ndarray): promoted.append(Array._promote(arg)) else: promoted.append( _promote(arg, (Bool, Int, Float, Scalar), i, np_ufunc.__name__)) # TODO(gabe) not great to be relying on internal `_promote` here except (ProxyTypeError, TypeError): raise ProxyTypeError( "Argument {} to function {} must be a Workflows Array, Scalar, Int, Float," "Bool, or a type promotable to one of those, not {}". format(i + 1, np_ufunc.__name__, type(arg))) return_type = _ufunc_result_type( *promoted, return_type_override=return_type_override) return return_type._from_apply("wf.numpy." + np_ufunc.__name__, *promoted) HANDLED_UFUNCS[np_ufunc.__name__] = wf_ufunc copy_docstring_from_numpy(wf_ufunc, np_ufunc) # create an inspect.Signature object return_annotation = (return_type_override if return_type_override is not None else Union[Array, MaskedArray, Scalar, Int, Float, Bool]) if np_ufunc.nin == 2: signature = Signature( [ Parameter( "x1", Parameter.POSITIONAL_OR_KEYWORD, annotation=Union[Array, MaskedArray, Scalar, Int, Float, Bool], ), Parameter( "x2", Parameter.POSITIONAL_OR_KEYWORD, annotation=Union[Array, MaskedArray, Scalar, Int, Float, Bool], ), ], return_annotation=return_annotation, ) else: signature = Signature( [ Parameter( "x", Parameter.POSITIONAL_OR_KEYWORD, annotation=Union[Array, MaskedArray, Scalar, Int, Float, Bool], ) ], return_annotation=return_annotation, ) # set __annotations__ if "sphinx" not in sys.modules: wf_ufunc.__annotations__ = { name: param.annotation for name, param in signature.parameters.items() } wf_ufunc.__annotations__["return"] = signature.return_annotation # set __signature__ to the stringified version wf_ufunc.__signature__ = stringify_signature(signature) # forward attributes wf_ufunc.nin = np_ufunc.nin wf_ufunc.nargs = np_ufunc.nargs wf_ufunc.nout = np_ufunc.nout wf_ufunc.ntypes = np_ufunc.ntypes wf_ufunc.identity = np_ufunc.identity wf_ufunc.signature = np_ufunc.signature wf_ufunc.types = np_ufunc.types # NOTE: we currently don't support other attributes of ufuncs (besides `__call__`) wf_ufunc.reduce = lambda *args: raise_( NotImplementedError( "The `reduce` ufunc method is not supported by Workflows types")) wf_ufunc.reduceat = lambda *args: raise_( NotImplementedError( "The `reduceat` ufunc method is not supported by Workflows types")) wf_ufunc.accumulate = lambda *args: raise_( NotImplementedError( "The `accumulate` ufunc method is not supported by Workflows types" )) wf_ufunc.outer = lambda *args: raise_( NotImplementedError( "The `outer` ufunc method is not supported by Workflows types")) return wf_ufunc
def make_signature(fields): return Signature( Parameter(field, Parameter.POSITIONAL_OR_KEYWORD) for field in fields)
def __init__(self, backends: Sequence[BaseAuthentication], user_db: BaseUserDatabase): self.backends = backends self.user_db = user_db parameters = [ Parameter(name=name_to_variable_name(backend.name), kind=Parameter.POSITIONAL_OR_KEYWORD, default=Depends(backend.scheme)) for backend in self.backends ] signature = Signature(parameters) @with_signature(signature, func_name='get_optional_current_user') async def get_optional_current_user(*args, **kwargs): return await self.authenticate(*args, **kwargs) @with_signature(signature, func_name='get_optional_current_active_user') async def get_optional_current_active_user(*args, **kwargs): user = await get_optional_current_user(*args, **kwargs) if not user or not user.is_active: return None return user @with_signature(signature, func_name='get_optional_current_superuser') async def get_optional_current_superuser(*args, **kwargs): user = await get_optional_current_active_user(*args, **kwargs) if not user or not user.is_superuser: return None return user @with_signature(signature, func_name='get_current_user') async def get_current_user(*args, **kwargs): user = await get_optional_current_user(*args, **kwargs) if user is None: raise HTTPException(status_code=403, detail='You do not have the permission') return user @with_signature(signature, func_name='get_current_active_user') async def get_current_active_user(*args, **kwargs): user = await get_optional_current_active_user(*args, **kwargs) if user is None: raise HTTPException(status_code=403, detail='You do not have the permission') return user @with_signature(signature, func_name='get_current_superuser') async def get_current_superuser(*args, **kwargs): user = await get_optional_current_active_user(*args, **kwargs) if user is None: raise HTTPException(status_code=403, detail='You do not have the permission') if not user.is_superuser: raise HTTPException(status_code=403, detail='You need to be superuser') return user self.get_current_user = get_current_user self.get_current_active_user = get_current_active_user self.get_optional_current_active_user = get_optional_current_active_user self.get_optional_current_superuser = get_optional_current_superuser self.get_optional_current_user = get_optional_current_user self.get_current_superuser = get_current_superuser
def make_sig(*names): parms = [ Parameter(name, Parameter.POSITIONAL_OR_KEYWORD) for name in names ] return Signature(parms)
class Sample: __signature__ = Signature(parameters=[Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
def generate_model_signature( init: Callable[..., None], fields: Dict[str, 'ModelField'], config: Type['BaseConfig'] ) -> 'Signature': """ Generate signature for model based on its fields """ from inspect import Parameter, Signature, signature present_params = signature(init).parameters.values() merged_params: Dict[str, Parameter] = {} var_kw = None use_var_kw = False for param in islice(present_params, 1, None): # skip self arg if param.kind is param.VAR_KEYWORD: var_kw = param continue merged_params[param.name] = param if var_kw: # if custom init has no var_kw, fields which are not declared in it cannot be passed through allow_names = config.allow_population_by_field_name for field_name, field in fields.items(): param_name = field.alias if field_name in merged_params or param_name in merged_params: continue elif not param_name.isidentifier(): if allow_names and field_name.isidentifier(): param_name = field_name else: use_var_kw = True continue # TODO: replace annotation with actual expected types once #1055 solved kwargs = {'default': field.default} if not field.required else {} merged_params[param_name] = Parameter( param_name, Parameter.KEYWORD_ONLY, annotation=field.outer_type_, **kwargs ) if config.extra is config.extra.allow: use_var_kw = True if var_kw and use_var_kw: # Make sure the parameter for extra kwargs # does not have the same name as a field default_model_signature = [ ('__pydantic_self__', Parameter.POSITIONAL_OR_KEYWORD), ('data', Parameter.VAR_KEYWORD), ] if [(p.name, p.kind) for p in present_params] == default_model_signature: # if this is the standard model signature, use extra_data as the extra args name var_kw_name = 'extra_data' else: # else start from var_kw var_kw_name = var_kw.name # generate a name that's definitely unique while var_kw_name in fields: var_kw_name += '_' merged_params[var_kw_name] = var_kw.replace(name=var_kw_name) return Signature(parameters=list(merged_params.values()), return_annotation=None)
def _mk_sig(req_args, def_args): "Create a signature object with required and default arguments" params = [_mk_param(k) for k in req_args] params += [_mk_param(k, default=v) for k, v in def_args.items()] return Signature(params)
def _make_mapping_signature(iterator_keys: tuple): params = [Parameter(name=key, kind=Parameter.KEYWORD_ONLY) for key in iterator_keys] params.append(Parameter(name="kwargs", kind=Parameter.VAR_KEYWORD)) return Signature(parameters=params, return_annotation=MappedModel)
def _get_setter_fun( cls, # type: Type property_name, # type: str type_hint, # type: Any default_value, # type: Any private_property_name, # type: str overridden_setter=AUTO # type: Callable ): """ Utility method to find the overridden setter function for a given property, or generate a new one :param cls: :param property_name: :param type_hint: :param default_value: :param private_property_name: :param overridden_setter: an already found overridden setter to use. If AUTO is provided (default), the class will be inspected to find them :return: """ if overridden_setter is AUTO: # If not provided - look for an overridden setter in the class overridden_setters = getmembers(cls, predicate=_has_annotation( __SETTER_OVERRIDE_ANNOTATION, property_name)) if len(overridden_setters) > 1: raise DuplicateOverrideError( 'Setter is overridden more than once for attribute name : %s' % property_name) else: try: overridden_setter = overridden_setters[0][1] except IndexError: pass if overridden_setter is not None: # --use the overridden setter found/provided setter_fun = overridden_setter try: # python 2 - possibly unbind the function setter_fun = setter_fun.im_func except AttributeError: pass # --find the parameter name and check the signature s = signature(setter_fun) p = [ attribute_name for attribute_name, param in s.parameters.items() if attribute_name is not 'self' ] if len(p) != 1: raise IllegalSetterSignatureException( 'overridden setter %s should have 1 and only 1 non-self argument, ' 'found %s' % (setter_fun.__name__, s)) actual_arg_name = p[0] else: # --create the setter: Dynamically compile a wrapper with correct argument name sig = Signature(parameters=[ Parameter('self', kind=Parameter.POSITIONAL_OR_KEYWORD), Parameter(property_name, kind=Parameter.POSITIONAL_OR_KEYWORD, annotation=type_hint, default=default_value) ]) @with_signature(sig) def autoprops_generated_setter(self, **kwargs): """ generated by `autoprops` - setter for a property """ setattr(self, private_property_name, kwargs[property_name]) setter_fun = autoprops_generated_setter actual_arg_name = property_name return setter_fun, actual_arg_name
""" 我们已经编写了一个使用*args和**kwargs作为参数的函数或者方法,这样使得函数成为通用型(可接受任意数量和类型的参数), 但是,我们也想对传入的参数做检查,看看它们是否匹配了某个特定的函数调用签名。 """ #关于操作函数调用签名的问题,都应该使用inspect模块中的相应功能 from inspect import Signature from inspect import Parameter #Make a signature for a func(x,y=42,*,z = None) parms = [ Parameter('x', Parameter.POSITIONAL_OR_KEYWORD), Parameter('y', Parameter.POSITIONAL_OR_KEYWORD, default=42), Parameter('z', Parameter.KEYWORD_ONLY, default=None) ] sig = Signature(parms) print(sig) #(x, y=42, *, z=None) #一旦有了签名对象,就可以通过对象的bind()方法轻松的将其绑定到*args和**kwargs上 def func(*args, **kwargs): bound_values = sig.bind(*args, **kwargs) for name, value in bound_values.arguments.items(): print(name, value) func(1, 2, z=3) #x 1 #y 2 #z 3 func(1)
def _create_builder(cls, element, completions): def builder(cls, spec=None, **kws): spec = element if spec is None else '%s.%s' % (element, spec) prefix = 'In opts.{element}(...), '.format(element=element) backend = kws.get('backend', None) keys = set(kws.keys()) if backend: allowed_kws = cls._element_keywords(backend, elements=[element ])[element] invalid = keys - set(allowed_kws) else: mismatched = {} all_valid_kws = set() for loaded_backend in Store.loaded_backends(): valid = set( cls._element_keywords(loaded_backend).get(element, [])) all_valid_kws |= set(valid) if keys <= valid: # Found a backend for which all keys are valid return Options(spec, **kws) mismatched[loaded_backend] = list(keys - valid) invalid = keys - all_valid_kws # Keys not found for any backend if mismatched and not invalid: # Keys found across multiple backends msg = ( '{prefix} keywords supplied are mixed across backends. ' 'Keyword(s) {info}') info = ', '.join('%s are invalid for %s' % (', '.join(repr(el) for el in v), k) for k, v in mismatched.items()) raise ValueError(msg.format(info=info, prefix=prefix)) allowed_kws = completions reraise = False if invalid: try: cls._options_error( list(invalid)[0], element, backend, allowed_kws) except ValueError as e: msg = str(e)[0].lower() + str(e)[1:] reraise = True if reraise: raise ValueError(prefix + msg) return Options(spec, **kws) filtered_keywords = [ k for k in completions if k not in cls._no_completion ] sorted_kw_set = sorted(set(filtered_keywords)) if sys.version_info.major == 2: kws = ', '.join('{opt}=None'.format(opt=opt) for opt in sorted_kw_set) builder.__doc__ = '{element}({kws})'.format(element=element, kws=kws) else: from inspect import Parameter, Signature signature = Signature( [Parameter('spec', Parameter.POSITIONAL_OR_KEYWORD)] + [ Parameter(kw, Parameter.KEYWORD_ONLY) for kw in sorted_kw_set ]) builder.__signature__ = signature return classmethod(builder)
def make_signature(names): """Make a namedtuple-like signature from a list of field names.""" return Signature( Parameter(name, Parameter.POSITIONAL_OR_KEYWORD) for name in names)
import pytest __all__ = ['simplified_test_function'] # Pytest determines the signature of the test function by unpacking any # wrapped functions (this is the default of the signature() function it # uses. We correct this behavior by setting the __signature__ attribute of # the wrapper function to its correct signature. To do that, we cannot use # signature() because its follow_wrapped parameter was introduced only in # Python 3.5. Instead, we build the signature manually. TESTFUNC_SIGNATURE = Signature( parameters=[ Parameter('desc', Parameter.POSITIONAL_OR_KEYWORD), Parameter('kwargs', Parameter.POSITIONAL_OR_KEYWORD), Parameter('exp_exc_types', Parameter.POSITIONAL_OR_KEYWORD), Parameter('exp_warn_types', Parameter.POSITIONAL_OR_KEYWORD), Parameter('condition', Parameter.POSITIONAL_OR_KEYWORD), ] ) def simplified_test_function(test_func): """ A decorator for test functions that simplifies the test function by handling a number of things: * Skipping the test if the `condition` item in the testcase is `False`, * Invoking the Python debugger if the `condition` item in the testcase is the string "pdb", * Capturing and validating any warnings issued by the test function,
def make_signature(names): return Signature( [Parameter(name, Parameter.POSITIONAL_OR_KEYWORD) for name in names])
def test_module_function(): """Ensure module function's signature.""" assert inspect.isfunction(lmp.util.model.create) assert inspect.signature(lmp.util.model.create) == Signature( parameters=[ Parameter( name='model_name', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, annotation=str, ), Parameter( name='kwargs', kind=Parameter.VAR_KEYWORD, annotation=Optional[Dict], ), ], return_annotation=BaseModel, ) assert inspect.isfunction(lmp.util.model.load) assert inspect.signature(lmp.util.model.load) == Signature( parameters=[ Parameter( name='ckpt', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, annotation=int, ), Parameter( name='exp_name', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, annotation=str, ), Parameter( name='model_name', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, annotation=str, ), Parameter( name='kwargs', kind=Parameter.VAR_KEYWORD, annotation=Optional[Dict], ), ], return_annotation=BaseModel, ) assert inspect.isfunction(lmp.util.model.list_ckpts) assert inspect.signature(lmp.util.model.list_ckpts) == Signature( parameters=[ Parameter( name='exp_name', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, annotation=str, ), Parameter( name='first_ckpt', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, annotation=int, ), Parameter( name='last_ckpt', kind=Parameter.POSITIONAL_OR_KEYWORD, default=Parameter.empty, annotation=int, ), ], return_annotation=List[int], )