Base effect configuration classes.
BaseConfig works with argutils.ArgSpec field defaults to define effect
configuration options and populate an argparse.ArgumentParser.
BaseConfig._build_config constructs config instances either from a parsed
argparse.Namespace or from the default values stored on each field's
ArgSpec.
BaseConfig
dataclass
Base configuration class for effects.
This class serves as a base for all effect configurations, providing a common
interface for argument parser population and configuration building. Effect config
classes are created via _build_config, which reads values from a parsed
argparse.Namespace and falls back to argutils.ArgSpec defaults for fields
defined with ArgSpec instances. Any config class intended to be used to populate
a subparser must define a parser_spec attribute with type argutils.ParserSpec.
Source code in terminaltexteffects/engine/base_config.py
| @dataclass
class BaseConfig:
"""Base configuration class for effects.
This class serves as a base for all effect configurations, providing a common
interface for argument parser population and configuration building. Effect config
classes are created via `_build_config`, which reads values from a parsed
`argparse.Namespace` and falls back to `argutils.ArgSpec` defaults for fields
defined with `ArgSpec` instances. Any config class intended to be used to populate
a subparser must define a `parser_spec` attribute with type `argutils.ParserSpec`.
"""
@classmethod
def _populate_parser(cls, parser: argparse.ArgumentParser | argparse._SubParsersAction) -> None:
"""Populate the argument parser with the config class's argument specs.
If `parser` is a subparser collection, `cls.parser_spec` is used to create
the subparser before adding field argument specs. Config classes used in that mode
must define `parser_spec`.
Raises:
AttributeError: If `parser` is a subparser collection and `cls.parser_spec`
is not defined.
"""
if isinstance(parser, argparse._SubParsersAction):
parser = parser.add_parser(**vars(cls.parser_spec)) # pyright: ignore[reportAttributeAccessIssue]
parser.formatter_class = argutils.CustomFormatter # pyright: ignore[reportAttributeAccessIssue]
assert isinstance(parser, argparse.ArgumentParser)
for field in fields(cls):
if field.name == "parser_spec":
continue
spec = field.default
assert isinstance(spec, argutils.ArgSpec)
add_args_sig = {k: v for k, v in vars(spec).items() if v is not argutils._MISSING}
parser.add_argument(add_args_sig.pop("name"), **add_args_sig)
@classmethod
def _build_config(cls: type[CONFIG], parsed_args: argparse.Namespace | None = None) -> CONFIG:
"""Build a config instance from parsed arguments or `ArgSpec` defaults.
When `parsed_args` is provided, matching namespace attributes are used first and
missing fields fall back to each field's `ArgSpec.default` when available. When
`parsed_args` is `None`, the config is built entirely from `ArgSpec.default`
values.
Args:
parsed_args (argparse.Namespace | None): Parsed CLI arguments, or None to use
`ArgSpec` defaults only.
Raises:
AttributeError: If a required config field is missing from `parsed_args` and
does not define an `ArgSpec` default.
Returns:
CONFIG: A populated config instance.
"""
if parsed_args is not None:
config_args: dict[str, typing.Any] = {}
for field in fields(cls):
if field.name == "parser_spec":
continue
if hasattr(parsed_args, field.name):
config_args[field.name] = getattr(parsed_args, field.name)
elif isinstance(field.default, argutils.ArgSpec):
config_args[field.name] = field.default.default
else:
msg = f"Missing required config field '{field.name}' for {cls.__name__} in parsed arguments."
raise AttributeError(msg)
return cls(**config_args)
return cls(
**{
field.name: field.default.default
for field in fields(cls)
if isinstance(field.default, argutils.ArgSpec)
},
)
|
FinalGradientDirectionArg
dataclass
Bases: ArgSpec
Argument specification for selecting the final text gradient direction.
Source code in terminaltexteffects/engine/base_config.py
| @dataclass(frozen=True)
class FinalGradientDirectionArg(argutils.ArgSpec):
"""Argument specification for selecting the final text gradient direction."""
name: str = "--final-gradient-direction"
type: typing.Callable[[str], Gradient.Direction] = argutils.GradientDirection.type_parser
default: Gradient.Direction = Gradient.Direction.VERTICAL
metavar: str = argutils.GradientDirection.METAVAR
help: str = "Direction of the final gradient across the text."
|
FinalGradientFramesArg
dataclass
Bases: ArgSpec
Argument specification for selecting the final text gradient frames.
Source code in terminaltexteffects/engine/base_config.py
| @dataclass(frozen=True)
class FinalGradientFramesArg(argutils.ArgSpec):
"""Argument specification for selecting the final text gradient frames."""
name: str = "--final-gradient-frames"
type: typing.Callable[[str], int] = argutils.PositiveInt.type_parser
default: int = 5
metavar: str = argutils.PositiveInt.METAVAR
help: str = "Number of frames to display each gradient step. Increase to slow down the gradient animation."
|
FinalGradientStepsArg
dataclass
Bases: ArgSpec
Argument specification for selecting the final text gradient steps.
Source code in terminaltexteffects/engine/base_config.py
| @dataclass(frozen=True)
class FinalGradientStepsArg(argutils.ArgSpec):
"""Argument specification for selecting the final text gradient steps."""
name: str = "--final-gradient-steps"
type: typing.Callable[[str], int] = argutils.PositiveInt.type_parser
nargs: str = "+"
action: type[argutils.TupleAction] = argutils.TupleAction
default: tuple[int, ...] | int = 12
metavar: str = argutils.PositiveInt.METAVAR
help: str = (
"Space separated, unquoted, list of the number of gradient steps to use. "
"More steps will create a smoother and longer gradient animation."
)
|
FinalGradientStopsArg
dataclass
Bases: ArgSpec
Argument specification for selecting the final text gradient stops.
Source code in terminaltexteffects/engine/base_config.py
| @dataclass(frozen=True)
class FinalGradientStopsArg(argutils.ArgSpec):
"""Argument specification for selecting the final text gradient stops."""
name: str = "--final-gradient-stops"
type: typing.Callable[[str], Color] = argutils.ColorArg.type_parser
nargs: str = "+"
action: type[argutils.TupleAction] = argutils.TupleAction
default: tuple[Color, ...] = (Color("#8A008A"), Color("#00D1FF"), Color("#FFFFFF"))
metavar: str = argutils.ColorArg.METAVAR
help: str = (
"Space separated, unquoted, list of colors for the character gradient (applied across the canvas). "
"If only one color is provided, the characters will be displayed in that color."
)
|