renderable Module#

Classes#

Renderable

A renderable.

RenderArgs

Render arguments.

ArgsNamespace

Render class-specific render argument namespace.

Frame

A rendered frame.

class term_image.renderable.Renderable(frame_count, frame_duration)[source]#

Bases: object

A renderable.

Parameters:
  • frame_count (int | FrameCount) –

    Number of frames. If it’s a

    • positive integer, the number of frames is as given.

    • FrameCount enum member, see the member’s description.

    If equal to 1 (one), the renderable is non-animated. Otherwise, it is animated.

  • frame_duration (int | FrameDuration) –

    The duration of a frame. If it’s a

    • positive integer, it implies a static duration (in milliseconds) i.e the same duration applies to every frame.

    • FrameDuration enum member, see the member’s description.

    This argument is ignored if frame_count equals 1 (one) i.e the renderable is non-animated.

Raises:

ValueError – An argument has an invalid value.

Attention

This is an abstract base class. Hence, only concrete subclasses can be instantiated.

See also

Renderable

Renderable‘s Extension API

Attributes:

Args

Render class-specific render arguments.

animated

True if the renderable is animated.

Special Methods:

__iter__

Returns a render iterator.

__str__

Renders the current frame with default arguments and no padding.

Instance Properties:

frame_count

Frame count

frame_duration

Frame duration

render_size

Render size

Instance Methods:

draw

Draws the current frame or an animation to standard output.

render

Renders the current frame.

seek

Sets the current frame number.

tell

Returns the current frame number.

Args: ClassVar[type[ArgsNamespace] | None]#

Render class-specific render arguments.

This is either:

  • a render argument namespace class (subclass of ArgsNamespace) associated [3] with the render class, or

  • None, if the render class has no render arguments.

If this is a class, an instance of it (or a subclass thereof) is contained within any RenderArgs instance associated [1] with the render class or any of its subclasses. Also, an instance of this class (or a subclass of it) is returned by render_args[render_cls]; where render_args is an instance of RenderArgs as previously described and render_cls is the render class with which this namespace class is associated [3].

Example
>>> class Foo(Renderable):
...     pass
...
... class FooArgs(ArgsNamespace, render_cls=Foo):
...     foo: str | None = None
...
>>> Foo.Args is FooArgs
True
>>>
>>> # default
>>> foo_args = Foo.Args()
>>> foo_args
FooArgs(foo=None)
>>> foo_args.foo is None
True
>>>
>>> render_args = RenderArgs(Foo)
>>> render_args[Foo]
FooArgs(foo=None)
>>>
>>> # non-default
>>> foo_args = Foo.Args("FOO")
>>> foo_args
FooArgs(foo='FOO')
>>> foo_args.foo
'FOO'
>>>
>>> render_args = RenderArgs(Foo, foo_args.update(foo="bar"))
>>> render_args[Foo]
FooArgs(foo='bar')

On the other hand, if this is None, it implies the render class has no render arguments.

Example
>>> class Bar(Renderable):
...     pass
...
>>> Bar.Args is None
True
>>> render_args = RenderArgs(Bar)
>>> render_args[Bar]
Traceback (most recent call last):
  ...
NoArgsNamespaceError: 'Bar' has no render arguments
animated: bool#

True if the renderable is animated. Otherwise, False.

iter(self)[source]#

Returns a render iterator.

Returns:

A render iterator (with frame caching disabled and all other optional arguments to RenderIterator being the default values).

Raises:

NonAnimatedRenderableError – The renderable is non-animated.

Return type:

RenderIterator

Animated renderables are iterable i.e they can be used with various means of iteration such as the for statement and iterable unpacking.

str(self)[source]#

Renders the current frame with default arguments and no padding.

Returns:

The frame render output.

Raises:

RenderError – An error occurred during rendering.

Return type:

str

property frame_count: int | Literal[FrameCount.INDEFINITE]#

Frame count

GET:

Returns either

  • the number of frames the renderable has, or

  • INDEFINITE.

property frame_duration: int | FrameDuration#

Frame duration

GET:

Returns

  • a positive integer, a static duration (in milliseconds) i.e the same duration applies to every frame; or

  • DYNAMIC.

SET:

If the value is

  • a positive integer, it implies a static duration (in milliseconds) i.e the same duration applies to every frame.

  • DYNAMIC, see the enum member’s description.

Raises:

NonAnimatedRenderableError – The renderable is non-animated.

property render_size: Size#

Render size

GET:

Returns the size of the renderable’s render output.

draw(render_args=None, padding=AlignedPadding(width=0, height=-2, h_align=CENTER, v_align=MIDDLE, fill=' '), *, animate=True, loops=-1, cache=100, check_size=True, allow_scroll=False, hide_cursor=True, echo_input=False)[source]#

Draws the current frame or an animation to standard output.

Parameters:
  • render_args (RenderArgs | None) – Render arguments.

  • padding (Padding) – Render output padding.

  • animate (bool) – Whether to enable animation for animated renderables. If disabled, only the current frame is drawn.

  • loops (int) – See RenderIterator (applies to animations only).

  • cache (bool | int) – See RenderIterator. (applies to animations only).

  • check_size (bool) – Whether to validate the padded render size of non-animations.

  • allow_scroll (bool) – Whether to validate the padded render height of non-animations. Ignored if check_size is False.

  • hide_cursor (bool) – Whether to hide the cursor while drawing.

  • echo_input (bool) –

    Whether to display input while drawing (applies on Unix only).

    Note

    • If disabled (default), input is not read/consumed, it’s just not displayed.

    • If enabled, echoed input may affect cursor positioning and therefore, the output (especially for animations).

Raises:

If check_size is True (or it’s an animation),

Note

  • hide_cursor and echo_input apply if and only if the output stream is connected to a terminal.

  • For animations (i.e animated renderables with animate = True), the padded render size is always validated.

  • Animations with definite frame count, by default, are infinitely looped but can be terminated with SIGINT (CTRL + C), without raising KeyboardInterrupt.

render(render_args=None, padding=ExactPadding(left=0, top=0, right=0, bottom=0, fill=' '))[source]#

Renders the current frame.

Parameters:
Returns:

The rendered frame.

Raises:
Return type:

Frame

seek(offset, whence=Seek.START)[source]#

Sets the current frame number.

Parameters:
  • offset (int) – Frame offset (relative to whence).

  • whence (Seek) – Reference position for offset.

Returns:

The new current frame number.

Raises:
Return type:

int

The value range for offset depends on whence:

whence

Valid value range for offset

START

0 <= offset < frame_count

CURRENT

-tell() <= offset < frame_count - tell()

END

-frame_count < offset <= 0

tell()[source]#

Returns the current frame number.

Returns:

Zero, if the renderable is non-animated or has INDEFINITE frame count. Otherwise, the current frame number.

Return type:

int


class term_image.renderable.RenderArgs(render_cls, /, *namespaces)[source]#
class term_image.renderable.RenderArgs(render_cls, init_render_args, /, *namespaces)

Bases: RenderArgsData

Render arguments.

Parameters:
  • render_cls (type[Renderable]) – A render class.

  • init_render_args (RenderArgs | None) –

    A set of render arguments. If not None,

    • it must be compatible [2] with render_cls,

    • it’ll be used to initialize the render arguments.

  • namespaces (ArgsNamespace) –

    Render argument namespaces compatible [4] with render_cls.

    Note

    If multiple namespaces associated with the same render class are given, the last of them takes precedence.

Raises:

A set of render arguments (an instance of this class) is basically a container of render argument namespaces (instances of ArgsNamespace); one for each render class, which has render arguments, in the Method Resolution Order of its associated [1] render class.

The namespace for each render class is derived from the following sources, in [descending] order of precedence:

  • namespaces

  • init_render_args

  • default render argument namespaces

Note

Instances are immutable but updated copies can be created via update().

See also

Args

Render class-specific render arguments.

Footnotes

Attributes:

render_cls

The associated render class

Special Methods:

__contains__

Checks if a render argument namespace is contained in this set of render arguments.

__eq__

Compares this set of render arguments with another.

__getitem__

Returns a constituent namespace.

__hash__

Computes the hash of the render arguments.

__iter__

Returns an iterator that yields the constituent namespaces.

Instance Methods:

convert

Converts the set of render arguments to one for a related render class.

update

Replaces or updates render argument namespaces.

render_cls: type[Renderable]#

The associated render class

namespace in self[source]#

Checks if a render argument namespace is contained in this set of render arguments.

Parameters:

namespace (ArgsNamespace) – A render argument namespace.

Returns:

True if the given namespace is equal to any of the namespaces contained in this set of render arguments. Otherwise, False.

Return type:

bool

self == other[source]#

Compares this set of render arguments with another.

Parameters:

other (object) – Another set of render arguments.

Returns:

True if both are associated with the same render class and have equal argument values. Otherwise, False.

Return type:

bool

self[render_cls][source]#

Returns a constituent namespace.

Parameters:

render_cls (type[Renderable]) – A render class of which render_cls is a subclass (which may be render_cls itself) and which has render arguments.

Returns:

The constituent namespace associated with render_cls.

Raises:
Return type:

Any

Note

The return type hint is Any only for compatibility with static type checking, as this aspect of the interface seems too dynamic to be correctly expressed with the exisiting type system.

Regardless, the return value is guaranteed to always be an instance of a render argument namespace class associated with render_cls. For instance, the following would always be valid for Renderable:

renderable_args: RenderableArgs = render_args[Renderable]

and similar idioms are encouraged to be used for other render classes.

hash(self)[source]#

Computes the hash of the render arguments.

Returns:

The computed hash.

Return type:

int

Important

Like tuples, an instance is hashable if and only if the constituent namespaces are hashable.

iter(self)[source]#

Returns an iterator that yields the constituent namespaces.

Returns:

An iterator that yields the constituent namespaces.

Return type:

Iterator[ArgsNamespace]

Warning

The number and order of namespaces is guaranteed to be the same across all instances associated [1] with the same render class but beyond this, should not be relied upon as the details (such as the specific number or order) may change without notice.

The order is an implementation detail of the Renderable API and the number should be considered alike with respect to the associated render class.

convert(render_cls)[source]#

Converts the set of render arguments to one for a related render class.

Parameters:

render_cls (type[Renderable]) – A render class of which render_cls is a parent or child (which may be render_cls itself).

Returns:

A set of render arguments associated [1] with render_cls and initialized with all constituent namespaces (of this set of render arguments, self) that are compatible [4] with render_cls.

Raises:

ValueErrorrender_cls is not a parent or child of render_cls.

Return type:

RenderArgs

update(namespace, /, *namespaces) RenderArgs[source]#
update(render_cls, /, **fields) RenderArgs

Replaces or updates render argument namespaces.

Parameters:
  • namespace (ArgsNamespace) – Prepended to namespaces.

  • namespaces (ArgsNamespace) –

    Render argument namespaces compatible [4] with render_cls.

    Note

    If multiple namespaces associated with the same render class are given, the last of them takes precedence.

  • render_cls (type[Renderable]) – A render class of which render_cls is a subclass (which may be render_cls itself) and which has render arguments.

  • fields (Any) –

    Render argument fields.

    The keywords must be names of render argument fields for render_cls.

Returns:

For the first form, an instance with the namespaces for the respective associated render classes of the given namespaces replaced.

For the second form, an instance with the given render argument fields for render_cls updated, if any.

Raises:

TypeError – The arguments given do not conform to any of the expected forms.

Return type:

RenderArgs

Propagates exceptions raised by:


class term_image.renderable.ArgsNamespace(*values, **fields)[source]#

Bases: ArgsDataNamespace

Render class-specific render argument namespace.

Parameters:
  • values (Any) –

    Render argument field values.

    The values are mapped to fields in the order in which the fields were defined.

  • fields (Any) –

    Render argument fields.

    The keywords must be names of render argument fields for the associated [3] render class.

Raises:

If no value is given for a field, its default value is used.

Note

  • Fields are exposed as instance attributes.

  • Instances are immutable but updated copies can be created via update().

See also

ArgsNamespace.

Footnotes

Special Methods:

__eq__

Compares the namespace with another.

__hash__

Computes the hash of the namespace.

__or__

Derives a set of render arguments from the combination of both operands.

__pos__

Creates a set of render arguments from the namespace.

__ror__

Same as __or__() but with reflected operands.

Instance Methods:

as_dict

Copies the namespace as a dictionary.

to_render_args

Creates a set of render arguments from the namespace.

update

Updates render argument fields.

Class Methods:

get_fields

Returns the field definitions.

get_render_cls

Returns the associated render class.

self == other[source]#

Compares the namespace with another.

Parameters:

other (object) – Another render argument namespace.

Returns:

True if both operands are associated with the same render class and have equal field values. Otherwise, False.

Return type:

bool

hash(self)[source]#

Computes the hash of the namespace.

Returns:

The computed hash.

Return type:

int

Important

Like tuples, an instance is hashable if and only if the field values are hashable.

self | other[source]#

Derives a set of render arguments from the combination of both operands.

Parameters:

other (ArgsNamespace | RenderArgs) – Another render argument namespace or a set of render arguments.

Returns:

A set of render arguments associated with the most derived one of the associated render classes of both operands.

Raises:
Return type:

RenderArgs

Note

  • If other is a render argument namespace associated with the same render class as self, other takes precedence.

  • If other is a set of render arguments that contains a namespace associated with the same render class as self, self takes precedence.

+self[source]#

Creates a set of render arguments from the namespace.

Returns:

A set of render arguments associated with the same render class as the namespace and initialized with the namespace.

Return type:

RenderArgs

Tip

+namespace is shorthand for namespace.to_render_args().

other | self[source]#

Same as __or__() but with reflected operands.

Note

Unlike __or__(), if other is a render argument namespace associated with the same render class as self, self takes precedence.

as_dict()[source]#

Copies the namespace as a dictionary.

Returns:

A dictionary mapping field names to their values.

Return type:

dict[str, Any]

Warning

The number and order of fields are guaranteed to be the same for a namespace class that defines fields, its subclasses, and all their instances; but beyond this, should not be relied upon as the details (such as the specific number or order) may change without notice.

The order is an implementation detail of the Render Arguments/Data API and the number should be considered an implementation detail of the specific namespace subclass.

classmethod get_fields()[source]#

Returns the field definitions.

Returns:

A mapping of field names to their default values.

Return type:

Mapping[str, Any]

Warning

The number and order of fields are guaranteed to be the same for a namespace class that defines fields, its subclasses, and all their instances; but beyond this, should not be relied upon as the details (such as the specific number or order) may change without notice.

The order is an implementation detail of the Render Arguments/Data API and the number should be considered an implementation detail of the specific namespace subclass.

to_render_args(render_cls=None)[source]#

Creates a set of render arguments from the namespace.

Parameters:

render_cls (type[Renderable] | None) – A render class, with which the namespace is compatible [4].

Returns:

A set of render arguments associated with render_cls (or the associated [3] render class of the namespace, if None) and initialized with the namespace.

Return type:

RenderArgs

Propagates exceptions raised by the RenderArgs constructor, as applicable.

See also

__pos__().

update(**fields)[source]#

Updates render argument fields.

Parameters:

fields (Any) – Render argument fields.

Returns:

A namespace with the given fields updated.

Raises:

UnknownArgsFieldError – Unknown field name(s).

Return type:

Self

classmethod get_render_cls()#

Returns the associated render class.

Returns:

The associated render class, if the namespace class has been associated.

Raises:

UnassociatedNamespaceError – The namespace class hasn’t been associated with a render class.

Return type:

type[Renderable]


class term_image.renderable.Frame(number, duration, render_size, render_output)[source]#

Bases: NamedTuple

A rendered frame.

Tip

  • Instances are immutable and hashable.

  • Instances with equal fields compare equal.

Warning

Even though this class inherits from tuple, the class and its instances should not be used as such, because:

  • this is an implementation detail,

  • the number or order of fields may change.

Any change to this aspect of the interface may happen without notice and will not be considered a breaking change.

Attributes:

number

Frame number

duration

Frame duration (in milliseconds)

render_size

Frame render size

render_output

Frame render output

Special Methods:

__str__

Returns the frame render output.

number: int#

Frame number

The number of the rendered frame (a non-negative integer), if the frame was rendered by a renderable with definite frame count. Otherwise, the value range and meaning of this field is unspecified.

duration: int#

Frame duration (in milliseconds)

The duration of the rendered frame (a non-negative integer), if the frame was rendered by an animated renderable. Otherwise, the value range and meaning of this field is unspecified.

Hint

For animated renderables, a zero value indicates that the next frame should be displayed immediately after (without any delay), except stated otherwise.

render_size: Size#

Frame render size

render_output: str#

Frame render output

str(self)[source]#

Returns the frame render output.

Returns:

The frame render output, render_output.

Return type:

str


Enumerations#

FrameCount

Frame count enumeration

FrameDuration

Frame duration enumeration

Seek

Relative seek enumeration

class term_image.renderable.FrameCount[source]#

Bases: Enum

Frame count enumeration

See also

frame_count, seek(), tell().

INDEFINITE#

Indicates a renderable has a streaming source.

In other words, it’s either the renderable has an infinite amount of frames or the exact amount cannot be predetermined.

POSTPONED#

Indicates lazy evaluation of frame count.

Evaluation of frame count is postponed until frame_count is invoked.


class term_image.renderable.FrameDuration[source]#

Bases: Enum

Frame duration enumeration

See also

frame_duration.

DYNAMIC#

Dynamic frame duration

The duration of each frame is determined at render-time.


class term_image.renderable.Seek[source]#

Bases: IntEnum

Relative seek enumeration

Tip

  • Each member’s value is that of the corresponding os.SEEK_* constant.

  • Every member can be used directly as an integer since enum.IntEnum is a base class.

SET = 0#
START = 0#

Start position

CUR = 1#
CURRENT = 1#

Current position

END = 2#

End position


Exceptions#

RenderableError

Base exception class for errors specific to the Renderable API and other APIs extending it.

IndefiniteSeekError

Raised when a seek is attempted on a renderable with INDEFINITE frame count.

RenderError

Base exception class for errors that occur during rendering.

RenderSizeOutofRangeError

Raised when the render size of a renderable is beyond an expected range.

RenderArgsDataError

Base exception class for errors specific to RenderArgs and RenderData.

RenderArgsError

Base exception class for errors specific to RenderArgs.

RenderDataError

Base exception class for errors specific to RenderData.

IncompatibleArgsNamespaceError

Raised when a given render argument namespace is incompatible [4] with a certain render class.

IncompatibleRenderArgsError

Raised when a given set of render arguments is incompatible [2] with a certain render class.

NoArgsNamespaceError

Raised when an attempt is made to get a render argument namespace for a render class that has no render arguments.

NoDataNamespaceError

Raised when an attempt is made to get a render data namespace for a render class that has no render data.

NonAnimatedRenderableError

Raised when attempting to perform certain operations meant for animated renderables on a non-animated renderable.

UnassociatedNamespaceError

Raised when certain operations are attempted on a render argument/data namespace class that hasn't been associated [3] [6] with a render class.

UninitializedDataFieldError

Raised when an attempt is made to access a render data field that hasn't been initialized i.e for which a value hasn't been set.

UnknownArgsFieldError

Raised when an attempt is made to access or modify an unknown render argument field.

UnknownDataFieldError

Raised when an attempt is made to access or modify an unknown render data field.

exception term_image.renderable.RenderableError[source]#

Bases: TermImageError

Base exception class for errors specific to the Renderable API and other APIs extending it.

Raised for errors that occur during the creation of render classes.

exception term_image.renderable.IndefiniteSeekError[source]#

Bases: RenderableError

Raised when a seek is attempted on a renderable with INDEFINITE frame count.

exception term_image.renderable.RenderError[source]#

Bases: RenderableError

Base exception class for errors that occur during rendering.

If the direct cause of the error is an exception, it should typically be attached as the context of this exception, as in:

raise SubclassOfRenderError("...") from exception
exception term_image.renderable.RenderSizeOutofRangeError[source]#

Bases: RenderableError

Raised when the render size of a renderable is beyond an expected range.

exception term_image.renderable.RenderArgsDataError[source]#

Bases: RenderableError

Base exception class for errors specific to RenderArgs and RenderData.

Raised for errors that occur during the creation of render argument/data namespace classes.

exception term_image.renderable.RenderArgsError[source]#

Bases: RenderArgsDataError

Base exception class for errors specific to RenderArgs.

Raised for errors that occur during the creation of render argument namespace classes.

exception term_image.renderable.RenderDataError[source]#

Bases: RenderArgsDataError

Base exception class for errors specific to RenderData.

exception term_image.renderable.IncompatibleArgsNamespaceError[source]#

Bases: RenderArgsError

Raised when a given render argument namespace is incompatible [4] with a certain render class.

exception term_image.renderable.IncompatibleRenderArgsError[source]#

Bases: RenderArgsError

Raised when a given set of render arguments is incompatible [2] with a certain render class.

exception term_image.renderable.NoArgsNamespaceError[source]#

Bases: RenderArgsError

Raised when an attempt is made to get a render argument namespace for a render class that has no render arguments.

exception term_image.renderable.NoDataNamespaceError[source]#

Bases: RenderDataError

Raised when an attempt is made to get a render data namespace for a render class that has no render data.

exception term_image.renderable.NonAnimatedRenderableError[source]#

Bases: RenderableError

Raised when attempting to perform certain operations meant for animated renderables on a non-animated renderable.

exception term_image.renderable.UnassociatedNamespaceError[source]#

Bases: RenderArgsDataError

Raised when certain operations are attempted on a render argument/data namespace class that hasn’t been associated [3] [6] with a render class.

exception term_image.renderable.UninitializedDataFieldError[source]#

Bases: RenderDataError, AttributeError

Raised when an attempt is made to access a render data field that hasn’t been initialized i.e for which a value hasn’t been set.

exception term_image.renderable.UnknownArgsFieldError[source]#

Bases: RenderArgsError, AttributeError

Raised when an attempt is made to access or modify an unknown render argument field.

exception term_image.renderable.UnknownDataFieldError[source]#

Bases: RenderDataError, AttributeError

Raised when an attempt is made to access or modify an unknown render data field.


Type Variables and Aliases#

term_image.renderable.OptionalPaddingT = TypeVar(OptionalPaddingT, bound=term_image.padding.Padding | None)#

Invariant TypeVar bound to typing.Optional[term_image.padding.Padding].


Extension API#

Note

The following interfaces are provided and required only to extend the Renderable API i.e to create custom renderables or extend any of those provided by this library.

Everything required for normal usage should typically be exposed in the public API.

For performance reasons, all implementations of these interfaces within this library perform no form of argument validation, except stated otherwise. The same should apply to any extension or override of these interfaces. All arguments are and should be expected to be valid. Hence, arguments should be validated beforehand if necessary.

In the same vein, return values of any of these interfaces will not be validated by the callers before use.

Renderable#

class term_image.renderable.Renderable[source]

See Renderable for the public API.

Classes:

Attributes:

_EXPORTED_ATTRS_

Exported attributes.

_EXPORTED_DESCENDANT_ATTRS_

Exported descendant attributes.

Instance Methods:

_animate_

Animates frames of a renderable.

_clear_frame_

Clears the previous frame of an animation, if necessary.

_get_frame_count_

Implements POSTPONED frame count evaluation.

_get_render_data_

Generates data required for rendering that's based on internal or external state.

_handle_interrupted_draw_

Performs any special handling necessary when an interruption occurs while writing a render output to a stream.

_init_render_

Initiates a render operation.

_render_

Renders a frame.

Class Methods:

_finalize_render_data_

Finalizes render data.

_Data_: ClassVar[type[DataNamespace] | None]#

Render class-specific render data.

This is either:

  • a render data namespace class (subclass of DataNamespace) associated [6] with the render class, or

  • None, if the render class has no render data.

If this is a class, an instance of it (or a subclass thereof) is contained within any RenderData instance associated [5] with the render class or any of its subclasses. Also, an instance of this class (or a subclass of it) is returned by render_data[render_cls]; where render_data is an instance of RenderData as previously described and render_cls is the render class with which this namespace class is associated [6].

Example
>>> class Foo(Renderable):
...     pass
...
... class _Data_(DataNamespace, render_cls=Foo):
...     foo: str | None
...
>>> Foo._Data_ is FooData
True
>>>
>>> foo_data = Foo._Data_()
>>> foo_data
<FooData: foo=<uninitialized>>
>>> foo_data.foo
Traceback (most recent call last):
  ...
UninitializedDataFieldError: The render data field 'foo' of 'Foo' has not been initialized
>>>
>>> foo_data.foo = "FOO"
>>> foo_data
<FooData: foo='FOO'>
>>> foo_data.foo
'FOO'
>>>
>>> render_data = RenderData(Foo)
>>> render_data[Foo]
<FooData: foo=<uninitialized>>
>>>
>>> render_data[Foo].foo = "bar"
>>> render_data[Foo]
<FooData: foo='bar'>

On the other hand, if this is None, it implies the render class has no render data.

Example
>>> class Bar(Renderable):
...     pass
...
>>> Bar._Data_ is None
True
>>>
>>> render_data = RenderData(Bar)
>>> render_data[Bar]
Traceback (most recent call last):
  ...
NoDataNamespaceError: 'Bar' has no render data

See also

RenderableData

Render data for Renderable.

_EXPORTED_ATTRS_: ClassVar[tuple[str, ...]]#

Exported attributes.

This specifies class attributes defined by the class (not a parent) on itself but not its subclasses which should be exported to definitions of the class in subprocesses.

These attributes are typically assigned using __class__.* within methods.

Note

  • Defining this is optional.

  • The attributes are exported for a class if and only if they are defined on that class when starting a subprocess.

  • The attributes are exported only for subprocesses started via multiprocessing.Process.

Tip

This can be used to export “private” attributes of the class across subprocesses.

_EXPORTED_DESCENDANT_ATTRS_: ClassVar[tuple[str, ...]]#

Exported descendant attributes.

This specifies class attributes defined by the class (not a parent) on itself and its subclasses (i.e descendant attributes) which should be exported to definitions of the class and its subclasses in subprocesses.

These attributes are typically assigned using cls.* within class methods.

This extends the exported descendant attributes of parent classes i.e all exported descendant attributes of a class are also exported for its subclasses.

Note

  • Defining this is optional.

  • The attributes are exported for a class if and only if they are defined on that class when starting a subprocess.

  • The attributes are exported only for subprocesses started via multiprocessing.Process.

Tip

This can be used to export “private” descendant attributes of the class across subprocesses.

_animate_(render_data, render_args, padding, loops, cache, output)[source]#

Animates frames of a renderable.

Parameters:
  • render_data (RenderData) – Render data.

  • render_args (RenderArgs) – Render arguments associated with the renderable’s class.

  • output (TextIO) – The text I/O stream to which rendered frames will be written.

All other parameters are the same as for draw(), except that padding must have absolute dimensions if it’s an instance of AlignedPadding.

This is called by draw() for animations.

Note

  • The base implementation does not finalize render_data.

  • Render size validation is expected to have been performed by the caller.

  • When called by draw() (at least, the base implementation), loops and cache wouldn’t have been validated.

_clear_frame_(render_data, render_args, cursor_x, output)[source]#

Clears the previous frame of an animation, if necessary.

Parameters:
  • render_data (RenderData) – Render data.

  • render_args (RenderArgs) – Render arguments.

  • cursor_x (int) –

    Column/horizontal position of the cursor at the point of calling this method.

    Note

    The position is 1-based i.e the leftmost column on the screen is at position 1 (one).

  • output (TextIO) – The text I/O stream to which frames of the animation are being written.

Called by the base implementation of _animate_() just before drawing the next frame of an animation.

Upon calling this method, the cursor should be positioned at the top-left-most cell of the region occupied by the frame render output on the terminal screen.

Upon return, ensure the cursor is at the same position it was at the point of calling this method (at least logically, since output shouldn’t be flushed yet).

The base implementation does nothing.

Note

  • This is required only if drawing the next frame doesn’t inherently overwrite the previous frame.

  • This is only meant (and should only be used) as a last resort since clearing the previous frame before drawing the next may result in visible flicker.

  • Ensure whatever this method does doesn’t result in the screen being scrolled.

Tip

To reduce flicker, it’s advisable to not flush output. It will be flushed after writing the next frame.

classmethod _finalize_render_data_(render_data)[source]#

Finalizes render data.

Parameters:

render_data (RenderData) – Render data.

Typically, an overriding method should

  • finalize the data generated by _get_render_data_() of the same class, if necessary,

  • call the overridden method, passing on render_data.

Note

  • It’s recommended to call RenderData.finalize() instead as that assures a single invocation of this method.

  • Any definition of this method should be safe for multiple invocations on the same RenderData instance, just in case.

See also

_get_render_data_(), RenderData.finalize(), the finalize parameter of _init_render_().

_get_frame_count_()[source]#

Implements POSTPONED frame count evaluation.

Returns:

The frame count of the renderable. See frame_count.

Note

Returning POSTPONED or 1 (one) is invalid and may result in unexpected/undefined behaviour across various interfaces defined by this library (and those derived from them), since re-postponing evaluation is unsupported and the renderable would have been taken to be animated.

Return type:

int | Literal[FrameCount.INDEFINITE]

The base implementation raises NotImplementedError.

_get_render_data_(*, iteration)[source]#

Generates data required for rendering that’s based on internal or external state.

Parameters:

iteration (bool) – Whether the render operation requiring the data involves a sequence of renders (most likely of different frames), or it’s a one-off render.

Returns:

The generated render data.

Return type:

RenderData

The render data should include copies of any variable/mutable internal/external state required for rendering and other data generated from constant state but which should persist throughout a render operation (which may involve consecutive/repeated renders of one or more frames).

May also be used to “allocate” and initialize storage for mutable/variable data specific to a render operation.

Typically, an overriding method should

Important

The RenderData instance returned must be associated [5] with the type of the renderable on which this method is called i.e type(self). This is always the case for the base implementation of this method.

Note

This method being called doesn’t mean the data generated will be used immediately.

abstract _get_render_size_()[source]#

Returns the renderable’s render size.

Returns:

The size of the renderable’s render output.

Return type:

Size

The base implementation raises NotImplementedError.

Note

Both dimensions are expected to be positive.

See also

render_size

_handle_interrupted_draw_(render_data, render_args, output)[source]#

Performs any special handling necessary when an interruption occurs while writing a render output to a stream.

Parameters:
  • render_data (RenderData) – Render data.

  • render_args (RenderArgs) – Render arguments.

  • output (TextIO) – The text I/O stream to which the render output was being written.

Called by the base implementations of draw() (for non-animations) and _animate_() when KeyboardInterrupt is raised while writing a render output.

The base implementation does nothing.

Note

output should be flushed by this method.

Hint

For a renderable that uses SGR sequences in its render output, this method may write CSI 0 m to output.

_init_render_(renderer, render_args=None, padding=None, *, iteration=False, finalize=True, check_size=False, allow_scroll=False)[source]#

Initiates a render operation.

Parameters:
  • renderer (Callable[[RenderData, RenderArgs], T]) – Performs a render operation or extracts render data and arguments for a render operation to be performed later on.

  • render_args (RenderArgs | None) – Render arguments.

  • padding (OptionalPaddingT) – Render output padding.

  • iteration (bool) – Whether the render operation involves a sequence of renders (most likely of different frames), or it’s a one-off render.

  • finalize (bool) – Whether to finalize the render data passed to renderer immediately renderer returns.

  • check_size (bool) – Whether to validate the [padded] render size of non-animations.

  • allow_scroll (bool) – Whether to validate the [padded] render height of non-animations. Ignored if check_size is False.

Returns:

A tuple containing

  • The return value of renderer.

  • padding (with equivalent absolute dimensions if it’s an instance of AlignedPadding).

Raises:
Return type:

tuple[T, OptionalPaddingT]

After preparing render data and processing arguments, renderer is called with the following positional arguments:

  1. Render data associated with the renderable’s class

  2. Render arguments associated with the renderable’s class and initialized with render_args

Any exception raised by renderer is propagated.

Important

Beyond this method (i.e any context from renderer onwards), use of any variable state (internal or external) should be avoided if possible. Any variable state (internal or external) required for rendering should be provided via _get_render_data_().

If at all any variable state has to be used and is not reasonable/practicable to be provided via _get_render_data_(), it should be read only once during a single render and passed to any nested/subsequent calls that require the value of that state during the same render.

This is to prevent inconsistency in data used for the same render which may result in unexpected output.

abstract _render_(render_data, render_args)[source]#

Renders a frame.

Parameters:
Returns:

The rendered frame.

  • The render_size field = render_data[Renderable].size.

  • The render_output field holds the render output. This string should:

    • contain as many lines as render_size.height i.e exactly render_size.height - 1 occurrences of \n (the newline sequence).

    • occupy exactly render_size.height lines and render_size.width columns on each line when drawn onto a terminal screen, at least when the render size it not greater than the terminal size on either axis.

      Tip

      If for any reason, the output behaves differently when the render height is greater than the terminal height, the behaviour, along with any possible alternatives or workarounds, should be duely noted. This doesn’t apply to the width.

    • not end with \n (the newline sequence).

  • As for the duration field, if the renderable is:

Raises:
Return type:

Frame

Note

StopIteration may be raised if and only if render_data[Renderable].iteration is True. Otherwise, it would be out of place.

See also

RenderableData.


ArgsNamespace#

class term_image.renderable.ArgsNamespace[source]

See ArgsNamespace for the public API.

Defining Fields#

Fields are defined as annotated class attributes. All annotated attributes of a subclass are taken to be fields. Every such attribute must be assigned a value which is taken to be the default value of the field.

Example
>>> class Foo(Renderable):
...     pass
...
>>> class FooArgs(ArgsNamespace, render_cls=Foo):
...     foo: str = "FOO"
...     bar: str = "BAR"
...
>>> FooArgs.get_fields()
mappingproxy({'foo': 'FOO', 'bar': 'BAR'})

The attribute annotations are only used to identify the fields, they’re never evaluated or used otherwise by any part of the Renderable API. The field names will be unbound from their assigned values (the default field values) during the creation of the class.

Note

A subclass that inherits fields must not define fields.

Associating With a Render Class#

To associate a namespace class with a render class, the render class should be specified via the render_cls keyword argument in the class definition header.

Example
>>> class Foo(Renderable):
...     pass
...
>>> class FooArgs(ArgsNamespace, render_cls=Foo):
...     foo: str = "FOO"
...
>>> FooArgs.get_render_cls() is Foo
True

Note

  • A subclass that has fields must be associated [3] with a render class.

  • A subclass that has NO fields cannot be associated with a render class.

  • A subclass that inherits fields cannot be reassociated with another render class.

Attention

Due to the design of the Renderable API, if a render class is intended to have a namespace class asssociated, the namespace class should be associated with it before it is subclassed or any RenderArgs instance associated with it is created.

Inheriting Fields#

Fields are inherited from any associated [3] render argument namespace class (i.e anyone that has fields) by subclassing it. The new subclass inherits both the fields and associated render class of its parent.

Example
>>> class Foo(Renderable):
...     pass
...
>>> class FooArgs(ArgsNamespace, render_cls=Foo):
...     foo: str = "FOO"
...
>>> FooArgs.get_render_cls() is Foo
True
>>> FooArgs.get_fields()
mappingproxy({'foo': 'FOO'})
>>>
>>> class SubFooArgs(FooArgs):
...     pass
...
>>> SubFooArgs.get_render_cls() is Foo
True
>>> SubFooArgs.get_fields()
mappingproxy({'foo': 'FOO'})

Note

A subclass that inherits fields:

  • must not define fields.

  • cannot be reassociated with another render class.

Other Notes#

Note

  • A subclass cannot have multiple base classes.

  • The constructor of any subclass that has fields must not have required parameters.

Tip

A subclass may neither define nor inherit fields. Such can be used as a base class for other namespace classes.

Important

Due to the design and implementation of the API, field values (including defaults) should:

  • (and are expected to) be immutable.

    Otherwise, such may yield unexpected behaviour during render operations or unexpected render outputs, if an object used as a field value is modified, as:

    • a namespace containing a mutable field value (or a set of render arguments containing such a namespace) may be in use in an asynchronous render operation,

    • different sets of render arguments may contain the same namespace, and

    • different namespaces may contain the same object as field values.

  • be hashable.

    Otherwise, the namespace and any containing set of render arguments will also not be hashable.


Other Classes#

RenderData

Render data.

DataNamespace

Render class-specific render data namespace.

RenderableData

Render data namespace for Renderable.

class term_image.renderable.RenderData(render_cls)[source]#

Bases: RenderArgsData

Render data.

Parameters:

render_cls (type[Renderable]) – A render class.

An instance of this class is basically a container of render data namespaces (instances of DataNamespace); one for each render class, which has render data, in the Method Resolution Order of its associated [5] render class.

Note

  • Instances are immutable but the constituent namespaces are mutable.

  • Instances and their contents shouldn’t be copied by any means because finalizing an instance may invalidate all other copies.

  • Instances should always be explicitly finalized as soon as they’re no longer needed.

See also

_Data_

Render class-specific render data.

Footnotes

Attributes:

render_cls

The associated render class

finalized

Finalization status

Special Methods:

__getitem__

Returns a constituent namespace.

__iter__

Returns an iterator that yields the constituent namespaces.

Instance Methods:

finalize

Finalizes the render data.

render_cls: type[Renderable]#

The associated render class

finalized: bool#

Finalization status

self[render_cls][source]#

Returns a constituent namespace.

Parameters:

render_cls (type[Renderable]) – A render class of which render_cls is a subclass (which may be render_cls itself) and which has render data.

Returns:

The constituent namespace associated with render_cls.

Raises:
Return type:

Any

Note

The return type hint is Any only for compatibility with static type checking, as this aspect of the interface seems too dynamic to be correctly expressed with the exisiting type system.

Regardless, the return value is guaranteed to always be an instance of a render data namespace class associated with render_cls. For instance, the following would always be valid for Renderable:

renderable_data: RenderableData = render_data[Renderable]

and similar idioms are encouraged to be used for other render classes.

iter(self)[source]#

Returns an iterator that yields the constituent namespaces.

Returns:

An iterator that yields the constituent namespaces.

Return type:

Iterator[DataNamespace]

Warning

The number and order of namespaces is guaranteed to be the same across all instances associated [5] with the same render class but beyond this, should not be relied upon as the details (such as the specific number or order) may change without notice.

The order is an implementation detail of the Renderable API and the number should be considered alike with respect to the associated render class.

finalize()[source]#

Finalizes the render data.

Calls _finalize_render_data_() of render_cls.

Note

This method is safe for multiple invocations on the same instance.


class term_image.renderable.DataNamespace[source]#

Bases: ArgsDataNamespace

Render class-specific render data namespace.

Raises:

UnassociatedNamespaceError – The namespace class hasn’t been associated [6] with a render class.

Subclassing, defining (and inheriting) fields and associating with a render class are just as they are for ArgsNamespace, except that values assigned to class attributes are neither required nor used.

Every field of a namespace is uninitialized immediately after instantiation. The fields are expected to be initialized within the _get_render_data_() method of the render class with which the namespace is associated [6] or at some other point during a render operation, if necessary.

Note

  • Fields are exposed as instance attributes.

  • Instances are mutable and fields can be updated in-place, either individually by assignment to an attribute reference or in batch via update().

  • An instance shouldn’t be copied by any means because finalizing its containing RenderData instance may invalidate all copies of the namespace.

Footnotes

Instance Methods:

as_dict

Copies the namespace as a dictionary.

update

Updates render data fields.

Class Methods:

get_fields

Returns the field names.

get_render_cls

Returns the associated render class.

as_dict()[source]#

Copies the namespace as a dictionary.

Returns:

A dictionary mapping field names to their current values.

Raises:

UninitializedDataFieldError – A field has not been initialized.

Return type:

dict[str, Any]

Warning

The number and order of fields are guaranteed to be the same for a namespace class that defines fields, its subclasses, and all their instances; but beyond this, should not be relied upon as the details (such as the specific number or order) may change without notice.

The order is an implementation detail of the Render Arguments/Data API and the number should be considered an implementation detail of the specific namespace subclass.

classmethod get_fields()[source]#

Returns the field names.

Returns:

A tuple of field names.

Return type:

tuple[str, …]

Warning

The number and order of fields are guaranteed to be the same for a namespace class that defines fields, its subclasses, and all their instances; but beyond this, should not be relied upon as the details (such as the specific number or order) may change without notice.

The order is an implementation detail of the Render Arguments/Data API and the number should be considered an implementation detail of the specific namespace subclass.

update(**fields)[source]#

Updates render data fields.

Parameters:

fields (Any) – Render data fields.

Raises:

UnknownDataFieldError – Unknown field name(s).

classmethod get_render_cls()#

Returns the associated render class.

Returns:

The associated render class, if the namespace class has been associated.

Raises:

UnassociatedNamespaceError – The namespace class hasn’t been associated with a render class.

Return type:

type[Renderable]


class term_image.renderable.RenderableData[source]#

Bases: DataNamespace

Render data namespace for Renderable.

See also

_Data_

Render class-specific render data.

_render_()

Renders a frame of a renderable.

Attributes:

size

Render size

frame_offset

Frame number/offset

seek_whence

Reference position for frame_offset

duration

Frame duration

iteration

Render operation kind

size: geometry.Size#

Render size

See _render_().

frame_offset: int#

Frame number/offset

If the frame_count of the renderable (that generated the data) is:

  • definite (i.e an integer); the value of this field is a non-negative integer less than the frame count, the number of the frame to be rendered.

  • INDEFINITE, the value range and interpretation of this field depends on the value of iteration and seek_whence.

    If iteration is False, the value is always zero and anything (such as a placeholder frame) may be rendered, as renderables with INDEFINITE frame count are typically meant for iteration/animation.

    If iteration is True and seek_whence is:

    • CURRENT, the value of this field may be:

      • zero, denoting that the next frame on the stream should be rendered.

      • positive, denoting that the stream should be seeked forward by frame_offset frames and then the new next frame should be rendered.

      • negative, denoting that the stream should be seeked backward by -frame_offset frames and then the new next frame should be rendered.

    • START, the value of this field may be:

      • zero, denoting that the stream should be seeked to its beginning and then the first frame should be rendered.

      • positive, denoting that the stream should be seeked to the (frame_offset)th frame after the first and then the new next frame should be rendered.

    • END, the value of this field may be:

      • zero, denoting that the stream should be seeked to its end and then the last frame should be rendered.

      • negative, denoting that the stream should be seeked to the (-frame_offset)th frame before the last and then the new next frame should be rendered.

      If the end of the stream cannot be determined (yet), such as with a live source, the furthest available frame in the forward direction should be taken to be the end.

    Note

    • If any seek operation is not supported by the underlying source, it should be ignored and the next frame on the stream should be rendered.

    • If forward seek is supported but the offset is out of the range of available frames, the stream should be seeked to the furthest available frame in the forward direction if its end cannot be determined (yet), such as with a live source. Otherwise i.e if the offset is determined to be beyond the end of the stream, StopIteration should be raised (see _render_()).

    • If backward seek is supported but the offset is out of the range of available frames, the stream should be seeked to its beginning or the furthest available frame in the backward direction.

    Tip

    A render class that implements INDEFINITE frame count should specify which seek operations it supports and any necessary details.

seek_whence: Seek#

Reference position for frame_offset

If the frame_count of the renderable (that generated the data) is definite, or INDEFINITE but iteration is False; the value of this field is always START. Otherwise i.e if frame_count is INDEFINITE and iteration is True, it may be any member of Seek.

duration: int | FrameDuration#

Frame duration

The possible values and their respective interpretations are the same as for frame_duration. See _render_() for usage details.

Attention

This field is left uninitialized for render data generated by/for non-animated renderables.

iteration: bool#

Render operation kind

True if the render is part of a render operation involving a sequence of renders (most likely of different frames). Otherwise i.e if it’s a one-off render, False.