classification
Title: copy breaks staticmethod
Type: behavior Stage:
Components: Interpreter Core, Library (Lib) Versions: Python 3.5, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: alexandre.vassalotti, barry, dangyogi, serhiy.storchaka
Priority: normal Keywords:

Created on 2017-03-25 13:16 by dangyogi, last changed 2017-04-16 16:42 by serhiy.storchaka.

Pull Requests
URL Status Linked Edit
PR 925 open serhiy.storchaka, 2017-03-31 10:26
Messages (6)
msg290481 - (view) Author: Bruce Frederiksen (dangyogi) Date: 2017-03-25 13:16
Doing a copy on a staticmethod breaks it:

Python 3.5.2 (default, Nov 17 2016, 17:05:23) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from copy import copy
>>> def foo(): pass
... 
>>> class bar: pass
... 
>>> bar.x = staticmethod(foo)
>>> bar.x.__name__
'foo'
>>> bar.y = copy(staticmethod(foo))
>>> bar.y.__name__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: uninitialized staticmethod object
msg290484 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-03-25 14:02
Copying and pickling of staticmethod objects are not supported. Starting from 3.6 this raises an exception (see issue22995).

>>> bar.y = copy(staticmethod(foo))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython3.6/Lib/copy.py", line 96, in copy
    rv = reductor(4)
TypeError: can't pickle staticmethod objects
msg290905 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-03-31 10:31
This issue was fixed by issue22995 in 3.6. But for some reasons the general solution was not applied to 3.5 and 2.7. Proposed patch makes staticmethod, classmethod and property descriptors explicitly non-pickleable (as was made explicitly non-pickleable file-like object) in 3.5. Only tests will be foreported to 3.6 and 3.7.
msg291739 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-16 06:34
What are your thoughts Barry? staticmethod, classmethod and property objects are incorrectly pickled in 2.7 and 3.5 (they are not pickleable in 3.6+). Making them not pickleable in 2.7 and 3.5 can help to catch programming errors.

But this can break the code that "just works" (actually works incorrectly) if it pickles or deepcopies complex objects containing staticmethod, classmethod or property objects, but never use it. Similar situation happened in issue22995 with Cython objects.

Maybe emitting a warning rather than an exception would be safer? But deprecation warnings are ignored by default.
msg291748 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2017-04-16 15:12
I'd be very hesitant to add anything to 2.7 that changes (even broken) behavior here.  It might make more sense to backport the more strict checks to 3.5.  OTOH, we can save people from all programming errors, and if warnings are basically ignored (plus, adding warnings *can* break things), then perhaps we should only document the limitations.

There's already some description of copy()'s limitations, so either add another warning there, or in the static method objects description in section 3.2
msg291752 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-16 16:42
If add just warnings we are free to add any warnings in 2.7 in Py3k compatible mode (option -3).
History
Date User Action Args
2017-04-16 16:42:32serhiy.storchakasetmessages: + msg291752
2017-04-16 15:12:48barrysetmessages: + msg291748
2017-04-16 06:34:24serhiy.storchakasetmessages: + msg291739
2017-03-31 10:31:09serhiy.storchakasetmessages: + msg290905
2017-03-31 10:26:04serhiy.storchakasetpull_requests: + pull_request822
2017-03-25 14:02:29serhiy.storchakasetversions: + Python 2.7
nosy: + barry, alexandre.vassalotti, serhiy.storchaka

messages: + msg290484

components: + Interpreter Core
2017-03-25 13:16:44dangyogicreate