This is meant to allow simple type conversions to happen before the
interpreter function is called. This should simplify some cases like the
"native" keyword arugment that are booleans in the Meson DSL, but an
Enum in the implementation
This attribute is a callable that returns a string if the value is
invalid, otherwise None. This intended for cases like the `install_*`
function's `install_mode` paramater, which is either an int or the
string "preserve", which allows us to do nice things like:
```python
class Kwargs(TypedDict):
install_mode: T.Union[int, T.Literal['preserve']]
@typed_kwargs(
'foo', KwargInfo('install_mode', ...,
validator=lambda x: None if isinstance(x, int) or x == 'preserve' else 'must be the literal "preserve"),
)
def install_data(self, node, args, kwargs: 'Kwargs'):
...
```
In this case mypy *knows* that the string is preserve, as do we, and we
can simply do tests like:
```python
if kwargs['install_mode'] == 'preserve':
...
else:
# this is an int
```
Add a method to downgrade an option to disabled if it is not used.
This is useful to avoid unnecessary search for dependencies;
for example
dep = dependency('dep', required: get_option('feature').disable_auto_if(not foo))
can be used instead of the more verbose and complex
if get_option('feature').auto() and not foo then
dep = dependency('', required: false)
else
dep = dependency('dep', required: get_option('feature'))
endif
or to avoid unnecessary dependency searches:
dep1 = dependency('dep1', required: get_option('foo'))
# dep2 is only used together with dep1
dep2 = dependency('dep2', required: get_option('foo').disable_auto_if(not dep1.found()))
```
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Add a method to perform a logical AND on a feature object. The method
also takes care of raising an error if 'enabled' is ANDed with false.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
It's really inconvenient to want a thing that is always a list, but not
be able to provide a default value of a list because of mutation. To
that end the typed_kwargs method now makes a shallow copy of the default
when using a `ContainerTypeInfo` as the type. This mean that using a
default of `[]` is perfectly safe.
When mutable items are stored in an lru cache, changing the returned
items changes the cached items as well. Therefore we want to ensure that
we're not mutating them. Using the ImmutableListProtocol allows mypy to
find mutations and reject them. This doesn't solve the problem of
mutable values inside the values, so you could have to do things like:
```python
ImmutableListProtocol[ImmutableListProtocol[str]]
```
or equally hacky. It can also be used for input types and acts a bit
like C's const:
```python
def foo(arg: ImmutableListProtocol[str]) -> T.List[str]:
arg[1] = 'foo' # works while running, but mypy errors
```
this is a place that *must* only be imported inside a if
typing.TYPE_CHECKING block. It is a mixture of smoothing over thinigs
that moved from typing_extensions to typing in later python versions and
useful but typing only code.
This makes typing_extensions required for python versions older than
3.8 *when running mypy*. typing_extensions should *only* be imported
inside an `if typing.TYPE_CHECKING` block (include the new _typing.py
module) to ensure that it doesn't become a runtime dependency
This method simplifies the conversion of Feature objects to booleans.
Often, one has to use the "not" operator in order to treat "auto"
and "enabled" the same way.
"allowed()" also works well in conjunction with the require method that
is introduced in the next patch. For example,
if get_option('foo').require(host_machine.system() == 'windows').allowed() then
src += ['foo.c']
config.set10('HAVE_FOO', 1)
endif
can be used instead of
if host_machine.system() != 'windows'
if get_option('foo').enabled()
error('...')
endif
endif
if not get_option('foo').disabled() then
src += ['foo.c']
config.set10('HAVE_FOO', 1)
endif
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>