Skip to content

Commit

Permalink
ENH: improve base interface hinting w/circular ref
Browse files Browse the repository at this point in the history
  • Loading branch information
mplanchard committed Dec 9, 2019
1 parent 3a6827a commit 1780999
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 70 deletions.
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ disallow_untyped_defs = True
disallow_incomplete_defs = True
disallow_untyped_decorators = True
strict_optional = True
warn_unused_ignores = True
warn_redundant_casts = True
warn_return_any = True
warn_unused_ignores = True

[mypy-tests.*]
disallow_untyped_decorators = False
Expand Down
2 changes: 1 addition & 1 deletion src/safetywrap/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Typesafe python versions of Rust-inspired result types."""

__all__ = ("Option", "Result", "Ok", "Err", "Some", "Nothing")
__version__ = "1.0.0"
__version__ = "1.0.1"
__version_info__ = tuple(map(int, __version__.split(".")))


Expand Down
86 changes: 43 additions & 43 deletions src/safetywrap/_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,37 +103,37 @@ def __init__(self, result: T) -> None:
"""Wrap a result."""
self._value: T = result

def and_(self, res: "_Result[U, E]") -> "_Result[U, E]":
def and_(self, res: "Result[U, E]") -> "Result[U, E]":
"""Return `res` if the result is `Ok`, otherwise return `self`."""
return res

def or_(self, res: "_Result[T, F]") -> "_Result[T, F]":
def or_(self, res: "Result[T, F]") -> "Result[T, F]":
"""Return `res` if the result is `Err`, otherwise `self`."""
return t.cast(Result[T, F], self)

def and_then(self, fn: t.Callable[[T], "_Result[U, E]"]) -> "_Result[U, E]":
def and_then(self, fn: t.Callable[[T], "Result[U, E]"]) -> "Result[U, E]":
"""Call `fn` if Ok, or ignore an error.
This can be used to chain functions that return results.
"""
return fn(self._value)

def flatmap(self, fn: t.Callable[[T], "_Result[U, E]"]) -> "_Result[U, E]":
def flatmap(self, fn: t.Callable[[T], "Result[U, E]"]) -> "Result[U, E]":
"""Call `fn` if Ok, or ignore an error.
This can be used to chain functions that return results.
"""
return self.and_then(fn)

def or_else(self, fn: t.Callable[[E], "_Result[T, F]"]) -> "_Result[T, F]":
def or_else(self, fn: t.Callable[[E], "Result[T, F]"]) -> "Result[T, F]":
"""Return `self` if `Ok`, or call `fn` with `self` if `Err`."""
return t.cast(Result[T, F], self)

def err(self) -> _Option[E]:
def err(self) -> Option[E]:
"""Return Err value if result is Err."""
return Nothing()

def ok(self) -> _Option[T]:
def ok(self) -> Option[T]:
"""Return OK value if result is Ok."""
return Some(self._value)

Expand Down Expand Up @@ -170,11 +170,11 @@ def iter(self) -> t.Iterator[T]:
"""
return iter(self)

def map(self, fn: t.Callable[[T], U]) -> "_Result[U, E]":
def map(self, fn: t.Callable[[T], U]) -> "Result[U, E]":
"""Map a function onto an okay result, or ignore an error."""
return Ok(fn(self._value))

def map_err(self, fn: t.Callable[[E], F]) -> "_Result[T, F]":
def map_err(self, fn: t.Callable[[E], F]) -> "Result[T, F]":
"""Map a function onto an error, or ignore a success."""
return t.cast(Result[T, F], self)

Expand Down Expand Up @@ -232,37 +232,37 @@ def __init__(self, result: E) -> None:
"""Wrap a result."""
self._value = result

def and_(self, res: "_Result[U, E]") -> "_Result[U, E]":
def and_(self, res: "Result[U, E]") -> "Result[U, E]":
"""Return `res` if the result is `Ok`, otherwise return `self`."""
return t.cast(Result[U, E], self)

def or_(self, res: "_Result[T, F]") -> "_Result[T, F]":
def or_(self, res: "Result[T, F]") -> "Result[T, F]":
"""Return `res` if the result is `Err`, otherwise `self`."""
return res

def and_then(self, fn: t.Callable[[T], "_Result[U, E]"]) -> "_Result[U, E]":
def and_then(self, fn: t.Callable[[T], "Result[U, E]"]) -> "Result[U, E]":
"""Call `fn` if Ok, or ignore an error.
This can be used to chain functions that return results.
"""
return t.cast(Result[U, E], self)

def flatmap(self, fn: t.Callable[[T], "_Result[U, E]"]) -> "_Result[U, E]":
def flatmap(self, fn: t.Callable[[T], "Result[U, E]"]) -> "Result[U, E]":
"""Call `fn` if Ok, or ignore an error.
This can be used to chain functions that return results.
"""
return self.and_then(fn)
return t.cast(Result[U, E], self.and_then(fn))

def or_else(self, fn: t.Callable[[E], "_Result[T, F]"]) -> "_Result[T, F]":
def or_else(self, fn: t.Callable[[E], "Result[T, F]"]) -> "Result[T, F]":
"""Return `self` if `Ok`, or call `fn` with `self` if `Err`."""
return fn(self._value)

def err(self) -> _Option[E]:
def err(self) -> Option[E]:
"""Return Err value if result is Err."""
return Some(self._value)

def ok(self) -> _Option[T]:
def ok(self) -> Option[T]:
"""Return OK value if result is Ok."""
return Nothing()

Expand Down Expand Up @@ -299,11 +299,11 @@ def iter(self) -> t.Iterator[T]:
"""
return iter(self)

def map(self, fn: t.Callable[[T], U]) -> "_Result[U, E]":
def map(self, fn: t.Callable[[T], U]) -> "Result[U, E]":
"""Map a function onto an okay result, or ignore an error."""
return t.cast(Result[U, E], self)

def map_err(self, fn: t.Callable[[E], F]) -> "_Result[T, F]":
def map_err(self, fn: t.Callable[[E], F]) -> "Result[T, F]":
"""Map a function onto an error, or ignore a success."""
return Err(fn(self._value))

Expand Down Expand Up @@ -363,29 +363,29 @@ def __init__(self, value: T) -> None:
# not sure why pylint things _value is not in __slots__
self._value = value # pylint: disable=assigning-non-slot

def and_(self, alternative: _Option[U]) -> _Option[U]:
def and_(self, alternative: Option[U]) -> Option[U]:
"""Return `Nothing` if `self` is `Nothing`, or the `alternative`."""
return alternative

def or_(self, alternative: _Option[T]) -> _Option[T]:
def or_(self, alternative: Option[T]) -> Option[T]:
"""Return option if it is `Some`, or the `alternative`."""
return self

def xor(self, alternative: _Option[T]) -> _Option[T]:
def xor(self, alternative: Option[T]) -> Option[T]:
"""Return Some IFF exactly one of `self`, `alternative` is `Some`."""
return (
t.cast(_Option[T], self) if alternative.is_nothing() else Nothing()
t.cast(Option[T], self) if alternative.is_nothing() else Nothing()
)

def and_then(self, fn: t.Callable[[T], _Option[U]]) -> _Option[U]:
def and_then(self, fn: t.Callable[[T], Option[U]]) -> Option[U]:
"""Return `Nothing`, or call `fn` with the `Some` value."""
return fn(self._value)

def flatmap(self, fn: t.Callable[[T], "_Option[U]"]) -> "_Option[U]":
def flatmap(self, fn: t.Callable[[T], Option[U]]) -> Option[U]:
"""Return `Nothing`, or call `fn` with the `Some` value."""
return self.and_then(fn)
return t.cast(Option[U], self.and_then(fn))

def or_else(self, fn: t.Callable[[], _Option[T]]) -> _Option[T]:
def or_else(self, fn: t.Callable[[], Option[T]]) -> Option[T]:
"""Return option if it is `Some`, or calculate an alternative."""
return self

Expand All @@ -397,7 +397,7 @@ def expect(self, msg: str, exc_cls: t.Type[Exception] = RuntimeError) -> T:
"""
return self._value

def filter(self, predicate: t.Callable[[T], bool]) -> _Option[T]:
def filter(self, predicate: t.Callable[[T], bool]) -> Option[T]:
"""Return `Nothing`, or an option determined by the predicate.
If `self` is `Some`, call `predicate` with the wrapped value and
Expand All @@ -423,7 +423,7 @@ def iter(self) -> t.Iterator[T]:
"""Return an iterator over the possibly contained value."""
return iter(self)

def map(self, fn: t.Callable[[T], U]) -> _Option[U]:
def map(self, fn: t.Callable[[T], U]) -> Option[U]:
"""Apply `fn` to the contained value if any."""
return Some(fn(self._value))

Expand All @@ -442,15 +442,15 @@ def ok_or(self, err: E) -> Result[T, E]:
Maps `Some(v)` to `Ok(v)` or `None` to `Err(err)`.
"""
res: Result[T, E] = Ok(t.cast(T, self._value))
res: Result[T, E] = Ok(self._value)
return res

def ok_or_else(self, err_fn: t.Callable[[], E]) -> Result[T, E]:
"""Transform an option into a `Result`.
Maps `Some(v)` to `Ok(v)` or `None` to `Err(err_fn())`.
"""
res: Result[T, E] = Ok(t.cast(T, self._value))
res: Result[T, E] = Ok(self._value)
return res

def unwrap(self) -> T:
Expand Down Expand Up @@ -515,27 +515,27 @@ def __new__(cls, _: None = None) -> "Nothing[T]":
cls._instance = inst
return t.cast("Nothing[T]", cls._instance)

def and_(self, alternative: _Option[U]) -> _Option[U]:
def and_(self, alternative: Option[U]) -> Option[U]:
"""Return `Nothing` if `self` is `Nothing`, or the `alternative`."""
return t.cast(_Option[U], self)
return t.cast(Option[U], self)

def or_(self, alternative: _Option[T]) -> _Option[T]:
def or_(self, alternative: Option[T]) -> Option[T]:
"""Return option if it is `Some`, or the `alternative`."""
return alternative

def xor(self, alternative: _Option[T]) -> _Option[T]:
def xor(self, alternative: Option[T]) -> Option[T]:
"""Return Some IFF exactly one of `self`, `alternative` is `Some`."""
return alternative if alternative.is_some() else self

def and_then(self, fn: t.Callable[[T], _Option[U]]) -> _Option[U]:
def and_then(self, fn: t.Callable[[T], Option[U]]) -> Option[U]:
"""Return `Nothing`, or call `fn` with the `Some` value."""
return t.cast(_Option[U], self)
return t.cast(Option[U], self)

def flatmap(self, fn: t.Callable[[T], "_Option[U]"]) -> "_Option[U]":
def flatmap(self, fn: t.Callable[[T], Option[U]]) -> Option[U]:
"""Return `Nothing`, or call `fn` with the `Some` value."""
return self.and_then(fn)
return t.cast(Option[U], self.and_then(fn))

def or_else(self, fn: t.Callable[[], _Option[T]]) -> _Option[T]:
def or_else(self, fn: t.Callable[[], Option[T]]) -> Option[T]:
"""Return option if it is `Some`, or calculate an alternative."""
return fn()

Expand All @@ -547,7 +547,7 @@ def expect(self, msg: str, exc_cls: t.Type[Exception] = RuntimeError) -> T:
"""
raise exc_cls(msg)

def filter(self, predicate: t.Callable[[T], bool]) -> _Option[T]:
def filter(self, predicate: t.Callable[[T], bool]) -> Option[T]:
"""Return `Nothing`, or an option determined by the predicate.
If `self` is `Some`, call `predicate` with the wrapped value and
Expand All @@ -571,9 +571,9 @@ def iter(self) -> t.Iterator[T]:
"""Return an iterator over the possibly contained value."""
return iter(self)

def map(self, fn: t.Callable[[T], U]) -> _Option[U]:
def map(self, fn: t.Callable[[T], U]) -> Option[U]:
"""Apply `fn` to the contained value if any."""
return t.cast(_Option[U], self)
return t.cast(Option[U], self)

def map_or(self, default: U, fn: t.Callable[[T], U]) -> U:
"""Apply `fn` to contained value, or return the default."""
Expand Down

0 comments on commit 1780999

Please sign in to comment.