[pypy-issue] Issue #2551: struct.Struct has weird __new__ arguments (pypy/pypy)
Steven Noonan
issues-reply at bitbucket.org
Wed May 3 08:08:33 EDT 2017
New issue 2551: struct.Struct has weird __new__ arguments
https://bitbucket.org/pypy/pypy/issues/2551/structstruct-has-weird-__new__-arguments
Steven Noonan:
For some reason, CPython and PyPy differ here:
```
$ pypy -c "import struct; help(struct.Struct.__new__)"
Help on function __new__:
__new__(subtype, format)
$ python2 -c "import struct; help(struct.Struct.__new__)"
Help on built-in function __new__:
__new__(...)
T.__new__(S, ...) -> a new object with type S, a subtype of T
```
This difference breaks two Python modules I use (livestreamer and streamlink). Both of those modules have some common code which creates several classes that inherit from struct.Struct. The derived classes can't be constructed properly due to the `__new__` difference:
```
Traceback (most recent call last):
File "/opt/pypy/bin/streamlink", line 11, in <module>
load_entry_point('streamlink==0.5.0', 'console_scripts', 'streamlink')()
File "/opt/pypy/site-packages/pkg_resources/__init__.py", line 565, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/opt/pypy/site-packages/pkg_resources/__init__.py", line 2631, in load_entry_point
return ep.load()
File "/opt/pypy/site-packages/pkg_resources/__init__.py", line 2291, in load
return self.resolve()
File "/opt/pypy/site-packages/pkg_resources/__init__.py", line 2297, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
File "/opt/pypy/site-packages/streamlink_cli/main.py", line 17, in <module>
from streamlink.stream import StreamProcess
File "/opt/pypy/site-packages/streamlink/stream/__init__.py", line 4, in <module>
from streamlink.stream.akamaihd import AkamaiHDStream
File "/opt/pypy/site-packages/streamlink/stream/akamaihd.py", line 15, in <module>
from ..packages.flashmedia import FLV, FLVError
File "/opt/pypy/site-packages/streamlink/packages/flashmedia/__init__.py", line 4, in <module>
from .amf import *
File "/opt/pypy/site-packages/streamlink/packages/flashmedia/amf.py", line 3, in <module>
from .types import AMF0String, AMF0Value, U8, U16BE, U32BE
File "/opt/pypy/site-packages/streamlink/packages/flashmedia/types.py", line 298, in <module>
U24BE = HighLowCombo(">HB", 8, True)
TypeError: __new__() takes exactly 2 arguments (4 given)
```
The arguments for `__init__` are apparently being passed into `__new__` and `Struct.__new__` only accepts two arguments: the first is the class to create an instance of (as with all `__new__` functions) and the second is the format string.
Sometimes the derived classes take other kinds of arguments for `__init__` too (such as instances of other derived classes). So in order to get the livestreamer and streamlink modules to work, I came up with this hack:
```diff
diff --git a/src/streamlink/packages/flashmedia/types.py b/src/streamlink/packages/flashmedia/types.py
index cc4fcca..731bff1 100644
--- a/src/streamlink/packages/flashmedia/types.py
+++ b/src/streamlink/packages/flashmedia/types.py
@@ -30,6 +30,19 @@ AMF3_MAX_INTEGER = 268435455
class PrimitiveType(Struct):
+ def __new__(classtype, *args):
+ try:
+ return Struct.__new__(classtype, *args)
+ except:
+ pass
+
+ try:
+ return Struct.__new__(classtype, args[0])
+ except:
+ pass
+
+ return Struct.__new__(classtype, '')
+
def __call__(self, *args):
return self.pack(*args)
```
This change makes the modules *work properly*, but it feels like this may be a PyPy library bug.
So either:
* PyPy needs to make the Struct.__new__ function match CPython's
* or, the streamlink and livestreamer modules shouldn't have classes inheriting from Struct
Which makes more sense?
More information about the pypy-issue
mailing list