Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Incorrect pickling behavior in the c implemented classmethod descriptors #95196

Copy link
Copy link
Closed
@UltimateLobster

Description

@UltimateLobster
Issue body actions

Bug report

Hello there, this is my first bug report so apologies if there's something I miss.

Consider the following code:

import pickle

classmethod_descriptor = dict.__dict__["fromkeys"]
unpickled_classmethod_descriptor = pickle.loads(pickle.dumps(classmethod_descriptor, protocol=5))

While it passes without raising any errors, classmethod_descriptor differs from unpickled_classmethod_descriptor. Instead of the original descriptor, the pickling process yields the function itself:

>>> classmethod_descriptor
<method 'fromkeys' of 'dict' objects>

>>> unpickled_classmethod_descriptor
<function dict.fromkeys(iterable, value=None, /)>

Manually calling the descriptor's __reduce_ex__ allows us to see the reason:

>>> classmethod_descriptor.__reduce_ex__(5)
(<function getattr>, (dict, 'fromkeys'))

This behavior differs from python implemented classmethods:

import pickle

class A:
    @classmethod
    def method(cls):
        pass

classmethod_descriptor = A.__dict__["method"]

# Any of these lines will raise "TypeError: cannot pickle 'classmethod' object"
pickle.dumps(classmethod_descriptor, protocol=5)
classmethod_descriptor.__reduce_ex__(5)

Since it fails with normal classmethods, I would expect it to fail with their c counterparts as well so their behavior would match.
Either that, or having both of them succeed during the pickling process, in which case, __reduce_ex__ should return a valid result in both cases.

The bug occurs with other c implemented class methods as well:

import pickle

from datetime import datetime

classmethod_descriptor = datetime.__dict__["now"]

# Returns False
pickle.loads(pickle.dumps(classmethod_descriptor, 5)) == classmethod_descriptor

# Returns True
pickle.loads(pickle.dumps(classmethod_descriptor, 5)) == datetime.now

Your environment

Python Versions:
I've tested it with both 3.10.5 and 3.11.04b
OS - Windows 10 Pro 64 bit

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    Status

    Done
    Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.