Beispiel #1
0
 def ask(self, prompt: str, default: Literal['y', 'n'],
         do: ZIOMonad[System, NoReturn]) -> ZIO[System, NoReturn, bool]:
     default_str = 'Y/n' if default == 'y' else 'y/N'
     choice = do << self.get_input_from_console(
         prompt=f"{prompt} [{default_str}]: ",
         parse_value=(ZIO.from_callable(str).map(str.lower).require(
             lambda s: s in {'y', 'n'},
             lambda s: s).either().to_callable()),
         default_value=default)
     return ZIO.succeed(choice == 'y')
Beispiel #2
0
def prog(
    do: ZIOMonad[ConsoleSystemEnvironment, NoReturn]
) -> ZIO[ConsoleSystemEnvironment, NoReturn, int]:
    age = do << console.get_input_from_console(
        prompt="How old are you?\n",
        parse_value=ZIO.from_callable(str).map(int).catch(
            ValueError).either().to_callable(),
        default_value=21)
    do << console.print(f"You are {age} years old.")
    return ZIO.succeed(age)
Beispiel #3
0
 def input(
     self,
     prompt: Optional[str] = None
 ) -> ZIO[object, Union[EOFError, KeyboardInterrupt], str]:
     user_input = self._user_input.pop(0)
     self._effects.append(console_effect.Input(prompt, user_input))
     if isinstance(user_input, str):
         return ZIO.succeed(user_input)
     else:
         result: Union[EOFError, KeyboardInterrupt] = user_input
         return ZIO.fail(result)
Beispiel #4
0
def test_zio_flatten_1() -> None:
    count = 0

    def _impure_function(x: int) -> ZIO[object, NoReturn, int]:
        nonlocal count
        count += 1
        return ZIO.succeed(x + 1)

    assert (ZIO.succeed(100).flat_map(_impure_function).flat_map(
        _impure_function).flat_map(_impure_function).map(
            lambda x: ZIO.succeed(f"The result is: {x}")).flatten()._run(
                ())) == Right("The result is: 103")
    assert count == 3
Beispiel #5
0
def test_from_callable() -> None:
    def _f(arg_1: int, arg_2: str, *, arg_3: float) -> str:
        return f"{arg_1} {arg_2} {arg_3}"

    program = ZIO.from_callable(_f)
    assert unsafe_run(program.provide(FunctionArguments(
        42, "foo", arg_3=3.14))) == "42 foo 3.14"
Beispiel #6
0
def test_zio_flatten_2() -> None:
    count = 0

    def _impure_function(x: int) -> ZIO[object, NoReturn, int]:
        nonlocal count
        count += 1
        return ZIO.succeed(x + 1)

    def _kaboom(x: int) -> ZIO[object, NoReturn, int]:
        raise Bippy

    assert (ZIO.succeed(100).flat_map(_impure_function).flat_map(
        _kaboom).flat_map(_impure_function).flat_map(_impure_function).map(
            lambda x: ZIO.succeed(f"The result is: {x}")).catch(
                Bippy).flatten()._run(())) == Left(Bippy())
    assert count == 1
Beispiel #7
0
def test_zio_catch_3() -> None:
    def _impure_function() -> int:
        raise Bippy

    program = ZIO.effect_total(_impure_function).catch(NotBippy)
    with pytest.raises(Bippy):
        program._run(())
Beispiel #8
0
def test_zio_effect_catch_3() -> None:
    def _impure_function() -> None:
        raise Bippy

    program = ZIO.effect_catch(_impure_function, NotBippy)
    with pytest.raises(Bippy):
        program._run(())
Beispiel #9
0
def test_get_input_from_console_eof_error() -> None:
    program = console.get_input_from_console(
        prompt="How much wood would a woodchuck chuck?",
        parse_value=ZIO.from_callable(str).map(int).catch(
            ValueError).either().to_callable(),
        default_value=None)

    exception = EOFError()

    mock_console = MockConsole(["bad", "input", exception])
    mock_system = MockSystem()
    with pytest.raises(SystemExit):
        unsafe_run(
            program.provide(
                ConsoleSystemEnvironment(console=mock_console,
                                         system=mock_system)))

    assert mock_console.effects == [
        console_effect.Input("How much wood would a woodchuck chuck?", "bad"),
        console_effect.Input("How much wood would a woodchuck chuck?",
                             "input"),
        console_effect.Input("How much wood would a woodchuck chuck?",
                             exception),
        console_effect.Print("")
    ]
    assert mock_console.user_input == []

    assert mock_system.effects == [system_effect.Exit(None)]
Beispiel #10
0
 def input(
     self,
     prompt: Optional[str] = None
 ) -> ZIO[object, Union[EOFError, KeyboardInterrupt], str]:
     return (ZIO.effect_catch(
         lambda: builtins.input(prompt)
         if prompt is not None else builtins.input(),
         EOFError).catch(KeyboardInterrupt))
Beispiel #11
0
def program(
    do: ZIOMonad[Console, Union[EOFError, KeyboardInterrupt]]
) -> ZIO[Console, Union[EOFError, KeyboardInterrupt], str]:
    con = do << Environment()

    do << con.print("Hello, what is your name?")
    name = do << con.input()
    do << con.print(f"Your name is: {name}")
    x = do << ZIO.succeed(1)

    while x < 20:
        x = do << (
            ZIO.succeed(x).map(lambda p: p + 1).flat_map(lambda q: ZIO.succeed(
                q - 1)).flat_map(lambda r: ZIO.succeed(r + 1)))

    do << con.print(f"The value of x is: {x}")
    return ZIO.succeed(f"Hello, {name}!")
Beispiel #12
0
    def get_input_from_console(
            self, prompt: str, parse_value: Callable[[str], Either[E, A]],
            default_value: Optional[A],
            do: ZIOMonad[System, NoReturn]) -> ZIO[System, NoReturn, A]:
        while True:
            keyboard_input = do << (
                self.input(prompt).either().map(lambda e: e.to_union()))

            if isinstance(keyboard_input, (EOFError, KeyboardInterrupt)):
                do << self.print("")
                system = do << Environment()
                return system.exit()

            if keyboard_input == '' and default_value is not None:
                return ZIO.succeed(default_value)

            parse_result = parse_value(keyboard_input)
            if isinstance(parse_result, Right):
                return ZIO.succeed(parse_result.value)
Beispiel #13
0
def test_zio_effect_catch_1() -> None:
    x: Optional[int] = None

    def _impure_function() -> int:
        nonlocal x
        x = 100
        return 42

    program = ZIO.effect_catch(_impure_function, Bippy)
    assert x is None
    assert program._run(()) == Right(42)
    assert x == 100
Beispiel #14
0
def test_zio_map_1() -> None:
    count = 0

    def _impure_function(x: int) -> int:
        nonlocal count
        count += 1
        return x + 1

    assert (ZIO.succeed(100).map(_impure_function).map(_impure_function).map(
        _impure_function).map(lambda x: f"The result is: {x}")._run(
            ())) == Right("The result is: 103")
    assert count == 3
Beispiel #15
0
def test_from_to_callable_1() -> None:
    class Cat:
        def meow(self, *, volume: int) -> str:
            if volume < 10:
                return "meow"
            else:
                return "MEOW!"

    meow_to_callable = (Environment[Cat]().map(lambda cat: ZIO.from_callable(
        cat.meow)).swap_environments().to_callable())

    assert unsafe_run(meow_to_callable(volume=11).provide(Cat())) == "MEOW!"
Beispiel #16
0
def test_zio_effect_success() -> None:
    x: Optional[int] = None

    def _impure_function() -> None:
        nonlocal x
        x = 42

    program = ZIO.effect(_impure_function)
    assert x is None

    program._run(())
    assert x == 42
Beispiel #17
0
def test_zio_map_error_1() -> None:
    count = 0

    def _impure_function(x: int) -> int:
        nonlocal count
        count += 1
        return x + 1

    assert (ZIO.fail(100).map_error(_impure_function).map_error(
        _impure_function).map_error(_impure_function).map_error(
            lambda x: f"The result is: {x}")._run(
                ())) == Left("The result is: 103")
    assert count == 3
Beispiel #18
0
def test_zio_lshift_2() -> None:
    def _kaboom(x: object) -> Either[NoReturn, int]:
        raise Bippy

    assert ((ZIO.succeed(100) << ZIO.succeed(1) << ZIO.succeed(2) <<
             ZIO(_kaboom) << ZIO.succeed(3)).flat_map(lambda x: ZIO.succeed(
                 f"The result is: {x}")).catch(Bippy))._run(
                     ()) == Left(Bippy())
Beispiel #19
0
def test_from_to_callable_2() -> None:
    @dataclass(frozen=True)
    class SomeException(Exception):
        message: str

    class SomeAPI:
        def thing_that_may_fail(self, *, bippy: str) -> int:
            raise SomeException("Murphy's Law")

    safer_thing = (Environment[SomeAPI]().map(
        lambda api: (ZIO.from_callable(api.thing_that_may_fail).catch(
            SomeException).either())).swap_environments().to_callable())

    assert unsafe_run(safer_thing(bippy="bippy").provide(SomeAPI())) == Left(
        SomeException("Murphy's Law"))
Beispiel #20
0
def test_zio_map_error_2() -> None:
    count = 0

    def _impure_function(x: int) -> int:
        nonlocal count
        count += 1
        return x + 1

    def _kaboom(x: int) -> int:
        raise Bippy

    assert (ZIO.fail(100).map_error(_impure_function).map_error(_kaboom).
            map_error(_impure_function).map_error(_impure_function).map_error(
                lambda x: f"The result is: {x}").catch(Bippy)._run(
                    ())) == Left(Bippy())
    assert count == 1
Beispiel #21
0
def test_get_input_from_console_1() -> None:
    program = console.get_input_from_console(
        prompt="How much wood would a woodchuck chuck?",
        parse_value=ZIO.from_callable(str).map(int).catch(
            ValueError).either().to_callable(),
        default_value=None)

    mock_console = MockConsole(["42"])
    mock_system = MockSystem()

    output = unsafe_run(
        program.provide(
            ConsoleSystemEnvironment(console=mock_console,
                                     system=mock_system)))
    assert output == 42
    assert mock_console.effects == [
        console_effect.Input("How much wood would a woodchuck chuck?", "42")
    ]
    assert mock_console.user_input == []
Beispiel #22
0
 def exit(
         self,
         exit_code: Optional[int] = None
 ) -> ZIO[object, NoReturn, NoReturn]:
     self._effects.append(system_effect.Exit(exit_code))
     return ZIO.fail(SystemExit(exit_code)).or_die()
Beispiel #23
0
 def exit(
         self,
         exit_code: Optional[int] = None
 ) -> ZIO[object, NoReturn, NoReturn]:
     return ZIO.effect_total(lambda: sys.exit(exit_code))  # type: ignore
Beispiel #24
0
 def print(self, line: str) -> ZIO[object, NoReturn, None]:
     self._effects.append(console_effect.Print(line))
     return ZIO.succeed(None)
Beispiel #25
0
def test_zio_fail() -> None:
    assert ZIO.fail(42)._run(()) == Left(42)
Beispiel #26
0
 def print(self, line: str) -> ZIO[object, NoReturn, None]:
     return ZIO.effect_total(lambda: builtins.print(line))
Beispiel #27
0
def test_to_callable() -> None:
    def _f(arg_1: int, arg_2: str, *, arg_3: float) -> str:
        return f"{arg_1} {arg_2} {arg_3}"

    g = ZIO.from_callable(_f).to_callable()
    assert g(42, "foo", arg_3=3.14) == "42 foo 3.14"
Beispiel #28
0
def test_zio_effect_failure() -> None:
    def _impure_function() -> None:
        raise Bippy

    program = ZIO.effect(_impure_function)
    assert program._run(()) == Left(Bippy())
Beispiel #29
0
    def effects(
            self) -> List[Union[console_effect.Print, console_effect.Input]]:
        return self._effects

    @property
    def user_input(self) -> List[Union[EOFError, KeyboardInterrupt, str]]:
        return self._user_input


class HasConsole(Protocol):
    @property
    def console(self) -> Console:
        pass  # pragma: nocover


print = (Environment[HasConsole]().map(lambda env: ZIO.from_callable(
    env.console.print).flatten()).swap_environments().to_callable())

input = (Environment[HasConsole]().map(lambda env: ZIO.from_callable(
    env.console.input).flatten()).swap_environments().to_callable())


class HasConsoleSystem(HasConsole, HasSystem, Protocol):
    pass


def get_input_from_console(
        prompt: str, parse_value: Callable[[str], Either[E, A]],
        default_value: Optional[A]) -> ZIO[HasConsoleSystem, NoReturn, A]:
    return (Environment[HasConsoleSystem]
            ().flat_map(lambda env: env.console.get_input_from_console(
                prompt, parse_value, default_value).provide(env.system)))
Beispiel #30
0
def test_zio_effect_catch_2() -> None:
    def _impure_function() -> None:
        raise Bippy

    program = ZIO.effect_catch(_impure_function, Bippy)
    assert program._run(()) == Left(Bippy())