Skip to content

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,

custom_type.py
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 of arc.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

examples/context_manager.py
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 0x7ff8c5aa4fa0>
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()
$ python example.py x,y,z
array(['x', 'y', 'z'], dtype='<U1')
All other principles about custom types hold for alias types.

Note that this is a simplified example, a more complete implementation would support the use of generics using numpy.typing