Pular para conteúdo

Core

O tipo de resultado e os singletons de valor.

py_return_success_or_error.core.return_success_or_error

O tipo de resultado da biblioteca: uma união fechada de sucesso ou falha.

ReturnSuccessOrError[TValue, TError] é um alias de união de :class:Success e :class:Failure. O erro é parametrizado por feature: cada caso de uso declara o seu conjunto fechado de erros (tipicamente uma união de tipos concretos), e o consumidor trata todos os casos de forma exaustiva.

Consumo canônico (exaustivo, provado pelo mypy/pyright)::

match result:
    case Success(value):
        ...  # caminho feliz
    case Failure(error):
        ...  # trate cada caso do union de erro
    case _:
        assert_never(result)

Para o estilo funcional, use a função :func:match.

ReturnSuccessOrError = Success[TValue] | Failure[TError]

União fechada de :class:Success e :class:Failure.

Só existem dois casos, e o match/case com assert_never prova a cobertura de ambos em tempo de checagem de tipos.

Failure dataclass

Caso de falha do resultado, carregando o erro ocorrido.

Imutável e com igualdade por valor. TError é o conjunto fechado de erros da feature — não há erro universal imposto pela biblioteca.

Attributes:

Name Type Description
error TError

O erro da feature.

Source code in src/py_return_success_or_error/core/return_success_or_error.py
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@final
@dataclass(frozen=True, slots=True)
class Failure[TError]:
    """Caso de **falha** do resultado, carregando o erro ocorrido.

    Imutável e com igualdade por valor. ``TError`` é o conjunto fechado
    de erros da feature — não há erro universal imposto pela biblioteca.

    Attributes:
        error: O erro da feature.
    """

    error: TError

    def __str__(self) -> str:
        return f'Failure: {self.error}'

Success dataclass

Caso de sucesso do resultado, carregando o valor produzido.

Imutável e com igualdade por valor.

Attributes:

Name Type Description
value TValue

O valor de sucesso.

Source code in src/py_return_success_or_error/core/return_success_or_error.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@final
@dataclass(frozen=True, slots=True)
class Success[TValue]:
    """Caso de **sucesso** do resultado, carregando o valor produzido.

    Imutável e com igualdade por valor.

    Attributes:
        value: O valor de sucesso.
    """

    value: TValue

    def __str__(self) -> str:
        return f'Success: {self.value}'

match(result, *, on_success, on_error)

Consome o resultado de forma exaustiva, no estilo funcional.

Exatamente um dos dois ramos é executado e o seu retorno é devolvido.

Parameters:

Name Type Description Default
result ReturnSuccessOrError[TValue, TError]

O resultado a consumir.

required
on_success Callable[[TValue], TResult]

Ramo executado com o valor quando for :class:Success.

required
on_error Callable[[TError], TResult]

Ramo executado com o erro quando for :class:Failure.

required

Returns:

Type Description
TResult

O retorno do ramo executado.

Source code in src/py_return_success_or_error/core/return_success_or_error.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def match[TValue, TError, TResult](
    result: ReturnSuccessOrError[TValue, TError],
    *,
    on_success: Callable[[TValue], TResult],
    on_error: Callable[[TError], TResult],
) -> TResult:
    """Consome o resultado de forma exaustiva, no estilo funcional.

    Exatamente um dos dois ramos é executado e o seu retorno é devolvido.

    Args:
        result: O resultado a consumir.
        on_success: Ramo executado com o valor quando for :class:`Success`.
        on_error: Ramo executado com o erro quando for :class:`Failure`.

    Returns:
        O retorno do ramo executado.
    """
    match result:
        case Success(value):
            return on_success(value)
        case Failure(error):
            return on_error(error)
        case _:  # pragma: no cover - inalcançável, provado pelo mypy
            assert_never(result)

py_return_success_or_error.core.unit

Representa uma operação concluída sem valor de retorno.

Como None não distingue "sem valor" de "valor ausente por erro", usa-se Unit como TValue quando o caso de uso não produz dado algum — ReturnSuccessOrError[Unit, MeuErro].

UNIT = Unit() module-attribute

Instância única de :class:Unit.

Unit

Singleton selado que representa "operação sem valor de retorno".

Use a constante de módulo :data:UNIT (Unit() também devolve sempre a mesma instância).

Source code in src/py_return_success_or_error/core/unit.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@final
class Unit:
    """Singleton selado que representa "operação sem valor de retorno".

    Use a constante de módulo :data:`UNIT` (``Unit()`` também devolve
    sempre a mesma instância).
    """

    __slots__ = ()
    _instance: ClassVar['Unit | None'] = None

    def __new__(cls) -> 'Unit':
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __reduce__(self) -> str:
        return 'UNIT'

    def __repr__(self) -> str:
        return 'UNIT'

    def __str__(self) -> str:
        return 'Unit - void'

py_return_success_or_error.core.nil

Representa o nulo como resultado válido e esperado.

Quando "não encontrado" é um sucesso legítimo (e não uma falha), use Nil no valor — por exemplo ReturnSuccessOrError[Cliente | Nil, MeuErro] — em vez de None, que ficaria ambíguo, ou de um caso de erro, que forçaria o chamador a tratar um não-erro como falha.

NIL = Nil() module-attribute

Instância única de :class:Nil.

Nil

Singleton selado que representa "nulo como resultado válido".

Use a constante de módulo :data:NIL (Nil() também devolve sempre a mesma instância).

Source code in src/py_return_success_or_error/core/nil.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@final
class Nil:
    """Singleton selado que representa "nulo como resultado válido".

    Use a constante de módulo :data:`NIL` (``Nil()`` também devolve
    sempre a mesma instância).
    """

    __slots__ = ()
    _instance: ClassVar['Nil | None'] = None

    def __new__(cls) -> 'Nil':
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __reduce__(self) -> str:
        return 'NIL'

    def __repr__(self) -> str:
        return 'NIL'

    def __str__(self) -> str:
        return 'Nil - null'