Skip to content

Commit 1e279b8

Browse files
committed
Fixes
- Type callback protocols - Add missing exports
1 parent a9f9285 commit 1e279b8

File tree

8 files changed

+64
-15
lines changed

8 files changed

+64
-15
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ $ pip3 install expression
7272
4. [Optional Values](https://github.com/cognitedata/Expression/blob/main/notebooks/04%20-%20Optional%20Values.md)
7373
5. [Railway Oriented Programming](https://github.com/cognitedata/Expression/blob/main/notebooks/05%20-%20Railway%20Oriented%20Programming.md)
7474
6. [Effects and Side-effects](https://github.com/cognitedata/Expression/blob/main/notebooks/06%20-%20Effects%20and%20Side-Effects.md)
75+
7576
## Goals
7677

7778
- Industrial strength library for functional programming in Python.

expression/collections/frozenlist.py

+23-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,21 @@
2020

2121
import builtins
2222
import functools
23-
from typing import (Any, Callable, Generic, Iterable, Iterator, List, Optional,
24-
Protocol, Tuple, TypeVar, cast, get_origin, overload)
23+
from typing import (
24+
Any,
25+
Callable,
26+
Generic,
27+
Iterable,
28+
Iterator,
29+
List,
30+
Optional,
31+
Protocol,
32+
Tuple,
33+
TypeVar,
34+
cast,
35+
get_origin,
36+
overload,
37+
)
2538

2639
from expression.core import Case, Nothing, Option, Some, pipe
2740

@@ -426,6 +439,13 @@ def __call__(self, __source: FrozenList[TSource]) -> FrozenList[TSource]:
426439
...
427440

428441

442+
class TransformFn(Protocol[TResult]):
443+
"""A partially applied filter function."""
444+
445+
def __call__(self, __source: FrozenList[TSource]) -> FrozenList[TResult]:
446+
...
447+
448+
429449
def append(source: FrozenList[TSource]) -> Callable[[FrozenList[TSource]], FrozenList[TSource]]:
430450
def _append(other: FrozenList[TSource]) -> FrozenList[TSource]:
431451
return source.append(other)
@@ -586,7 +606,7 @@ def is_empty(source: FrozenList[TSource]) -> bool:
586606
return source.is_empty()
587607

588608

589-
def map(mapper: Callable[[TSource], TResult]) -> Callable[[FrozenList[TSource]], FrozenList[TResult]]:
609+
def map(mapper: Callable[[TSource], TResult]) -> TransformFn[TResult]:
590610
"""Map list.
591611
592612
Builds a new collection whose elements are the results of applying

expression/collections/seq.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
import builtins
2020
import functools
2121
import itertools
22-
from typing import (Any, Callable, Iterable, Iterator, Optional, Protocol,
23-
Tuple, TypeVar, overload)
22+
from typing import Any, Callable, Iterable, Iterator, Optional, Protocol, Tuple, TypeVar, overload
2423

2524
from expression.core import Case, Option, SupportsLessThan, identity, pipe
2625

@@ -290,7 +289,7 @@ def concat(*iterables: Iterable[TSource]) -> Iterable[TSource]:
290289
"""The empty sequence."""
291290

292291

293-
def filter(predicate: Callable[[TSource], bool]) -> Callable[[Iterable[TSource]], Iterable[TSource]]:
292+
def filter(predicate: Callable[[TSource], bool]) -> FilterFn:
294293
"""Filter sequence.
295294
296295
Filters the sequence to a new sequence containing only the
@@ -450,7 +449,7 @@ def _iter(source: Iterable[TSource]) -> None:
450449
return _iter
451450

452451

453-
def map(mapper: Callable[[TSource], TResult]) -> Callable[[Iterable[TSource]], Iterable[TResult]]:
452+
def map(mapper: Callable[[TSource], TResult]) -> TransformFn[TResult]:
454453
"""Map source sequence.
455454
456455
Builds a new collection whose elements are the results of
@@ -692,7 +691,10 @@ def _zip(source2: Iterable[TResult]) -> Iterable[Tuple[TSource, TResult]]:
692691
"of",
693692
"of_list",
694693
"of_iterable",
694+
"range",
695695
"scan",
696696
"singleton",
697+
"take",
697698
"unfold",
699+
"zip",
698700
]

expression/core/builder.py

+3
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,6 @@ def wrapper(*args: Any, **kw: Any) -> TOuter:
9292
return result
9393

9494
return wrapper
95+
96+
97+
__all__ = ["Builder"]

expression/core/choice.py

+12
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,15 @@ def __init__(self, value: C) -> None:
144144
def case(cls, case: Case[C]) -> Iterable[C]:
145145
"""Helper to cast the match result to correct type."""
146146
return case(cls)
147+
148+
149+
__all__ = [
150+
"Choice",
151+
"Choice2",
152+
"Choice3",
153+
"Choice1of2",
154+
"Choice2of2",
155+
"Choice1of3",
156+
"Choice2of3",
157+
"Choice3of3",
158+
]

expression/core/error.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ def __init__(self, expr: Any):
1818

1919

2020
def failwith(message: str) -> NoReturn:
21+
"""Raise exception with the given message string."""
2122
raise Exception(message)
2223

2324

24-
__all__ = ["EffectError", "failwith"]
25+
__all__ = ["EffectError", "failwith", "MatchFailureError"]

expression/core/option.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Iterator,
1515
List,
1616
Optional,
17+
Protocol,
1718
TypeVar,
1819
Union,
1920
cast,
@@ -317,6 +318,7 @@ def __iter__(self) -> Iterator[TSource]:
317318
We basically want to return nothing, but we have to return
318319
something to signal fail.
319320
"""
321+
320322
raise Nothing
321323
while False:
322324
yield
@@ -333,6 +335,16 @@ def __str__(self):
333335
return "Nothing"
334336

335337

338+
class TransformFn(Protocol[TResult]):
339+
"""Option transforming protocol function.
340+
341+
`Option[TSource]) -> Option[TResult]`
342+
"""
343+
344+
def __call__(self, __source: Option[TSource]) -> Option[TResult]:
345+
raise NotImplementedError
346+
347+
336348
# The singleton None class. We use the name 'Nothing' here instead of `None` to
337349
# avoid conflicts with the builtin `None` value in Python.
338350
# Note to self: Must be of type `Nothing_` or pattern matching will not work.
@@ -345,7 +357,7 @@ def __str__(self):
345357
"""
346358

347359

348-
def bind(mapper: Callable[[TSource], Option[TResult]]) -> Callable[[Option[TSource]], Option[TResult]]:
360+
def bind(mapper: Callable[[TSource], Option[TResult]]) -> TransformFn[TResult]:
349361
"""Bind option.
350362
351363
Applies and returns the result of the mapper if the value is
@@ -386,7 +398,7 @@ def is_some(option: Option[TSource]) -> bool:
386398
return option.is_some()
387399

388400

389-
def map(mapper: Callable[[TSource], TResult]) -> Callable[[Option[TSource]], Option[TResult]]:
401+
def map(mapper: Callable[[TSource], TResult]) -> TransformFn[TResult]:
390402
def _map(option: Option[TSource]) -> Option[TResult]:
391403
return option.map(mapper)
392404

expression/core/result.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -251,22 +251,20 @@ def __str__(self):
251251
return f"Error {self._error}"
252252

253253

254-
class TransformFn(Protocol[TSource, TResult]):
254+
class TransformFn(Protocol[TResult]):
255255
def __call__(self, __source: Result[TSource, TError]) -> Result[TResult, TError]:
256256
...
257257

258258

259-
def map(mapper: Callable[[TSource], TResult]) -> TransformFn[TSource, TResult]:
259+
def map(mapper: Callable[[TSource], TResult]) -> TransformFn[TResult]:
260260
def _map(result: Result[TSource, TError]) -> Result[TResult, TError]:
261261
return result.map(mapper)
262262

263263
# return cast(TransformFn[TSource, TResult], _map) # NOTE: cast for mypy
264264
return _map
265265

266266

267-
def bind(
268-
mapper: Callable[[TSource], Result[TResult, TError]]
269-
) -> Callable[[Result[TSource, TError]], Result[TResult, TError]]:
267+
def bind(mapper: Callable[[TSource], Result[TResult, TError]]) -> TransformFn[TResult]:
270268
def _bind(result: Result[TSource, TError]) -> Result[TResult, TError]:
271269
return result.bind(mapper)
272270

0 commit comments

Comments
 (0)