Skip to content

Commit

Permalink
Add Option casting with tests; modify Variable parameters to use it.
Browse files Browse the repository at this point in the history
  • Loading branch information
ashuping committed Sep 25, 2024
1 parent f23c8b6 commit 85a1b13
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
10 changes: 5 additions & 5 deletions modules/data/Variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ class BoundVariable[A](Variable):
'''
def __init__(self, name: str, val: A, var_type: Option[type] = Nothing(), desc: Option[str] = Nothing(), default: Option[A] = Nothing()):
self.__name = name
self.__val = val
self.__desc = desc
self.__default = default
self.__val = Option.make_from(val)
self.__desc = Option.make_from(desc)
self.__default = Option.make_from(default)

if var_type == Nothing():
if default == Nothing():
Expand Down Expand Up @@ -185,8 +185,8 @@ class UnboundVariable[A](Variable):
'''
def __init__(self, name: str, var_type: Option[type] = Nothing(), desc: Option[str] = Nothing(), default: Option[A] = Nothing()):
self.__name = name
self.__desc = desc
self.__default = default
self.__desc = Option.make_from(desc)
self.__default = Option.make_from(default)

if var_type == Nothing():
if default != Nothing():
Expand Down
28 changes: 27 additions & 1 deletion modules/types/Option.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ def flat_map(self, f: Callable[[A], 'Option[B]']) -> 'Option[B]':
'''
... # pragma: no cover

@staticmethod
def make_from(obj: any) -> 'Option[A]':
''' Convenience method to ensure an object is an Option. If `obj` is
already an Option, it is returned as-is. If `obj` is None, it is
converted to `Nothing()`. Otherwise, it is converted to `Some(obj)`
:param obj: The object to encapsulate
:returns: `obj` if `obj` is an Option; otherwise, `Some(obj)` if obj
is not None; otherwise, `Nothing()`.
'''
... # pragma: no cover

def __eq__(self, other):
if not issubclass(type(other), Option):
return False
Expand Down Expand Up @@ -123,4 +135,18 @@ def flat_map(self, f: Callable[[A], Option[B]]) -> Option[B]:
return f(self.__val)

def __str__(self):
return f'Some[{self.val.__class__.__name__}]({self.val})'
return f'Some[{self.val.__class__.__name__}]({self.val})'


def _make_from(obj: any) -> Option[A]:
# The inner function has to be defined after `Some` and `Nothing`, and then
# injected into the Object class.
if issubclass(type(obj), Option):
return obj

if obj is None:
return Nothing()

return Some(obj)

Option.make_from = _make_from
8 changes: 8 additions & 0 deletions test/types/test_Option.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,11 @@ def tf_stringify(x: float) -> str:
.flat_map(tf_invert) \
.map(tf_stringify) == Nothing(), \
"`map` should be skipped, since `tf_invert` returns Nothing()."

def test_make_from():
assert Option.make_from(1) == Some(1)
assert Option.make_from(Some(1)) == Some(1)

assert Option.make_from(Nothing()) == Nothing()
assert Option.make_from(None) == Nothing()
assert Option.make_from(Some(None)) == Some(None)

0 comments on commit 85a1b13

Please sign in to comment.