Standard library types#
The following Python standard library types can be used as type hints for Feud commands.
Tip
Types listed on this page from the collections, datetime decimal,
enum, fractions, pathlib, uuid and typing
standard library modules are easily accessible from the feud.typing module.
It is recommended to import the feud.typing module with an alias such as t for convenient short-hand use, e.g.
from feud import typing as t
t.Path # pathlib.Path
t.datetime # datetime.datetime
t.IntEnum # enum.IntEnum
t.NamedTuple # typing.NamedTuple
t.Union # typing.Union
String type#
The string type permits the user to enter free text as an input value.
str should be used to specify free text,
but it is also the default when no type hint is provided.
See also
pydantic.types.constr can be used to impose restrictions such as minimum/maximum string length.
Example
- Arguments:
ARG1: Any text (no type hint).ARG2: Any text.
- Options:
--opt: Any text.
# str.py
import feud
def command(arg1, arg2: str, *, opt: str = "value"):
print(f"{arg1=!r} ({type(arg1)})")
print(f"{arg2=!r} ({type(arg2)})")
print(f"{opt=!r} ({type(opt)})")
if __name__ == "__main__":
feud.run(command)
$ python str.py --help
$ python str.py "Hello World!" abc --opt test
arg1='Hello World' (<class 'str'>)
arg2='abc' (<class 'str'>)
opt='test' (<class 'str'>)
As free text is not validated, any input is accepted.
Literal string type (choices)#
Literal strings can be used to limit the user to a number of string choices.
typing.Literal should be used to specify literal string inputs.
See also
Enumeration types can also be used to represent choices.
Example
- Arguments:
ARG: Either the stringaorb.
- Options:
--opt: Either the stringc,dore. Defaults toe.
# literal.py
import feud
from feud import typing as t
def command(arg: t.Literal["a", "b"], *, opt: t.Literal["c", "d", "e"] = "e"):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt=!r} ({type(opt)})")
if __name__ == "__main__":
feud.run(command)
$ python literal.py --help
$ python literal.py b --opt d
arg='b' (<class 'str'>)
opt='d' (<class 'str'>)
$ python literal.py c
Boolean type#
The boolean type can be used to indicate a true/false input.
bool should be used to specify boolean inputs.
Common truth values that are accepted include any of the following (case insensitive):
True:
true,t,yes,y,1False:
false,f,no,n,0
Tip
When used as an option, the presence of a boolean flag is enough to set
the value to True — that is, to enable the flag the user should simply
specify --opt instead of --opt true (which will not work), for
example.
By default, a negated version of the flag (e.g. --no-opt) is also generated
to set the value to False. The generation of this negated flag can be
disabled by changing the Feud configuration parameters.
Example
- Arguments:
ARG: Boolean value.
- Options:
--opt: Boolean value.
# bool.py
import feud
def command(arg: bool, *, opt: bool = True):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt=!r} ({type(opt)})")
if __name__ == "__main__":
feud.run(command)
$ python bool.py --help
$ python bool.py false --opt
arg=False (<class 'bool'>)
opt=True (<class 'bool'>)
$ python bool.py true --no-opt
arg=True (<class 'bool'>)
opt=False (<class 'bool'>)
$ python bool.py maybe
Number types#
Number types can be used to indicate integers, floats or decimal numbers.
intshould be used to specify integer inputs.floatshould be used to specify fixed precision-floating point inputs.decimal.Decimalshould be used to specify arbitrary-precision floating point inputs.fractions.Fractionshould be used to specify fractions.
See also
pydantic.types.conintcan be used to restrict integers.pydantic.types.confloatcan be used to restrict floats.pydantic.types.condecimalcan be used to restrict decimals.
Example
- Arguments:
ARG: An integer value.
- Options:
--opt1: An integer value.--opt2: A fixed-precision floating point number.--opt3: An arbirary precision floating point number.
# number.py
import feud
from feud import typing as t
def command(arg: int, *, opt1: int, opt2: float, opt3: t.Decimal):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt1=!r} ({type(opt1)})")
print(f"{opt2=!r} ({type(opt2)})")
print(f"{opt3=!r} ({type(opt3)})")
if __name__ == "__main__":
feud.run(command)
$ python number.py --help
$ python number.py 0 --opt1 1 --opt2 -2.2 --opt3 3.33
arg=0 (<class 'int'>)
opt1=1 (<class 'int'>)
opt2=-2.2 (<class 'float'>)
opt3=Decimal('3.33') (<class 'decimal.Decimal'>)
$ python number.py abc --opt1 1.1 --opt2 true --opt3 invalid
Datetime types#
Datetime types can be used to indicate date or time related inputs.
datetime.datetimecan be used to indicate inputs with a date and time component.datetime.datecan be used to indicate date inputs.datetime.timecan be used to indicate time inputs.datetime.timedeltacan be used to indicate time delta inputs.
See also
pydantic.types.condatecan be used to impose restrictions such as minimum/maximum dates.pydantic.types.PastDate/pydantic.types.PastDatetimecan be used to restrict date/datetime inputs to the past.pydantic.types.FutureDate/pydantic.types.FutureDatetimecan be used to restrict date/datetime inputs to the future.
Example
- Arguments:
ARG: A datetime value.
- Options:
--opt1: A date value.--opt2: A time value.--opt3: A time delta value.
# date_time.py
import feud
from feud import typing as t
def command(arg: t.datetime, *, opt1: t.date, opt2: t.time, opt3: t.timedelta):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt1=!r} ({type(opt1)})")
print(f"{opt2=!r} ({type(opt2)})")
print(f"{opt3=!r} ({type(opt3)})")
if __name__ == "__main__":
feud.run(command)
$ python date_time.py --help
$ python date_time.py "2012-12-21 00:01:00" \
--opt1 2012-12-21 \
--opt2 00:01:00 \
--opt3 "704 days, 19:21:44.938965"
arg=datetime.datetime(2012, 12, 21, 0, 1) (<class 'datetime.datetime'>)
opt1=datetime.date(2012, 12, 21) (<class 'datetime.date'>)
opt2=datetime.time(0, 1) (<class 'datetime.time'>)
opt3=datetime.timedelta(days=704, seconds=69704, microseconds=938965) (<class 'datetime.timedelta'>)
$ python date_time.py abc --opt1 a --opt2 b --opt3 c
Path type#
The path type can be used to indicate a file or directory path input.
pathlib.Path should be used to specify path inputs.
Important
pathlib.Path does not validate whether or not the path already exists.
See also
pydantic.types.NewPathcan be used to indicate a path that must not already exist.pydantic.types.FilePathcan be used to indicate a path to a file that must already exist.pydantic.types.DirectoryPathcan be used to indicate a path to a directory that must already exist.
Example
- Arguments:
ARG: Path to a file or directory (may not exist).
- Options:
--opt: Path to a file or directory (may not exist). Defaults to/usr/local/bin.
# path.py
import feud
from feud import typing as t
def command(arg: t.Path, *, opt: t.Path = t.Path("/usr/local/bin")):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt=!r} ({type(opt)})")
if __name__ == "__main__":
feud.run(command)
$ python literal.py --help
$ python path.py /opt/homebrew --opt ~/dev/feud/README.md
arg=PosixPath('/opt/homebrew') (<class 'pathlib.PosixPath'>)
opt=PosixPath('/Users/eonu/dev/feud/README.md') (<class 'pathlib.PosixPath'>)
As pathlib.Path allows any string, any input is accepted.
Sequence types#
Variable length#
Variable length sequence types can be used to accept multiple input values.
list/typing.Listshould be used to specify a list of inputs.set/typing.Setshould be used to specify a set of inputs.frozenset/typing.FrozenSetshould be used to specify a frozen set of inputs.collections.deque/typing.Dequeshould be used to specify a deque of inputs.
Tip
Additional type restrictions can be placed on the items within the sequence, e.g.:
See also
pydantic.types.conlistcan be used to impose restrictions such as minimum/maximum list length.pydantic.types.consetcan be used to impose restrictions such as minimum/maximum set length.pydantic.types.confrozensetcan be used to impose restrictions such as minimum/maximum frozen set length.
Example
- Arguments:
FLOATS: Any number of float values (at least one).
- Options:
--ints: Any number of integer values (at least one).
# variable.py
import feud
def command(floats: list[float], *, ints: set[int]):
print(f"{floats=!r} ({type(floats)})")
print(f"{ints=!r} ({type(ints)})")
if __name__ == "__main__":
feud.run(command)
$ python variable.py --help
$ python variable.py 1.1 2.2 3.3 --ints 0 --ints 1 --ints 0 --ints 2
floats=[1.1, 2.2, 3.3] (<class 'list'>)
ints={0, 1, 2} (<class 'set'>)
$ python variable.py string
Fixed length#
Fixed length sequence types can be used to accept a fixed number of input values.
tuple/typing.Tupleshould be used to specify a tuple of inputs.typing.NamedTupleshould be used to specify a named tuple of inputs.
Tip
When used with ... as the second type argument, tuple/typing.Tuple
may also be used to accept a variable length input and convert the items into a tuple,
e.g. tuple[int, ...] accepts a variable number of integers.
Example
- Arguments:
NUMBERS: Pair of numbers consisting of an integer and float.
- Options:
--location: Pair of numbers consisting of a latitude & longitude (both floats).
# fixed.py
import feud
from feud import typing as t
class Coordinate(t.NamedTuple):
latitude: t.Latitude
longitude: t.Longitude
def command(numbers: tuple[int, float], *, location: Coordinate):
print(f"{numbers=!r} ({type(numbers)})")
print(f"{location=!r} ({type(location)})")
if __name__ == "__main__":
feud.run(command)
$ python fixed.py --help
$ python fixed.py 1 1.1 --location 65.2 149.0
numbers=(1, 1.1) (<class 'tuple'>)
location=Coordinate(latitude=65.2, longitude=149.0) (<class '__main__.Coordinate'>)
$ python fixed.py 1 1.1 --location 100 200
Enumeration types (choices)#
Enumerate types can be used to limit the user to a number of choices.
enum.Enum/enum.StrEnumshould be used to limit the user to string choices.enum.IntEnumshould be used to limit the user to integer choices.
Important
enum.Enum values may only be strings.
Example
- Arguments:
ARG: Either the number1or2.
- Options:
--opt: Either the stringaorb. Defaults toa.
import feud
from feud import typing as t
class Mode(t.Enum):
A = "a"
B = "b"
class Version(t.IntEnum):
ONE = 1
TWO = 2
def command(arg: Version, *, opt: Mode = Mode.A):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt=!r} ({type(opt)})")
if __name__ == "__main__":
feud.run(command)
$ python literal.py --help
$ python enumeration.py 1 --opt b
arg=<Version.ONE: 1> (<enum 'Version'>)
opt=<Mode.B: 'b'> (<enum 'Mode'>)
$ python enumeration.py 3 --opt c
UUID type#
The UUID type can be used to indicate a UUID input.
uuid.UUID should be used to specify UUID inputs.
Example
- Arguments:
ARG: A UUID value.
- Options:
--opt: A UUID value. Defaults to a random UUID if none is provided.
# uuids.py
from uuid import uuid4
import feud
from feud import typing as t
def command(arg: t.UUID, *, opt: t.UUID = uuid4()):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt=!r} ({type(opt)})")
if __name__ == "__main__":
feud.run(command)
$ python uuids.py --help
$ python uuids.py 2b293576-fe8c-4482-898c-547adf5a4a25
arg=UUID('2b293576-fe8c-4482-898c-547adf5a4a25') (<class 'uuid.UUID'>)
opt=UUID('8186f015-8ca6-4793-9513-121288f972fd') (<class 'uuid.UUID'>)
$ python uuids.py 123
Unions#
Unions can be used to allow for an input to match two or more supported Feud types.
typing.Union or the | operator can be used to specify union types.
Example
- Arguments:
ARG: A UUID value.
- Options:
--opt: A UUID value. Defaults to a random UUID if none is provided.
# union.py
import feud
from feud import typing as t
def command(arg: t.Union[int, float], *, opt: int | float):
print(f"{arg=!r} ({type(arg)})")
print(f"{opt=!r} ({type(opt)})")
if __name__ == "__main__":
feud.run(command)
$ python union.py --help
$ python union.py 1 --opt 1.1
arg=1 (<class 'int'>)
opt=1.1 (<class 'float'>)
$ python union.py a --opt b