Skip to content

Commit b6f2fea

Browse files
Use TYPE_CHECKING guard to avoid circular imports between result and option
1 parent b39dd23 commit b6f2fea

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

expression/core/option.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
from .curry import curry_flip
1616
from .error import EffectError
1717
from .pipe import PipeMixin
18-
from .result import Error, Ok, Result
1918
from .typing import GenericValidator, ModelField, SupportsValidation
2019

2120

2221
if TYPE_CHECKING:
2322
from expression.collections.seq import Seq
23+
from expression.core.result import Result
2424

2525
_TSource = TypeVar("_TSource")
2626
_TResult = TypeVar("_TResult")
@@ -158,7 +158,7 @@ def of_result(cls, result: Result[_TSource, _TError]) -> Option[_TSource]:
158158
return of_result(result)
159159

160160
@abstractmethod
161-
def to_optional(self) -> Optional[_TSource]:
161+
def to_optional(self) -> _TSource | None:
162162
"""Convert option to an optional."""
163163
raise NotImplementedError
164164

@@ -293,16 +293,20 @@ def to_seq(self) -> Seq[_TSource]:
293293

294294
return Seq.of(self._value)
295295

296-
def to_optional(self) -> Optional[_TSource]:
296+
def to_optional(self) -> _TSource | None:
297297
"""Convert option to an optional."""
298298
return self._value
299299

300300
def to_result(self, error: _TError) -> Result[_TSource, _TError]:
301301
"""Convert option to a result."""
302+
from expression.core.result import Ok
303+
302304
return Ok(self._value)
303305

304306
def to_result_with(self, error: Callable[[], _TError]) -> Result[_TSource, _TError]:
305307
"""Convert option to a result."""
308+
from expression.core.result import Ok
309+
306310
return Ok(self._value)
307311

308312
def dict(self) -> _TSource:
@@ -419,16 +423,20 @@ def to_seq(self) -> Seq[_TSource]:
419423

420424
return Seq()
421425

422-
def to_optional(self) -> Optional[_TSource]:
426+
def to_optional(self) -> _TSource | None:
423427
"""Convert option to an optional."""
424428
return None
425429

426430
def to_result(self, error: _TError) -> Result[_TSource, _TError]:
427431
"""Convert option to a result."""
432+
from expression.core.result import Error
433+
428434
return Error(error)
429435

430436
def to_result_with(self, error: Callable[[], _TError]) -> Result[_TSource, _TError]:
431437
"""Convert option to a result."""
438+
from expression.core.result import Error
439+
432440
return Error(error())
433441

434442
def dict(self) -> builtins.dict[str, Any]:
@@ -564,7 +572,7 @@ def to_seq(option: Option[_TSource]) -> Seq[_TSource]:
564572
return option.to_seq()
565573

566574

567-
def to_optional(value: Option[_TSource]) -> Optional[_TSource]:
575+
def to_optional(value: Option[_TSource]) -> _TSource | None:
568576
"""Convert an option value to an optional.
569577
570578
Args:
@@ -606,6 +614,8 @@ def of_obj(value: Any) -> Option[Any]:
606614

607615

608616
def of_result(result: Result[_TSource, _TError]) -> Option[_TSource]:
617+
from expression.core.result import Ok
618+
609619
match result:
610620
case Ok(value):
611621
return Some(value)

expression/core/result.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from abc import ABC, abstractmethod
1515
from collections.abc import Callable, Generator, Iterable, Iterator
1616
from typing import (
17+
TYPE_CHECKING,
1718
Any,
1819
ClassVar,
1920
Generic,
@@ -24,7 +25,10 @@
2425
get_origin,
2526
)
2627

27-
from . import option
28+
29+
if TYPE_CHECKING:
30+
from expression.core.option import Option
31+
2832
from .curry import curry_flip
2933
from .error import EffectError
3034
from .pipe import PipeMixin
@@ -139,24 +143,24 @@ def dict(self) -> builtins.dict[str, _TSource | _TError]:
139143

140144
@abstractmethod
141145
def swap(self) -> Result[_TError, _TResult]:
142-
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok"""
146+
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok."""
143147
raise NotImplementedError
144148

145149
@abstractmethod
146-
def to_option(self) -> option.Option[_TSource]:
150+
def to_option(self) -> Option[_TSource]:
147151
"""Convert result to an option."""
148152
raise NotImplementedError
149153

150154
@classmethod
151155
def of_option(
152-
cls, value: option.Option[_TSource], error: _TError
156+
cls, value: Option[_TSource], error: _TError
153157
) -> Result[_TSource, _TError]:
154158
"""Convert option to a result."""
155159
return of_option(value, error)
156160

157161
@classmethod
158162
def of_option_with(
159-
cls, value: option.Option[_TSource], error: Callable[[], _TError]
163+
cls, value: Option[_TSource], error: Callable[[], _TError]
160164
) -> Result[_TSource, _TError]:
161165
"""Convert option to a result."""
162166
return of_option_with(value, error)
@@ -254,12 +258,14 @@ def dict(self) -> builtins.dict[str, _TSource | _TError]:
254258
return {"ok": value}
255259

256260
def swap(self) -> Result[_TError, _TSource]:
257-
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok"""
261+
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok."""
258262
return Error(self._value)
259263

260-
def to_option(self) -> option.Option[_TSource]:
264+
def to_option(self) -> Option[_TSource]:
261265
"""Convert result to an option."""
262-
return option.Some(self._value)
266+
from expression.core.option import Some
267+
268+
return Some(self._value)
263269

264270
def __match__(self, pattern: Any) -> Iterable[_TSource]:
265271
if self is pattern or self == pattern:
@@ -376,12 +382,14 @@ def dict(self) -> builtins.dict[str, Any]:
376382
return {"error": error}
377383

378384
def swap(self) -> Result[_TError, _TSource]:
379-
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok"""
385+
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok."""
380386
return Ok(self._error)
381387

382-
def to_option(self) -> option.Option[_TSource]:
388+
def to_option(self) -> Option[_TSource]:
383389
"""Convert result to an option."""
384-
return option.Nothing
390+
from expression.core.option import Nothing
391+
392+
return Nothing
385393

386394
def __eq__(self, o: Any) -> bool:
387395
if isinstance(o, Error):
@@ -471,26 +479,26 @@ def is_error(result: Result[_TSource, _TError]) -> TypeGuard[Error[_TSource, _TE
471479

472480

473481
def swap(result: Result[_TSource, _TError]) -> Result[_TError, _TSource]:
474-
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok"""
482+
"""Swaps the value in the result so an Ok becomes an Error and an Error becomes an Ok."""
475483
return result.swap()
476484

477485

478-
def to_option(result: Result[_TSource, _TError]) -> option.Option[_TSource]:
486+
def to_option(result: Result[_TSource, _TError]) -> Option[_TSource]:
487+
from expression.core.option import Nothing, Some
488+
479489
match result:
480490
case Ok(value):
481-
return option.Some(value)
491+
return Some(value)
482492
case _:
483-
return option.Nothing
493+
return Nothing
484494

485495

486-
def of_option(
487-
value: option.Option[_TSource], error: _TError
488-
) -> Result[_TSource, _TError]:
496+
def of_option(value: Option[_TSource], error: _TError) -> Result[_TSource, _TError]:
489497
return value.to_result(error)
490498

491499

492500
def of_option_with(
493-
value: option.Option[_TSource], error: Callable[[], _TError]
501+
value: Option[_TSource], error: Callable[[], _TError]
494502
) -> Result[_TSource, _TError]:
495503
return value.to_result_with(error)
496504

0 commit comments

Comments
 (0)