LazyString.encode fails with <LazyString broken>
bdnettleton opened this issue · comments
The following code snippet raises a TypeError: 'bytes' object is not callable
from lazy_string import LazyString
def get_abc():
return "abc"
s = LazyString(get_abc)
print(s.encode('UTF-8'))
Here is the traceback from running this
Traceback (most recent call last):
File "testls.py", line 8, in <module>
print(s.encode('UTF-8'))
File "/usr/local/Cellar/python@3.7/3.7.11/Frameworks/Python.framework/Versions/3.7/lib/python3.7/collections/__init__.py", line 1163, in __str__
def __str__(self): return str(self.data)
File "/Users/brian/.virtualenvs/nips3/lib/python3.7/site-packages/lazy_string.py", line 56, in data
return self._func(*self._args, **self._kwargs)
TypeError: 'bytes' object is not callable
Here is a patch to fix this problem. If you give me permission to the repo, I'll try to create a pull request.
Index: lazy_string.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lazy_string.py b/lazy_string.py
--- a/lazy_string.py (revision c35803cd389e862a5f1c8671b49aff18cf7b75e5)
+++ b/lazy_string.py (date 1633030832060)
@@ -36,12 +36,13 @@
__slots__ = ("_func", "_args", )
def __new__(cls, func: Union[Callable, str], *args: Tuple, **kwargs: Mapping) -> object:
- if isinstance(func, str):
+ if isinstance(func, str) or isinstance(func, bytes):
# Many UserString's functions like `lower`, `__add__` and so on wrap
# returned values with a call to `self.__class__(...)` to ensure the
# result is of the same type as the original class.
# However, as the result of all of such methods is always a string,
# there's no need to create a new instance of a `LazyString`
+ # Same goes for function `encode` which returns a bytes object
return func
return object.__new__(cls)
I agree that there is a bug, though I don't see how the sample code hits it.
I also don't agree that the suggestion is the correct remediation.
I would propose that we check whether func
is Callable
and if it is not, then do something. We can still check if it is str
(or UserString
) and return them untouched, but if func
is none of these three types, then we should probably convert func
to a str
and return that value.
I don't recall the details and I'm not longer able to reproduce the issue. My fuzzy memory was that it seemed like something was trying to return the data somewhere as a new LazyString but that doesn't appear to be the case so my memory must be suspect.
Since I can't reproduce this I'm fine if you would like to close it. Apologies for taking your time.
Ah! I found what changed that fixes the problem. Python 3.7 attempts to return the result of UserString.encode as a LazyString, but this looks to be changed in Python 3.8! Since it's fixed in 3.8 and later I definitely think this can be closed.
Python 3.7 code: https://github.com/python/cpython/blob/dfc5e451b59e578b4e5eaddc34d4766271cb09dd/Lib/collections/__init__.py#L1232
Python 3.8 code:
https://github.com/python/cpython/blob/f78733b332966cef7d0c61165389549f4ffe0727/Lib/collections/__init__.py#L1213
Sincerely thank you for your efforts and sorry for not replying for a while! Closing the issue.