def callback(self, function: CallbackType[P]) -> None: if not inspect.iscoroutinefunction(function): raise TypeError( f"The callback for the command {function.__name__!r} must be a coroutine function." ) function = function.__func__ if inspect.ismethod( function) else function # HelpCommand.command_callback annotations = get_type_hints(function) for name, annotation in annotations.items(): if get_origin(annotation) is converters.Greedy and isinstance( annotation.converter, ForwardRef): annotations[name] = converters.Greedy[eval( annotation.converter.__forward_code__, function.__globals__)] function.__annotations__ = annotations self.params: dict[str, inspect.Parameter] = dict( inspect.signature(function).parameters) if not self.params: raise ClientException( f'Callback for {self.name} command is missing a "ctx" parameter.' ) from None self.module = function.__module__ self._callback = function
def attr___annotations__(self): obj = node_classes.Dict(parent=self._instance) if not self._instance.returns: returns = None else: returns = self._instance.returns args = self._instance.args pair_annotations = itertools.chain( zip(args.args or [], args.annotations), zip(args.kwonlyargs, args.kwonlyargs_annotations), zip(args.posonlyargs or [], args.posonlyargs_annotations), ) annotations = { arg.name: annotation for (arg, annotation) in pair_annotations if annotation } if args.varargannotation: annotations[args.vararg] = args.varargannotation if args.kwargannotation: annotations[args.kwarg] = args.kwargannotation if returns: annotations["return"] = returns items = [ (node_classes.Const(key, parent=obj), value) for (key, value) in annotations.items() ] obj.postinit(items) return obj
def __dask_distributed_annotations_pack__( self, annotations: Mapping[str, Any] | None = None ) -> Mapping[str, Any] | None: """Packs Layer annotations for transmission to scheduler Callables annotations are fully expanded over Layer keys, while other values are simply transmitted as is Parameters ---------- annotations : Mapping[str, Any], optional A top-level annotations. Returns ------- packed_annotations : dict Packed annotations. """ annotations = cast( "dict[str, Any]", toolz.merge(self.annotations or {}, annotations or {})) packed = {} for a, v in annotations.items(): if callable(v): packed[a] = {stringify(k): v(k) for k in self} packed[a]["__expanded_annotations__"] = True else: packed[a] = v return packed
def _build_json_api(apiclass: t.Type[JsonApiData], data: t.Dict[str, t.Any]) -> JsonApiData: instance = apiclass.__new__(apiclass) annotations = t.get_type_hints(apiclass) # NOTE # Ignore keys of data which is not defined in the apiclass. for key_def, type_def in annotations.items(): # Handle default values. if not (key_def in data or hasattr(apiclass, key_def)): raise ApiValidationFailedError( f"Raw data has no key named '{key_def}'.") if key_def in data: val = data.get(key_def) else: val = getattr(apiclass, key_def) # Validate types of values. if not _validate_obj(val, type_def): raise ApiValidationFailedError( "Invalid type was detected in received json data. " f"Expected: {type_def.__name__}; " f"Detected: {val.__class__.__name__}.") # Set values of attributes to an instance of the apiclass. # Handle only the case in which the origin is t.Optional. origin = get_origin(type_def) if origin == t.Union: type_def = get_args(type_def)[0] _set_non_optional_value(instance, type_def, key_def, val) return instance
def parse_annotations( annotations: Optional[Mapping[LabelName, str]]) -> api.Annotations: """Select annotations, if they are valid. Kubernetes allows the annotations to be arbitrary byte strings with a length of at most 256Kb. The python client will try to decode these with utf8, but appears to return raw data if an exception occurs. We have not tested whether this will happen. The current commit, when this information was obtained, was https://github.com/kubernetes/kubernetes/commit/a83cc51a19d1b5f2b2d3fb75574b04f587ec0054 Since not every annotation can be converted to a HostLabel, we decided to only use annotations, which are also valid Kubernetes labels. Kubernetes makes sure that the annotation has a valid name, so we only verify, that the key is also valid as a label. >>> parse_annotations(None) # no annotation specified for the object {} >>> parse_annotations({ ... '1': '', ... '2': 'a-', ... '3': 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', ... '4': 'a&a', ... '5': 'valid-key', ... }) {'1': '', '5': 'valid-key'} """ if annotations is None: return {} return { k: LabelValue(v) for k, v in annotations.items() if _is_valid_label_value(v) }
def arguments(self) -> List[StrawberryArgument]: # TODO: Move to StrawberryArgument? StrawberryResolver ClassVar? SPECIAL_ARGS = {"root", "self", "info"} annotations = self.wrapped_func.__annotations__ parameters = inspect.signature(self.wrapped_func).parameters function_arguments = set(parameters) - SPECIAL_ARGS annotations = { name: annotation for name, annotation in annotations.items() if name not in (SPECIAL_ARGS | {"return"}) } annotated_arguments = set(annotations) arguments_missing_annotations = function_arguments - annotated_arguments if any(arguments_missing_annotations): raise MissingArgumentsAnnotationsError( field_name=self.wrapped_func.__name__, arguments=arguments_missing_annotations, ) module = sys.modules[self.wrapped_func.__module__] annotation_namespace = module.__dict__ arguments = [] for arg_name, annotation in annotations.items(): parameter = parameters[arg_name] argument = StrawberryArgument( python_name=arg_name, graphql_name=None, type_annotation=StrawberryAnnotation( annotation=annotation, namespace=annotation_namespace), default=parameter.default, ) arguments.append(argument) return arguments
def __bytes__(self) -> bytes: try: annotations = self.__annotations__ except AttributeError: annotations = {} with StructIO() as io: for key, annotation in annotations.items(): if annotation == "int": io.write_u64(getattr(self, key)) elif annotation == "bool": io.write_u8(getattr(self, key)) return io.buffer
def fix_annotations( cls: typing.Type, clsdict: Vars, global_vars: Vars, local_vars: Vars, ) -> None: """Fix any forward references to variables defined in the callee scope.""" # Don't care except when enforcing types. if typing.TYPE_CHECKING: annotations = clsdict['__annotations__'] for field, type in annotations.items(): type = fix_annotation(type, global_vars, local_vars) annotations[field] = type
def set_slots( cls: typing.Type, clsdict: Vars, slots: bool, global_vars: Vars, local_vars: Vars, ) -> None: """Set default __slots__ implementation.""" if not slots or '__slots__' in clsdict: return annotations = clsdict['__annotations__'] is_cv = lambda x: is_classvar(x, global_vars, local_vars) slots = (k for k, v in annotations.items() if not is_cv(v)) clsdict['__slots__'] = tuple(slots)
def arguments(self) -> List[StrawberryArgument]: annotations = self.resolver.__annotations__ annotations = dict(islice(annotations.items(), 1, None)) annotations.pop("return", None) parameters = inspect.signature(self.resolver).parameters module = sys.modules[self.resolver.__module__] annotation_namespace = module.__dict__ arguments = [] for arg_name, annotation in annotations.items(): parameter = parameters[arg_name] argument = StrawberryArgument( python_name=arg_name, graphql_name=None, type_annotation=StrawberryAnnotation( annotation=annotation, namespace=annotation_namespace), default=parameter.default, ) arguments.append(argument) return arguments
def __new__(cls, name, bases, namespace, **kwargs): # noqa C901 annotations = resolve_annotations(namespace.get("__annotations__", {}), namespace.get("__module__", None)) for field, annotation in annotations.items(): if get_origin(annotation) is not Annotated: continue namespace[field] = FieldAnnotation.create_field_info( annotation=annotation, value=namespace.get(field, Undefined)) # Pydantic doesn't yet support Annotated annotations [1], so we'll unwrap the root type. # This prevents later inspection of the annotations with `get_type_hints`, so we'll # preferably avoid. # # 1: https://github.com/samuelcolvin/pydantic/pull/2147 if not _pydantic_is_annotated_aware: namespace["__annotations__"][field] = get_args(annotation)[0] return super().__new__(cls, name, bases, namespace, **kwargs)
def resolve_annotations( annotations: dict[str, Any], module: Optional[ModuleType], fullname: str, ) -> dict[str, Any]: """ Given an `annotations` dictionary with type annotations (for example, `cls.__annotations__`), this function tries to resolve all types using `pdoc.doc_types.safe_eval_type`. Returns: A dictionary with the evaluated types. """ ns = getattr(module, "__dict__", {}) resolved = {} for name, value in annotations.items(): resolved[name] = safe_eval_type(value, ns, fullname) return resolved
def _get_method_arguments(method: nodes.FunctionDef) -> list[str]: if method.args.args is None: return [] first_arg = 0 if method.type in {"function", "staticmethod"} else 1 arguments: list[nodes.AssignName] = method.args.args[first_arg:] annotations = dict(zip(arguments, method.args.annotations[first_arg:])) for arg in arguments: annotation_label = "" ann = annotations.get(arg) if ann: annotation_label = get_annotation_label(ann) annotations[arg] = annotation_label return [ f"{arg.name}: {ann}" if ann else f"{arg.name}" for arg, ann in annotations.items() ]
def _get_fields(cls) -> list[StructField]: fields = ListSubclass() # We need both to throw type errors in case a field is not annotated annotations = typing.get_type_hints(cls._real_cls()) # Make sure every `StructField` is annotated for name in vars(cls._real_cls()): value = getattr(cls, name) if isinstance(value, StructField) and name not in annotations: raise TypeError( f"Field {name!r}={value} must have some annotation." f" Use `None` if it is specified in the `StructField`.") # XXX: Python doesn't provide a simple way to get all defined attributes *and* # order them with respect to annotation-only fields. # Every struct field must be annotated. for name, annotation in annotations.items(): field = getattr(cls, name, StructField()) if not isinstance(field, StructField): continue field = field.replace(name=name) # An annotation of `None` means to use the field's type if annotation is not NoneType: if field.type is not None and field.type != annotation: raise TypeError( f"Field {name!r} type annotation conflicts with provided type:" f" {annotation} != {field.type}") field = field.replace(type=annotation) elif field.type is None: raise TypeError(f"Field {name!r} has no type") fields.append(field) setattr(fields, field.name, field) return fields
def invoker(): args = {} for param, notes in annotations.items(): if param == "return": continue adapt = notes.get("adapt", (lambda x: x)) color = COLORS.get(notes.get("color", "standard"), RESET) while param not in args: try: args[param] = adapt(input(f"{color}{param}{RESET}: ")) except AdaptionRetry: pass result = func(**args) if annotations["return"].get("print", False): print(result) return result
def __new__( cls, name: str, bases: typing.Tuple[type, ...], namespace: typing.Dict[str, typing.Any] ) -> type: model_fields: typing.Dict[str, ModelField] = {} slots: typing.Set[str] = set() for field in namespace['__annotations__']: if not field.startswith('__') and not field.endswith('__'): slots.add(field) if '__slots__' in namespace: slots.update(namespace['__slots__']) namespace['__slots__'] = tuple(slots) namespace['__model_fields__'] = model_fields self = type.__new__(cls, name, bases, namespace) annotations = typing.get_type_hints(self) for field, annotation in annotations.items(): if not field.startswith('__') and not field.endswith('__'): model_fields[field] = ModelField(field, annotation) return self
def get_arguments_from_annotations(annotations: Any, parameters: Mapping[str, inspect.Parameter], origin: Any) -> List[StrawberryArgument]: # Deferred to prevent import cycles from .types.type_resolver import _resolve_type arguments = [] for name, annotation in annotations.items(): default_value = parameters[name].default default_value = (undefined if default_value is inspect.Parameter.empty or is_unset(default_value) else default_value) if get_origin(annotation) is Annotated: argument = StrawberryArgument.from_annotated( python_name=name, annotation=annotation, default_value=default_value, origin=origin, ) else: argument = StrawberryArgument( type_=annotation, python_name=name, graphql_name=None, default_value=default_value, description=None, origin=origin, ) _resolve_type(argument) arguments.append(argument) return arguments
def get_flags(namespace: Dict[str, Any], globals: Dict[str, Any], locals: Dict[str, Any]) -> Dict[str, Flag]: annotations = namespace.get('__annotations__', {}) case_insensitive = namespace['__commands_flag_case_insensitive__'] flags: Dict[str, Flag] = {} cache: Dict[str, Any] = {} names: Set[str] = set() for name, annotation in annotations.items(): flag = namespace.pop(name, MISSING) if isinstance(flag, Flag): flag.annotation = annotation else: flag = Flag(name=name, annotation=annotation, default=flag) flag.attribute = name if flag.name is MISSING: flag.name = name annotation = flag.annotation = resolve_annotation(flag.annotation, globals, locals, cache) if flag.default is MISSING and hasattr(annotation, '__commands_is_flag__') and annotation._can_be_constructible(): flag.default = annotation._construct_default if flag.aliases is MISSING: flag.aliases = [] # Add sensible defaults based off of the type annotation # <type> -> (max_args=1) # List[str] -> (max_args=-1) # Tuple[int, ...] -> (max_args=1) # Dict[K, V] -> (max_args=-1, override=True) # Union[str, int] -> (max_args=1) # Optional[str] -> (default=None, max_args=1) try: origin = annotation.__origin__ except AttributeError: # A regular type hint if flag.max_args is MISSING: flag.max_args = 1 else: if origin is Union: # typing.Union if flag.max_args is MISSING: flag.max_args = 1 if annotation.__args__[-1] is type(None) and flag.default is MISSING: # typing.Optional flag.default = None elif origin is tuple: # typing.Tuple # tuple parsing is e.g. `flag: peter 20` # for Tuple[str, int] would give you flag: ('peter', 20) if flag.max_args is MISSING: flag.max_args = 1 elif origin is list: # typing.List if flag.max_args is MISSING: flag.max_args = -1 elif origin is dict: # typing.Dict[K, V] # Equivalent to: # typing.List[typing.Tuple[K, V]] flag.cast_to_dict = True if flag.max_args is MISSING: flag.max_args = -1 if flag.override is MISSING: flag.override = True elif origin is Literal: if flag.max_args is MISSING: flag.max_args = 1 else: raise TypeError(f'Unsupported typing annotation {annotation!r} for {flag.name!r} flag') if flag.override is MISSING: flag.override = False # Validate flag names are unique name = flag.name.casefold() if case_insensitive else flag.name if name in names: raise TypeError(f'{flag.name!r} flag conflicts with previous flag or alias.') else: names.add(name) for alias in flag.aliases: # Validate alias is unique alias = alias.casefold() if case_insensitive else alias if alias in names: raise TypeError(f'{flag.name!r} flag alias {alias!r} conflicts with previous flag or alias.') else: names.add(alias) flags[flag.name] = flag return flags
def annotate(**annotations): """Context Manager for setting HighLevelGraph Layer annotations. Annotations are metadata or soft constraints associated with tasks that dask schedulers may choose to respect: They signal intent without enforcing hard constraints. As such, they are primarily designed for use with the distributed scheduler. Almost any object can serve as an annotation, but small Python objects are preferred, while large objects such as NumPy arrays are discouraged. Callables supplied as an annotation should take a single *key* argument and produce the appropriate annotation. Individual task keys in the annotated collection are supplied to the callable. Parameters ---------- **annotations : key-value pairs Examples -------- All tasks within array A should have priority 100 and be retried 3 times on failure. >>> import dask >>> import dask.array as da >>> with dask.annotate(priority=100, retries=3): ... A = da.ones((10000, 10000)) Prioritise tasks within Array A on flattened block ID. >>> nblocks = (10, 10) >>> with dask.annotate(priority=lambda k: k[1]*nblocks[1] + k[2]): ... A = da.ones((1000, 1000), chunks=(100, 100)) Annotations may be nested. >>> with dask.annotate(priority=1): ... with dask.annotate(retries=3): ... A = da.ones((1000, 1000)) ... B = A + 1 """ # Sanity check annotations used in place of # legacy distributed Client.{submit, persist, compute} keywords if "workers" in annotations: if isinstance(annotations["workers"], (list, set, tuple)): annotations["workers"] = list(annotations["workers"]) elif isinstance(annotations["workers"], str): annotations["workers"] = [annotations["workers"]] elif callable(annotations["workers"]): pass else: raise TypeError( "'workers' annotation must be a sequence of str, a str or a callable, but got %s." % annotations["workers"] ) if ( "priority" in annotations and not isinstance(annotations["priority"], Number) and not callable(annotations["priority"]) ): raise TypeError( "'priority' annotation must be a Number or a callable, but got %s" % annotations["priority"] ) if ( "retries" in annotations and not isinstance(annotations["retries"], Number) and not callable(annotations["retries"]) ): raise TypeError( "'retries' annotation must be a Number or a callable, but got %s" % annotations["retries"] ) if ( "resources" in annotations and not isinstance(annotations["resources"], dict) and not callable(annotations["resources"]) ): raise TypeError( "'resources' annotation must be a dict, but got %s" % annotations["resources"] ) if ( "allow_other_workers" in annotations and not isinstance(annotations["allow_other_workers"], bool) and not callable(annotations["allow_other_workers"]) ): raise TypeError( "'allow_other_workers' annotations must be a bool or a callable, but got %s" % annotations["allow_other_workers"] ) prev_annotations = config.get("annotations", {}) new_annotations = { **prev_annotations, **{f"annotations.{k}": v for k, v in annotations.items()}, } with config.set(new_annotations): yield
mro = obj.mro() except TypeError: return True # We have to traverse the class's mro to find annotations since __annotations__ # doesn't include inherited attributes in-order to make resolving said annotations # possible (as you need to know the scope they were defined in). for mro_cls in mro: # obj.mro() includes the class itself at the start. try: # Some classes like object just don't have annotations cause thx python. annotations = mro_cls.__annotations__ except AttributeError: continue for name, annotation in filter(_is_public_key, annotations.items()): if name not in found_attributes: self._handle_annotation(mro_cls.__module__, f"{path}.{name}", annotation) found_attributes.add(name) return True return False def index_module(self: _ReferenceIndexT, module: types.ModuleType, /, *, recursive: bool = False) -> _ReferenceIndexT: """Add a module to the internal index of in-scope modules.
def add_module(self, module: types.ModuleType, cython: bool = False) -> None: """Add the given module, its members, and their submembers. The first examples are based on the site-package |numpy|: which is passed to method |Substituter.add_module|: >>> from hydpy.core.autodoctools import Substituter >>> substituter = Substituter() >>> import numpy >>> substituter.add_module(numpy) First, the module itself is added: >>> substituter.find("|numpy|") |numpy| :mod:`~numpy` Second, constants like |numpy.nan| are added: >>> substituter.find("|numpy.nan|") |numpy.nan| :const:`~numpy.nan` Third, functions like |numpy.clip| are added: >>> substituter.find("|numpy.clip|") |numpy.clip| :func:`~numpy.clip` Fourth, clases line |numpy.ndarray| are added: >>> substituter.find("|numpy.ndarray|") |numpy.ndarray| :class:`~numpy.ndarray` Method |Substituter.add_module| also searches for available annotations: >>> from hydpy.core import timetools >>> substituter.add_module(timetools) >>> substituter.find("Timegrids.init") |Timegrids.initindices| :const:`~hydpy.core.timetools.Timegrids.initindices` |Timegrids.init| :attr:`~hydpy.core.timetools.Timegrids.init` |timetools.Timegrids.initindices| \ :const:`~hydpy.core.timetools.Timegrids.initindices` |timetools.Timegrids.init| :attr:`~hydpy.core.timetools.Timegrids.init` >>> from hydpy.auxs import calibtools >>> substituter.add_module(calibtools) >>> substituter.find("RuleIUH.update_parameters") |RuleIUH.update_parameters| \ :attr:`~hydpy.auxs.calibtools.RuleIUH.update_parameters` |calibtools.RuleIUH.update_parameters| \ :attr:`~hydpy.auxs.calibtools.RuleIUH.update_parameters` Module |typingtools| is unique, as it is the only one for which |Substituter.add_module| considers all explicitly exported type aliases: >>> from hydpy.core import typingtools >>> substituter.add_module(typingtools) >>> substituter.find("|NDArrayFloat|") |NDArrayFloat| :class:`~hydpy.core.typingtools.NDArrayFloat` When adding Cython modules, the `cython` flag should be set |True|: >>> from hydpy.cythons import pointerutils >>> substituter.add_module(pointerutils, cython=True) >>> substituter.find("set_pointer") |PPDouble.set_pointer| \ :func:`~hydpy.cythons.autogen.pointerutils.PPDouble.set_pointer` |pointerutils.PPDouble.set_pointer| \ :func:`~hydpy.cythons.autogen.pointerutils.PPDouble.set_pointer` """ name_module = module.__name__.split(".")[-1] short = f"|{name_module}|" long = f":mod:`~{module.__name__}`" self.short2long[short] = long for (name_member, member) in vars(module).items(): if self.consider_member(name_member, member, module): role = self.get_role(member, cython) short = f"|{name_member}|" medium = f"|{name_module}.{name_member}|" long = f":{role}:`~{module.__name__}.{name_member}`" self.add_substitution(short, medium, long, module) if inspect.isclass(member): annotations = getattr(member, "__annotations__", {}) for name_submember, submember in vars(member).items(): if self.consider_member( name_member=name_submember, member=submember, module=module, class_=member, ignore=annotations, ): role = self.get_role(submember, cython) short = f"|{name_member}.{name_submember}|" medium = (f"|{name_module}.{name_member}." f"{name_submember}|") long = (f":{role}:`~{module.__name__}." f"{name_member}.{name_submember}`") self.add_substitution(short, medium, long, module) for name_submember, submember in annotations.items(): short = f"|{name_member}.{name_submember}|" medium = f"|{name_module}.{name_member}." f"{name_submember}|" long = (f":attr:`~{module.__name__}." f"{name_member}.{name_submember}`") self.add_substitution(short, medium, long, module)
def match(self, pattern): class _Temporary: p: pattern parsed_pattern = get_type_hints(_Temporary, localns={'pattern': pattern}, include_extras=True)['p'] if get_origin(parsed_pattern) is Annotated: parsed_pattern, recursive = get_args(parsed_pattern) else: recursive = False annotations = get_type_hints(parsed_pattern, include_extras=True) for name, expected in annotations.items(): #print(f'{expected=} {self[name]=}') expected_any = expected is Any got_something = self[name] is not None if expected_any and not got_something: break expected_tuple = get_origin(expected) is tuple got_something = self[name] is not None if expected_tuple and not got_something: break elif expected_tuple and got_something: exp_timestamp, exp_value = get_args(expected) got_timestamp, got_value = self[name] #print(f'{exp_timestamp=} {exp_value=}') #print(f'{got_timestamp=} {got_value=}') expected_any = exp_timestamp is Any got_something = got_timestamp is not None if expected_any and not got_something: break expected_any = exp_value is Any got_something = got_value is not None if expected_any and not got_something: break if get_origin(exp_value) is Literal: exp_value = get_args(exp_value)[0] if exp_value != got_value: break expected_list = get_origin(expected) is list got_something = self[name] is not None if expected_list and not got_something: break elif expected_list and got_something: exp_class = get_args(expected)[0] for tree in self.children: if next(tree.match(exp_class), None) is not None: break else: yield self return if recursive: for tree in self.children: yield from tree.match(pattern)
def get_flags(namespace: Dict[str, Any], globals: Dict[str, Any], locals: Dict[str, Any]) -> Dict[str, Flag]: annotations = namespace.get('__annotations__', {}) flags: Dict[str, Flag] = {} cache: Dict[str, Any] = {} for name, annotation in annotations.items(): flag = namespace.pop(name, MISSING) if isinstance(flag, Flag): flag.annotation = annotation else: flag = Flag(name=name, annotation=annotation, default=flag) flag.attribute = name if flag.name is MISSING: flag.name = name annotation = flag.annotation = resolve_annotation( flag.annotation, globals, locals, cache) # Add sensible defaults based off of the type annotation # <type> -> (max_args=1) # List[str] -> (max_args=-1) # Tuple[int, ...] -> (max_args=1) # Dict[K, V] -> (max_args=-1, override=True) # Optional[str] -> (default=None, max_args=1) try: origin = annotation.__origin__ except AttributeError: # A regular type hint if flag.max_args is MISSING: flag.max_args = 1 else: if origin is Union and annotation.__args__[-1] is type(None): # typing.Optional if flag.max_args is MISSING: flag.max_args = 1 if flag.default is MISSING: flag.default = None elif origin is tuple: # typing.Tuple # tuple parsing is e.g. `flag: peter 20` # for Tuple[str, int] would give you flag: ('peter', 20) if flag.max_args is MISSING: flag.max_args = 1 elif origin is list: # typing.List if flag.max_args is MISSING: flag.max_args = -1 elif origin is dict: # typing.Dict[K, V] # Equivalent to: # typing.List[typing.Tuple[K, V]] flag.cast_to_dict = True if flag.max_args is MISSING: flag.max_args = -1 if flag.override is MISSING: flag.override = True else: raise TypeError( f'Unsupported typing annotation {annotation!r} for {flag.name!r} flag' ) if flag.override is MISSING: flag.override = False flags[flag.name] = flag return flags