chainside / btcpy

A Python3 SegWit-compliant library which provides tools to handle Bitcoin data structures in a simple fashion.
https://www.chainside.net
GNU Lesser General Public License v3.0
270 stars 73 forks source link

Incompatibility with Python 3 versions lower than 3.5 #11

Closed ghost closed 6 years ago

ghost commented 6 years ago

It appears that the library is incompatible with Python versions lower than 3.5, despite claiming to be fully Python 3 compatible.

The issue stems from the following idiom mainly:

 m, *pubkeys, n = args

Unpacking rules were much stricter prior to Python 3.5 and did not allow this type of argument unpacking where a single argument follows star arguments.

In order for the library to be compatible with Python 3 versions lower than 3.5, it'd have to use the following idiom instead:

 m, n, *pubkeys = args

This appears to happen in quite a few places. Python 3.4 compatibility would be nice because that version of Python 3 often comes preinstalled with many systems.

Reference: https://www.python.org/dev/peps/pep-0448/

SimoneBronzini commented 6 years ago

Thanks for letting us know, this is gonna be fixed as soon as possible!

SimoneBronzini commented 6 years ago

I've been looking into this problem. Actually the a, *b, c = [1,2,3] works fine up to python3.0 (just tested on a 3.0 instance). The PEP you linked refers to other unpacking generalisations. As you can see here, the syntax you mention was introduced in python3.0.

ghost commented 6 years ago

Interesting. Here is my output when I try to run the test suite with Python 3.4.3.

(env) vedran@desktop:~/btcpy$ python -m unittest tests/unit.py 
Traceback (most recent call last):
  File "/usr/lib/python3.4/runpy.py", line 170, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.4/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3.4/unittest/__main__.py", line 18, in <module>
    main(module=None)
  File "/usr/lib/python3.4/unittest/main.py", line 92, in __init__
    self.parseArgs(argv)
  File "/usr/lib/python3.4/unittest/main.py", line 139, in parseArgs
    self.createTests()
  File "/usr/lib/python3.4/unittest/main.py", line 146, in createTests
    self.module)
  File "/usr/lib/python3.4/unittest/loader.py", line 146, in loadTestsFromNames
    suites = [self.loadTestsFromName(name, module) for name in names]
  File "/usr/lib/python3.4/unittest/loader.py", line 146, in <listcomp>
    suites = [self.loadTestsFromName(name, module) for name in names]
  File "/usr/lib/python3.4/unittest/loader.py", line 105, in loadTestsFromName
    module = __import__('.'.join(parts_copy))
  File "/home/vedran/btcpy/tests/unit.py", line 599
    script = MultisigScript(self.m, *self.pubkeys, self.n)
                                                         ^
SyntaxError: only named arguments may follow *expression
SimoneBronzini commented 6 years ago

Well, you are right indeed! The problem was not the m, *pubkeys, n = args at assignment time, it was when passing a *args to a function followed by other positional arguments instead of keyword arguments only. Fixing soon!

ghost commented 6 years ago

Ah. Sorry about that, it seems I may have misinterpreted the nature of the issue originally.