mxutils¶
Contains helper functions and types that are written in Python and exclusive to the Python API.
Overview¶
Classes¶
|
Generates
int or maxon.Id identifiers when defining them manually is not desirable. |
|
Provides a context manger to import from packages relative to a file which do not lie in a module search path.
|
Functions¶
|
Checks
item for being an iterable of a specific type, being composed of specific elements, or being of specific length. |
|
Checks
item for being of type t . |
|
Parses elements of all resource files contained in the given |
Function Listing¶
-
mxutils.
CheckIterable
(item: Any, tElement: Optional[Union[Type, tuple]] = None, tIterable: Optional[Union[Type, tuple]] = None, label: str | None = None, minCount: int | None = None, maxCount: int | None = None) → Any - Checks
item
for being an iterable of a specific type, being composed of specific elements, or being of specific length.When any of the checks fail, an error is being raised. If not,item
is being passed through. The function can automatically discover the symbol ofitem
when it is defined in the local or global scope of the function call. While all types of iterables are supported, it is onlydict
andc4d.BaseContainer
which are supported in their specific item, i.e., pairs, decomposition. All other iterables are treated as iterables of singular elements as for example lists or tuples.When possible, it is advantageous to replace iterable type checks with type conversions due to the computationally expensive nature of checking every item in an iterable. The expensive part of this call is passing notNone
fortElement
, i.e., checking the type of every element initem
(whenitem
is very large), all other checks are negligible in cost.- Parameters
item (typing.Any) – The item to be type checked.
tElement (typing.Type | tuple[typing.Type] | None (, optional)) – The type or types of elements the iterable
item
is allowed to have. PassingNone
will will accept any kind of element type. Defaults toNone
.tIterable (typing.Type | tuple[typing.Type] | None (, optional)) – The type or types the iterable
item
is allowed to be. PassingNone
will accept any kind of iterable. Defaults toNone
.label (str | None (, optional)) – The label with which to refer to
item
in exceptions. PassingNone
will result in an attempt to infer the symbol. Symbol discovery only works for values in the local or global scope. Defaults toNone
.minCount (int | None (, optional)) – The minimum length for the iterable
item
. PassingNone
will accept any iterable that is smaller than or equal tomaxCount
. Value must be smaller than or equal tomaxCount
Defaults toNone
.maxCount (int | None (, optional)) – The maximum length for the iterable
item
. PassingNone
will accept any iterable that is greater than or equal tominCount
. Value must be larger or equal tominCount
Defaults toNone
.
- Raises
TypeError – When
item
is failing the type tests.ValueError – When
minCount
is larger thanmaxCount
.RuntimeError – When any of the length checks fail.
RuntimeError – When accessing a stack trace or reading an executed file failed on a symbol discovery attempt.
- Returns
The value of
item
when the checks succeeded.- Return type
typing.Any
- Example
import c4d from mxutils import CheckIterable # Checks if `data` is composed of strings only; this will fail as there is an `int` in it. data: list[str|int] = ["1", "2", "3", 4, "5"] data = CheckIterable(data, str) # But the prior case is also an example for where element type assertions are unnecessary. # As we can enforce the type of items in `data` with `str()`. item: str = str(data[3]) # The common use case is checking type composition assumptions of function arguments passed # by unsafe sources, in order to avoid carrying out expensive computations which fail in a # very late stage due to encountering a malformed item in the input data. class Foo: def __init__(self, nodes: list[c4d.BaseObject | c4d.BaseTag]) -> None: # Assure that _nodes will be a list of tags and objects. self._nodes = CheckIterable(nodes, (c4d.BaseObject, c4d.BaseTag), list) # Tested can also be the length of the iterable. # Assures that `data` has at least the length of one. No specific type checks are performed # in this case, but `data` is still being tested for being an iterable. This is a very low # cost call, no matter how large data is, as the first argument `tElement` has is `None` and # `data` is therefore never traversed as elements of any type are accepted. data = CheckIterable(data, minCount=1) # Assures that `data` is not longer than five elements. data = CheckIterable(data, maxCount=5) # Assures that the length of `data` lies in the interval [1, 5]. data = CheckIterable(data, minCount=1, maxCount=5) # The function will always test if ``item`` is an iterable, even when both type tests are # set to None. So, this will raise an error as `int` does not implement `__iter__` CheckIterable(1) # but this will not, as `c4d.BaseContainer` does implement `__iter__`: data: c4d.BaseContainer = c4d.BaseContainer() CheckIterable(data) # All forms of iterable are supported, but only `c4d.BaseContainer` and `dict` are handled # manually to type test values in key, value pairs instead of testing the type of the pair. data[0] = "Hello world" data[1] = True # Will test data for being of type BaseContainer, holding only values of type str or bool. CheckIterable(data, (str, bool), c4d.BaseContainer) # The same thing for dict, key type testing is not supported. data = {1: "Hello World", "my_key": True} CheckIterable(data, (str, bool), dict) # Just as for CheckType(), automatic symbol discovery is only possible for values in the # local or global scope. So, when testing `sys.path`, one should pass a label, as errors # will otherwise refer to an 'unknown symbol'. import sys # Assures that sys.path is a list of strings with at least one element. paths = CheckIterable(sys.path, str, list, "sys.path", 1)
-
mxutils.
CheckType
(item: Any, t: Optional[Union[Type, tuple]] = None, label: str | None = None) → Any - Checks
item
for being of typet
.When the check fails, an error is being raised. If not,item
is being passed through. The function can automatically discover the symbol ofitem
when it is defined in the local or global scope of the function call.- Parameters
item (typing.Any) – The item to be type checked.
t (typing.Type | tuple[typing.Type] | None (, optional)) – The type or types
item
is allowed to be. PassingNone
will only assert thatitem
is notNone
. Defaults toNone
.label (str | None (, optional)) – The label with which to refer to
item
in exceptions. PassingNone
will result in an attempt to infer the symbol. Symbol discovery only works for values in the local or global scope. Defaults toNone
.
- Raises
TypeError – When
item
is failing the type test.RuntimeError – When accessing a stack trace or reading an executed file failed on a symbol discovery attempt.
- Returns
The value of
item
when the check succeeded.- Return type
typing.Any
- Example
import c4d import math from mxutils import CheckType MY_INT: int = 42 class Foo: SOME_INT: int = 42 def __init__(self, x: int) -> None: # Asserts that `x` is not `None`. CheckType(x) # Asserts that `x` is not `None` and assigns its values to `self._x`. self._x: object = CheckType(x) # Asserts that `MY_INT` is of type `int` or `float` and assigns its int value to `self._y`. self._y: int = int(CheckType(MY_INT, (int, float))) # Symbols which are neither in the global nor local scope are not automatically # discoverable and error messages for such values will refer to the value with # 'unknown symbol'. # `Foo.SOME_INT` and `math.pi` are not part of the local or global scope. When error # messages should not refer to a generic 'Unknown Symbol', one must pass in a label. # CheckType(Foo.SOME_INT, bool) # TypeError: Expected value of type <class 'bool'> for 'Unknown Symbol'. Received: <class 'int'> CheckType(math.pi, int, 'math.pi') # TypeError: Expected value of type <class 'int'> for 'math.pi'. Received: <class 'float'> # `x`, `y`, and `MY_INT` are in the global/local scope and automatically discovered. y: float = 1.0 CheckType(x, float) # TypeError: Expected value of type <class 'float'> for 'x'. Received: <class 'int'> CheckType(y, int) # TypeError: Expected value of type <class 'int'> for 'y'. Received: <class 'float'> CheckType(MY_INT, bool) # TypeError: Expected value of type <class 'bool'> for 'MY_INT'. Received: <class 'int'>
-
mxutils.
ImportSymbols
(path: str, output: Type = None) → dict[str, float | int | str] | None Parses elements of all resource files contained in the given
path
into the global scope of the caller or into a dictionary.See also
- Parameters
path (str) – The path within which header files should be discovered and parsed.
output (typing.Type) – If the parsed symbols should be placed in the global scope or be returned as a dictionary. Pass
None
to let them be placed in the global scope anddict
to have the function return them as a dictionary. Defaults toNone
.
- Returns
The parsed symbol value pairs as or nothing when the
output
wasNone
- Return type
dict[str, float | int | str] | None
- Example
The following header file
c:\data\c4d_symbols.h
,enum { ID_FOO = 1000, ID_BAR = 1001, _DUMMY_ELEMENT_ };
can be imported as follows:
import os import mxutils # Recursively parse header files in "c:\data" into this scope. mxutils.ImportSymbols("c:\data") # This would also work when only a singular file should be parsed. mxutils.ImportSymbols("c:\data\c4d_symbols.h") # The parsed symbols are now exposed in the global scope. print(ID_FOO) # Will print 1000 print(ID_BAR) # Will print 1001 # Alternatively, symbols can also be parsed into a dictionary. data: dict[str, int] = mxutils.ImportSymbols("c:\data\c4d_symbols.h", output=dict) print(data["ID_FOO"]) # Will print 1000 print(data["ID_BAR"]) # Will print 1001