Skip to content

Supported Types

This document outlines all of the types that arc supports for parameters.

When possible, arc uses builtin and standard library data types. But if no type is available, or the builtin types don't provide the neccessary functionality, arc may implement a custom type.

Builtin Types

str

str(v) is used which, in most cases, will be comparable to no change.

This is considered the default type is no type is specified.

int

arc uses int(v) to convert the value. Note that decimal input (1.4) will result in an error, not a narrowing operation.

float

Likewise, arc uses float(v). Ingeter values will be converted to a float (2 -> 2.0)

bool

Used to denote a Flag

examples/parameter_flag.py
import arc


@arc.command
def hello(firstname: str, reverse: bool):
    if reverse:
        firstname = firstname[::-1]

    arc.print(f"Hello, {firstname}! Hope you have a wonderful day!")


hello()
$ python parameter_flag.py Joseph
Hello, Joseph! Hope you have a wonderful day!
$ python parameter_flag.py Joseph --reverse
Hello, hpesoJ! Hope you have a wonderful day!

bytes

Converted using v.encode()

dict

Allows a list of comma-seperated key-value pairs. Can be typed generically on both keys and values.

dict_argument.py
import arc


@arc.command
def command(numbers: dict[str, int]):
    arc.print(numbers)


command()
$ python dict_argument.py one=1,two=2,three=3
{'one': 1, 'two': 2, 'three': 3}

Collection Types

arc allows you to collect multiple values from the command line into a single argument for your comamnd. To do this, you use the collection types: list, set and tuple

list

list_argument.py
import arc


@arc.command
def main(names: list):
    for name in names:
        arc.print(name)


main()
$ python list_argument.py Jonathen Joseph Jotaro
Jonathen
Joseph
Jotaro
Because list can accept any number of values, you won't be able to add additional arguments after names. Any other positional arguments would have to come before names.

set

Similar to list, but will filter out any non-unique elements.

set_argument.py
import arc


@arc.command
def main(vals: set):
    arc.print("Unique values:")
    arc.print("\n".join(vals))


main()
$ python set_argument.py 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4
Unique values:
3
1
2
4

tuple

Similar to list, but with some additional functionality.

According to PEP 484:

  • tuple represents an arbitrarily sized tuple of any type. In arc, this will behave the same as list
  • tuple[int, ...] represents an arbitrarily sized tuple of integers. In arc, this will behave the same as list[int]
  • tuple[int, int] represents a size-two tuple of integers. In arc, this behavior is unique to tuple as the parameter will only select 2 values from input.

Sub Typing

Collections can be sub-typed so that each item will be converted to the proper type:

sum.py
import arc


@arc.command
def main(nums: list[int]):
    arc.print("The total is: ", sum(nums))


main()
$ python sum.py 1 2 3 4 5 6 7 8 9
The total is:  45

Collections as Options

When used as an option, it allows the option to be used multiple times:

list_option.py
import arc


@arc.command
def main(*, names: list):
    for name in names:
        arc.print(name)


main()
$ python list_option.py --names Josuke --names Giorno --names Joylene
Josuke
Giorno
Joylene

Collection Lengths

You can specify how many items should be provided to a collection type with a type validator, specifically Len()

examples/length.py
from typing import Annotated
import arc
from arc.types.middleware import Len


@arc.command()
def command(vals: Annotated[list[int], Len(2, 10)]):
    arc.print(vals)


command()
$ python length.py 1 2 3 4 5 6
[1, 2, 3, 4, 5, 6]
$ python length.py 1
USAGE
    length.py [-h] vals [vals...]

invalid value for vals: expects between 2 and 10 arguments

Standard Library Types

typing.Any

Equivelant to str

typing.TypedDict

Constrains a dictionary input to a specific subset of keys and specific value types.

typing.Union

Allows the input to be multiple different types.

examples/union_argument.py
from typing import Union
import arc


@arc.command
def main(number: Union[int, str]):
    arc.print(type(number))


main()
$ python union_argument.py 5
<class 'int'>
$ python union_argument.py hello
<class 'str'>

arc will attempt to coerce the input into each type, from left to right. The first to succeed will be passed along to the command.

Warning

You cannot have a type like typing.Union[list, int] as collection types need to be known at definition of a command rather than during data validation.

Python 3.10's union syntax is also valid: int | str

pathlib.Path

Path won't perform any validation checks to assert that the input is a valid path, but it just offers the convenience of working with path objects rather than strings. Check the ValidPath custom type for additional validations

ipaddress.IPv4Address

Uses ipaddress.IPv4Address(v) for conversion, so anything valid there is valid here.

ipaddress.IPv6Address

Same as above

re.Pattern

Compile a regular expression using re.compile()

datetime.datetime

Convert string input to a datetime object

Type Arguments

You can provide the expected format of the datetime string via a type argument:

examples/dates.py
from typing import Annotated
import arc
from arc import types
import datetime


@arc.command
def command(date: Annotated[datetime.datetime, types.DateTimeArgs("%Y-%m-%d")]):
    arc.print(date)


command()

$ python dates.py 2022-01-01
2022-01-01 00:00:00

datetime.date

Convert string input to a date object.

types.DateArgs is equivalent to the above example.

datetime.time

Convert string input to a time object

types.TimeArgs is equivalent to the above example.

Constrained Input

typing.Literal

Enforces that the input must be a specific sub-set of values

examples/literal_argument.py
from typing import Literal
import arc


@arc.command
def main(word: Literal["foo", "bar", 1]):
    arc.print(word, type(word))


main()
$ python literal_argument.py foo
foo <class 'str'>
$ python literal_argument.py 1
1 <class 'int'>
$ python literal_argument.py other
USAGE
    literal_argument.py [-h] word

invalid value for word: must be foo, bar or 1

Note

arc compares the input to the string-ified version of each value in the Literal. So for the second example above, the comparison that succedded was "1" == "1" not 1 == 1.

enum.Enum

Similar to typing.Literal, restricts the input to a specific sub-set of values

examples/paint.py
from enum import Enum
import arc

arc.configure(autocomplete=True)


class Color(Enum):
    RED = "red"
    YELLOW = "yellow"
    GREEN = "green"


# Could also use:
# Color = Literal["red", "yellow", "green"]


@arc.command
def paint(color: Color):
    if color is Color.RED:
        arc.print("You painted the walls the bloodiest of reds")
    elif color is Color.YELLOW:
        arc.print("You painted the walls the most fabulous yellow")
    else:
        arc.print("You painted the walls the deepest of greens")


paint()
$ python paint.py red
You painted the walls the bloodiest of reds
$ python paint.py blue
USAGE
    paint.py [-h] [--autocomplete AUTOCOMPLETE] color

invalid value for color: must be red, yellow or green

arc Types

arc provides a variety of additional types exported from the arc.types module:

Warning

arc types are sort of weird in the general Python sense. While it will become more aparent later as to why this is the case, know that you cannot usually create the types on your own and have the expected behavior. If you do need / want to do this, you can use: arc.convert(<value>, <type>)

Context

Annotating an argument with this gives you access to the current execution context.

State

Reference State for details

Prompt

Gives you access to a Prompt instance

SemVer

A type to support semantically-versioned strings based on the spec found here

User (*NIX ONLY)

A representation of a *nix user. The input should be the name of the *nix user.

Group (*NIX ONLY)

A representation of a *nix group. The input should be the name of the *nix group.

File System Types

File

One of the most common things that a CLI tool is likely to do, is take in a file name as input, and interact with that file in some way. arc's advanced typing system makes this trivial, with the details around ensuring the file exists, opening it, and closing it handled by arc for you.

arc provides this functionality through its arc.types.File type. Let's use it to read out the first line of the source code's README.

examples/file.py
import arc
from arc.types import File


@arc.command
def command(file: File.Read):
    arc.print(file.readline())


command()
$ python file.py README.md
# ARC

There are constants defined on File (like File.Read above) for all common actions (Read, Write, Append, ReadWrite, etc...). You can view them all in the reference

ValidPath

pathlib.Path but asserts that the provided path actually exists

FilePath

pathlib.Path but asserts that the path both exists and is a file

DirectoryPath

pathlib.Path but asserts that the path both exists and is a directory

Networking Types

IpAddress

Union type for IPv4Address and IPv6Address

Url

Parses the strings input using urllib.parse.urlparse

HttpUrl

Url that asserts the scheme to be http or https

WebSocketUrl

Url that asserts the scheme to be wss

FtpUrl

Url that asserts the scheme to be ftp

MysqlUrl

Url that asserts the scheme to be `mysql

PostgresUrl

Url that checks that it is a valid PostgreSQL URL

Number Types

Note

For any types that simply change the base of the input (like Binary or Hex), it is essentially equivelant to int(v, base=<base>).

Binary

Accepts integers as binary stings (0101010110).

Oct

Accepts integers in base 8

Hex

Accepts integers in base 16

PositveInt

Enforces that the integer must be greater than 0

NegativeInt

Enforces that the integer must be less than 0

PositveFloat

Enforces that the float must be greater than 0

NegativeFloat

Enforces that the float must be less than 0

AnyNumber

Accepts floats, and integers in any base.

String Types

Char

Enforces that the string can only be a single character long

Password

When prompted for input, the user's input will not be echoed to the screen.

Email

Enforces that the string is a valid email address