Skip to content
This repository has been archived by the owner on Sep 15, 2024. It is now read-only.

Commit

Permalink
Update to Returns 0.15.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticfall committed Nov 9, 2020
1 parent 92327c7 commit 5d9fe1a
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 105 deletions.
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pytest = "*"

[packages]
rx = "3.1.1"
returns = "0.14.0"
returns = "0.15.0"

[requires]
python_version = "3.8"
190 changes: 107 additions & 83 deletions Pipfile.lock

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions alleycat/reactive/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import rx
from mypy_extensions import VarArg
from returns.context import RequiresContext
from returns.iterables import Fold
from returns.maybe import Maybe, Nothing
from rx import Observable

Expand All @@ -25,12 +26,12 @@ def new_view(read_only=False) -> ReactiveView:


def from_value(value: Optional[T], read_only=False) -> ReactiveProperty[T]:
return ReactiveProperty(Maybe.from_value(value), read_only)
return ReactiveProperty(Maybe.from_optional(value), read_only)


def from_observable(value: Optional[Observable] = None, read_only=False) -> ReactiveView:
init_value: RequiresContext[Observable, Any] = \
RequiresContext(lambda _: Maybe.from_value(value).value_or(rx.empty()))
RequiresContext(lambda _: Maybe.from_optional(value).value_or(rx.empty()))

return ReactiveView(init_value, read_only)

Expand All @@ -47,7 +48,9 @@ def process(modifier: Callable[[VarArg(Observable)], Observable]):
if modifier is None:
raise ValueError("Argument 'modifier' is required.")

init_value = RequiresContext.from_iterable([v.context for v in values]).map(lambda v: modifier(*v))
# noinspection PyTypeChecker
init_value = Fold.collect([v.context for v in values], RequiresContext.from_value(())) \
.map(lambda v: modifier(*v))

return ReactiveView(init_value)

Expand All @@ -73,8 +76,9 @@ def _combine_with(values: Sequence[ReactiveValue], combinator: Callable[[VarArg(
raise ValueError("Argument 'values' is required.")

def process(modifier: Callable[[Observable], Observable]):
init_value = RequiresContext.from_iterable([v.context for v in values]).map(
lambda v: combinator(*v)).map(modifier)
# noinspection PyTypeChecker
init_value = Fold.collect([v.context for v in values], RequiresContext.from_value(())) \
.map(lambda v: combinator(*v)).map(modifier)

return ReactiveView(init_value)

Expand All @@ -95,7 +99,7 @@ def process():
return process

(target, key) = Maybe \
.from_value(name) \
.from_optional(name) \
.map(lambda n: (obj, n)) \
.or_else_call(infer_name(utils.get_property_reference, 3))

Expand Down
6 changes: 4 additions & 2 deletions alleycat/reactive/property.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from typing import TypeVar, Generic, Callable, Optional, Any, cast, Tuple

import rx
from returns import pipeline
from returns.functions import identity
from returns.maybe import Maybe, Nothing
from returns.pipeline import pipe as pipe_
from rx import Observable
from rx.subject import BehaviorSubject

Expand Down Expand Up @@ -47,7 +47,9 @@ def as_view(self) -> ReactiveView[T]:

def pipe(self, modifiers: Callable[[Any], Tuple[Modifier, ...]]) -> ReactiveProperty:
def stack(obj: Any):
return pipe_(*([self.modifier(obj)] + list(modifiers(obj))))
# FIXME: Not sure why both PyCharm and Mypy fails to resolve pipeline.pipe(). Should investigate later.
# noinspection PyUnresolvedReferences
return pipeline.pipe(*([self.modifier(obj)] + list(modifiers(obj)))) # type:ignore

return ReactiveProperty(self.init_value, self.read_only, stack, self.validator)

Expand Down
4 changes: 2 additions & 2 deletions alleycat/reactive/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ def get_current_frame(depth: int = 1) -> Maybe[FrameType]:
raise ValueError("Argument 'depth' must be zero or a positive integer.")

def move_up(frame: Maybe[FrameType]) -> Maybe[FrameType]:
return frame.bind(lambda f: Maybe.from_value(f.f_back))
return frame.bind(lambda f: Maybe.from_optional(f.f_back))

return flow(Maybe.from_value(inspect.currentframe()), *[move_up for _ in range(depth)]) # type:ignore
return flow(Maybe.from_optional(inspect.currentframe()), *[move_up for _ in range(depth)]) # type:ignore


def get_property_reference(frame: FrameType) -> Maybe[Tuple[Any, str]]:
Expand Down
14 changes: 8 additions & 6 deletions alleycat/reactive/value.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self, read_only=False) -> None:
self._name: Optional[str] = None
self._read_only = read_only

data: RequiresContext[Any, ReactiveValue.Data[T]] = RequiresContext(lambda obj: self._get_data(obj))
data: RequiresContext[ReactiveValue.Data[T], Any] = RequiresContext(lambda obj: self._get_data(obj))

# Declare separately to prevent an object allocation with every value/observable reference.
self._context = data.map(lambda c: c.observable)
Expand Down Expand Up @@ -144,8 +144,7 @@ def __init__(self,
modifier: Callable[[Observable], Observable] = identity):
assert observable is not None

self.name = Maybe.from_value(name)

self._name = Maybe.from_optional(name)
self._value: Optional[U] = None

self._initialized = False
Expand All @@ -163,6 +162,10 @@ def update(value):
self._cancel_update = self.observable.subscribe(update, raise_exception)
self._connection = self._observable.connect() # type:ignore

@property
def name(self) -> Maybe[str]:
return self._name

def label(self) -> str:
return self.name.value_or("(anonymous)")

Expand Down Expand Up @@ -244,9 +247,8 @@ def init_data(v: Any):
return partial(initialize, v, self.name, new_instance)

return safe(getattr)(obj, DATA_KEY) \
.rescue(init_container) \
.bind(lambda v: safe(lambda: v[self.name])().rescue(init_data(v))) \
.fix(raise_exception) \
.lash(init_container) \
.bind(lambda v: safe(lambda: v[self.name])().lash(init_data(v))) \
.unwrap()

@abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
long_description_content_type="text/markdown",
url="https://github.com/mysticfall/alleycat-reactive",
packages=find_packages(),
install_requires=["returns==0.14.0", "rx==3.1.1"],
install_requires=["returns==0.15.0", "rx==3.1.1"],
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
Expand Down
10 changes: 6 additions & 4 deletions tests/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import rx
from returns.context import RequiresContext
from returns.iterables import Fold
from rx import operators as ops
from rx.subject import BehaviorSubject

Expand Down Expand Up @@ -188,10 +189,11 @@ class Fixture:

doubled: RV[int] = ReactiveView(value.context.map(lambda c: c.pipe(ops.map(lambda v: v * 2))))

result: RV[int] = ReactiveView(RequiresContext
.from_iterable([v.context for v in [value, doubled]])
.map(lambda v: rx.combine_latest(*v))
.map(lambda o: o.pipe(ops.map(lambda v: f"{v[0]} * 2 = {v[1]}"))))
# noinspection PyTypeChecker
result: RV[int] = ReactiveView(
Fold.collect([v.context for v in [value, doubled]], RequiresContext.from_value(()))
.map(lambda v: rx.combine_latest(*v))
.map(lambda o: o.pipe(ops.map(lambda v: f"{v[0]} * 2 = {v[1]}"))))

fixture = Fixture()

Expand Down

0 comments on commit 5d9fe1a

Please sign in to comment.