incorrect results for copy.copy() of various Stackless picklable types #127

Description
Originally reported by: Anselm Kruis (Bitbucket: akruis, GitHub: akruis)
Affected versions: all
Problem
Stackless can pickle a few more types than C-Python. A pickleable object can also be copied by copy.copy(). Therefore copy.copy() should work for all Stackless-pickleable types. Unfortunately if you copy a callable-iterator, you get a copy of type '_stackless._wrap.callable-iterator'
For Stackless 2.7.13 this problem is caused by a bug in prickelpit.c calliter_reduce(). The reduce function returns only a 2-tuple without a state value. Without a state, Python does not call __setstate__() on the newly created object. But Stackless changes the object type of the newly created object in __setstate__(). The fix is simple: return an empty state.
But in some versions of Python 3.x (see bpo-25718) copy.copy() contains am incorrect optimization: If copy.copy() uses a reduce-method (either from copy_reg.dispatch_table or obj.__reduce__() or obj.__reduce_ex__()), it does not call newobj.__setstate__(state), if the boolean value of state is false.
This can break Stackless, because it depends on __setstate__() being called.
Additionally I found, that bug in the pickle tests of Stackless Python 3.x. The pickles protocol value isn't passed the the pickler. Therefore it always uses the default protocol.
Solution
- I'll add a test class with a copy.copy() test case for each Stackless-picklable type.
- I'll fix the callable-iterator bug.
- In Python 3, I'll eventually add a dummy item to the state. Probably a single None value will be enough.
- I'll fix the protocol value issue.