From f45c311001162a46112e247ab6b51051bc978f80 Mon Sep 17 00:00:00 2001 From: Charles Stephens Date: Wed, 1 Nov 2023 16:51:18 -0600 Subject: [PATCH] Fix str() bug for tuple values Replaced the use of old-style formatting strings in __str__ methods. At first, that seems like a dated but harmless practice, but unfortunately While dated and seemingly a harmless practice, OSlash actually uses it in an incorrect way. If a program using OSlash deals with types other than strings, then the __str__ methods for classes like `Left`, `Right`, and `Either`, OSlash directly writes: return '%s' % value where `value` is an arbitrary type. Unfortunately, '%s' % value is only guaranteed to work if the value is a string, since Python will not call `str()` on it. (Well, more precisely, `'%s' % value` is guaranteed to *fail* if the value happens to be a tuple of a certain kind, since Python will try to unpack the tuple into the string formatting operation) The upshot is that such programs will get TypeErrors. Instead, use Python 3.8+ f-strings to guarantee that the value is converted to a string. --- oslash/either.py | 4 ++-- oslash/identity.py | 2 +- oslash/maybe.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/oslash/either.py b/oslash/either.py index 47b5448..533639a 100644 --- a/oslash/either.py +++ b/oslash/either.py @@ -98,7 +98,7 @@ def __eq__(self, other) -> bool: return isinstance(other, Right) and self._value == other._value def __str__(self) -> str: - return "Right %s" % self._value + return f"Right {self._value}" class Left(Either[TSource, TError]): @@ -129,7 +129,7 @@ def __eq__(self, other) -> bool: return isinstance(other, Left) and self._error == other._error def __str__(self) -> str: - return "Left: %s" % self._error + return f"Left: {self._error}" assert(isinstance(Either, Functor)) diff --git a/oslash/identity.py b/oslash/identity.py index 33dfde5..4248b2d 100644 --- a/oslash/identity.py +++ b/oslash/identity.py @@ -52,7 +52,7 @@ def __eq__(self, other) -> bool: return self._value == other() def __str__(self) -> str: - return "Identity(%s)" % self._value + return f"Identity({self._value})" def __repr__(self) -> str: return str(self) diff --git a/oslash/maybe.py b/oslash/maybe.py index dbb65c9..a2f1158 100644 --- a/oslash/maybe.py +++ b/oslash/maybe.py @@ -166,7 +166,7 @@ def __eq__(self, other) -> bool: return bool(other.map(lambda other_value: other_value == self._value)) def __str__(self) -> str: - return "Just %s" % self._value + return f"Just {self._value}" def __repr__(self) -> str: return str(self)