Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
import asyncio
from subprocess import PIPE, CalledProcessError
from typing import IO, Tuple, Union
from typing_extensions import Protocol
from .aio_trampoline import Done
from .effect import Effect, Try, add_repr, get_environment
from .either import Left, Right
from .immutable import Immutable
class Subprocess(Immutable):
"""
Module that enables running commands in the shell
"""
def run_in_shell(
self,
cmd: str,
stdin: Union[IO, int] = PIPE,
stdout: Union[IO, int] = PIPE,
stderr: Union[IO, int] = PIPE
) -> Try[CalledProcessError, Tuple[bytes, bytes]]:
"""
Get an `Effect` that runs `cmd` in the shell
Example:
>>> Subprocess().run_in_shell('cat foo.txt').run(None)
(b'contents of foo.txt', b'')
from .curry import curry
from .immutable import Immutable
from .monad import Monad, filter_m_, map_m_, sequence_
from .trampoline import Call, Done, Trampoline
from .with_effect import with_effect_
Context = TypeVar('Context')
Result_ = TypeVar('Result_')
Next = TypeVar('Next')
A = TypeVar('A')
B = TypeVar('B')
class Reader(Immutable, Generic[Context, Result_], Monad):
"""
Represents a computation that is not yet completed, but
will complete once given an object of type ``Context``
"""
f: Callable[[Context], Trampoline[Result_]]
def and_then(
self: 'Reader[Context, Result_]',
f: 'Callable[[Result_], Reader[Context, Next]]'
) -> 'Reader[Context, Next]':
"""
Compose ``f`` with the function wrapped by this
:class:`Reader` instance
>>> f(None)
1
>>> f('')
1
>>> "... and so on..."
Args:
value: The value to return always
Return:
function that always returns `value`
"""
return Always(value)
class Composition(Immutable):
functions: Tuple[Callable, ...]
def __call__(self, *args, **kwargs):
fs = reversed(self.functions)
first, *rest = fs
last_result = first(*args, **kwargs)
for f in rest:
last_result = f(last_result)
return last_result
def compose(
f: Callable[[Any], Any],
g: Callable[[Any], Any],
*functions: Callable[[Any], Any]
) -> Callable[[Any], Any]:
return await resource.get.__aexit__(*args, **kwargs)
class RuntimeEnv(Immutable, Generic[A]):
"""
Wraps the user supplied environment R and supplies various utilities
for the effect runtime such as the resource AsyncExitStack
:attribute r: The user supplied environment value
:attribute exit_stack: AsyncExitStack used to enable Effect resources
"""
r: A
exit_stack: AsyncExitStack
class Effect(Generic[R, E, A], Immutable):
"""
Wrapper for functions of type \
`Callable[[R], Awaitable[pfun.Either[E, A]]]` that are allowed to \
perform side-effects
"""
run_e: Callable[[RuntimeEnv[R]], Awaitable[Trampoline[Either[E, A]]]]
_repr: str = ''
def with_repr(self, s: str) -> Effect[R, E, A]:
return Effect(self.run_e, s) # type: ignore
def __repr__(self):
if not self._repr:
return f'Effect(run_e={repr(self.run_e)})'
return self._repr
from .either import Right
from .immutable import Immutable
from .maybe import Maybe, from_optional
from .parse import JSon
try:
import aiohttp
from aiohttp.client_exceptions import ClientError
except ImportError:
raise ImportError(
'Could not import aiohttp. To use pfun.effect.http, '
'install pfun with \n\n\tpip install pfun[http]'
)
class Response(Immutable):
"""
The result of making a HTTP request.
"""
content: bytes
"""
The response content
"""
status: int
"""
The request status
"""
reason: Maybe[str]
"""
The reason for the request status, e.g "OK"
"""
cookies: http.cookies.BaseCookie
from functools import wraps
from typing import (Any, Callable, Generic, Iterable, Optional, Sequence,
TypeVar, Union, cast)
from .either import Either, Left
from .functions import curry
from .immutable import Immutable
from .list import List
from .monad import Monad, filter_m_, map_m_, sequence_
A = TypeVar('A', covariant=True)
B = TypeVar('B')
C = TypeVar('C')
class Maybe_(Immutable, Monad, ABC):
"""
Abstract super class for classes that represent computations that can fail.
Should not be instantiated directly.
Use `Just` and `Nothing` instead.
"""
@abstractmethod
def and_then(self, f: Callable) -> Any:
"""
Chain together functional calls, carrying along the state of the
computation that may fail.
Example:
>>> f = lambda i: Just(1 / i) if i != 0 else Nothing()
>>> Just(2).and_then(f)
Just(0.5)
from typing import Callable, Generator, Generic, Iterable, TypeVar, cast
from pfun.monoid import M, append, empty
from .curry import curry
from .either import Either, Left
from .immutable import Immutable
from .monad import Monad, filter_m_, map_m_, sequence_
from .with_effect import with_effect_tail_rec
A = TypeVar('A')
B = TypeVar('B')
class Writer(Generic[A, M], Immutable, Monad):
"""
Represents a value
along with a monoid value that is accumulated as
an effect
"""
a: A
m: M
def and_then(self, f: 'Callable[[A], Writer[B, M]]') -> 'Writer[B, M]':
"""
Pass the value in this value/monoid pair to ``f``,
and then combine the resulting monoid with the monoid in this pair
:example:
>>> Writer(1, ['first element']).and_then(
@wraps(f)
def decorator(*args, **kwargs):
effect = f(*args, **kwargs)
self, *args = args
args_repr = ', '.join([repr(arg) for arg in args])
kwargs_repr = ', '.join(
[f'{name}={repr(value)}' for name, value in kwargs.items()]
)
sig_repr = args_repr + ((', ' + kwargs_repr) if kwargs_repr else '')
repr_ = f'{repr(self)}.{f.__name__}({sig_repr})'
return effect.with_repr(repr_)
return decorator # type: ignore
class Resource(Immutable, Generic[E, C]):
"""
Enables lazy initialisation of global async context managers that should \
only be entered once per effect invocation. If the same resource is \
acquired twice by an effect using `get`, the same context manager will \
be returned. All context managers controlled by resources are guaranteed \
to be entered before the effect that requires it is invoked, and exited \
after it returns. The wrapped context manager is only available when the \
resources context is entered.
:example:
>>> from aiohttp import ClientSession
>>> resource = Resource(ClientSession)
>>> r1, r2 = resource.get().and_then(
... lambda r1: resource.get().map(lambda r2: (r1, r2))
... )
import logging
from types import TracebackType
from typing import Optional, Tuple, Type, Union
from typing_extensions import Protocol
from .aio_trampoline import Done
from .effect import Depends, Effect, Success, add_repr, get_environment
from .either import Right
from .immutable import Immutable
ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType]
class Logger(Immutable):
"""
Wrapper around built-in `logging.Logger` class that
calls logging methods as effects
"""
logger: logging.Logger
def debug(
self,
msg: str,
stack_info: bool = False,
exc_info: Union[bool, ExcInfo] = False
) -> Success[None]:
"""
Create an effect that calls built-in `logging.debug`
Example:
"""
try:
return success(List(type_(**row) for row in results) # type: ignore
)
except TypeError as e:
return error(e)
class MalformedConnectionStr(Exception):
"""
Error returned when a malformed connection str is passed to `SQL`
"""
class SQL(Immutable, init=False):
"""
Module providing postgres sql client capability
"""
connection: Resource[asyncpg.PostgresError, PostgresConnection]
def __init__(self, connection_str: str):
"""
Create an SQL module
Args:
connection_str: connection string of the format \
`postgres://:@/`
"""
url = urllib.parse.urlparse(connection_str)
if url.scheme not in {'postgresql', 'postgres'}:
raise MalformedConnectionStr(connection_str)