Skip to content

redsun.injection

Sharing and asking

provides

provides(method: F) -> F

Share a method's return value under the type it is annotated with.

class MotorPresenter:
    @provides
    def readings(self) -> MotorReadings:
        return MotorReadings(...)

Anything asking for MotorReadings in its setup receives the result of calling this method on the built component. The return annotation is the key, so it must be distinct across the application.

DevicesOf module-attribute

DevicesOf: TypeAlias = Annotated[Mapping[str, P], Devices()]

Every device of the session that satisfies P, by name.

class MotorProtocol(Protocol):
    async def set(self, value: float) -> None: ...


class MotorPresenter:
    def __init__(self, name: str, *, motors: DevicesOf[MotorProtocol]) -> None:
        self._motors = motors

Devices are built before any presenter or view, so the mapping arrives complete and may be read while the component is built. Ask for redsun.DeviceMapping instead to receive every device, unfiltered.

Asking the session

satisfies

satisfies(candidate: type, protocol: TypeForm[P]) -> bool
satisfies(
    candidate: object, protocol: TypeForm[P]
) -> TypeIs[P]
satisfies(candidate: object, protocol: object) -> bool

Whether candidate satisfies protocol.

An instance that does is narrowed to protocol for a type checker; a class is not, since it is not an instance of the protocol it satisfies.

satisfying

satisfying(
    components: Mapping[str, object], protocol: TypeForm[P]
) -> dict[str, P]

Return the components of components that satisfy protocol, by name.

rejected

rejected(
    components: Mapping[str, Any], protocol: type
) -> dict[str, list[str]]

Return why each component that nearly matched protocol was left out.

Only components carrying some of the protocol's members appear, so a component missing all of them does not drown out a near miss.