Custom Types
Implement Your Own Type¶
By implementing a simple protocol, your custom classes can be easily used as the type of an arc parameter.
Example¶
When implementing your own types, you can make them compatible with arc by implementing the __convert__()
class method. arc will call this with the input from the command line (or some other source), and you are expected to parse the input and return an instance of the type. For example,
import arc
class CustomType:
def __init__(self, val: int):
self.val = val
def __str__(self):
return f"CustomType(val={self.val})"
@classmethod
def __convert__(cls, value: str):
if value.isnumeric():
return cls(int(value))
else:
raise arc.ConversionError(value, "must be an integer")
@arc.command
def main(foo: CustomType):
arc.print(foo)
main()
$ python custom_type.py 2
CustomType(val=2)
$ python custom_type.py string
USAGE
custom_type.py [-h] foo
invalid value for foo: must be an integer
Some notes about custom types:
In additon to value
, you can also add the following arguments to the signature (in the given order, but the names don't need to match):
info
: Description of the provided type. Instance ofarc.types.TypeInfo
Context Managers¶
Any type that is considered a context manager will be opened before the command callback executes, and then closed after the command executes
import arc
class ContextManager:
def __init__(self, value) -> None:
self.value = value
def __enter__(self):
arc.print("Entering the Context")
return self
def __exit__(self, *args):
arc.print("Exiting the Context")
@classmethod
def __convert__(cls, value):
return cls(value)
@arc.command
def command(val: ContextManager):
arc.print(val)
command()
$ python context_manager.py 1
Entering the Context
<ContextManager object at 0x73c8b438f450>
Exiting the Context
Note
Note that the return value of __enter__()
is important here, because it is the value that is passed to the command.
Type Aliases¶
Type aliases are the way in which arc implements support for builtin and standard library Python types, but can also be used for any type. You can use type aliases to provide support fo any third party library types. For example, supporting numpy arrays
import arc
from arc.types import Alias
import numpy as np
# Inherits from Alias. The 'of' parameter declares what types(s) this
# alias handles (can be a single type or tuple of types).
# Reads like a sentence: "NDArrayAlias is the Alias of np.ndarray"
class NDArrayAlias(Alias, of=np.ndarry):
@classmethod
def __convert__(cls, value: str):
return np.ndarray(value.split(","))
@arc.command
def main(array: np.ndarray):
arc.print(repr(array))
main()
Note that this is a simplified example, a more complete implementation would support the use of generics using numpy.typing