Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python_version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14-dev", "pypy-3.9"]
python_version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "pypy-3.9"]
exclude:
# Do not test all minor versions on all platforms, especially if they
# are not the oldest/newest supported versions
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 23.9.1
rev: 25.9.0
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
rev: v0.14.3
hooks:
- id: ruff
args: ["--fix", "--show-source"]
args: ["--fix", "--show-files"]
2 changes: 1 addition & 1 deletion cloudpickle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

__doc__ = cloudpickle.__doc__

__version__ = "3.1.2"
__version__ = "3.2.0.dev0"

__all__ = [ # noqa
"__version__",
Expand Down
6 changes: 4 additions & 2 deletions cloudpickle/cloudpickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
# cloudpickle. See: tests/test_backward_compat.py
from types import CellType # noqa: F401


# cloudpickle is meant for inter process communication: we expect all
# communicating processes to run the same Python version hence we favor
# communication speed over compatibility:
Expand Down Expand Up @@ -193,9 +192,12 @@ def _is_registered_pickle_by_value(module):


if sys.version_info >= (3, 14):

def _getattribute(obj, name):
return _pickle_getattribute(obj, name.split('.'))
return _pickle_getattribute(obj, name.split("."))

else:

def _getattribute(obj, name):
return _pickle_getattribute(obj, name)[0]

Expand Down
1 change: 0 additions & 1 deletion dev/make-distribution.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ rm -rf cloudpickle.egg-info
python setup.py sdist
python setup.py bdist_wheel --universal
twine upload dist/*

53 changes: 37 additions & 16 deletions tests/cloudpickle_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
from .testutils import assert_run_python_script
from .testutils import check_deterministic_pickle


_TEST_GLOBAL_VARIABLE = "default_value"
_TEST_GLOBAL_VARIABLE2 = "another_value"

Expand Down Expand Up @@ -354,7 +353,6 @@ class A:
assert hasattr(A_roundtrip, "__firstlineno__")
assert A_roundtrip.__firstlineno__ == A.__firstlineno__


def test_dynamically_generated_class_that_uses_super(self):
class Base:
def method(self):
Expand Down Expand Up @@ -1067,7 +1065,9 @@ def test_extended_arg(self):
def f():
x = {tup}
return zlib.crc32(bytes(bytearray(x)))
""".format(tup=", ".join(names))
""".format(
tup=", ".join(names)
)
exec(textwrap.dedent(code), d, d)
f = d["f"]
res = f()
Expand Down Expand Up @@ -1206,7 +1206,9 @@ def check_logger(self, name):
logging.basicConfig(level=logging.INFO)
logger = cloudpickle.loads(base64.b32decode(b'{}'))
logger.info('hello')
""".format(base64.b32encode(dumped).decode("ascii"))
""".format(
base64.b32encode(dumped).decode("ascii")
)
proc = subprocess.Popen(
[sys.executable, "-W ignore", "-c", code],
stdout=subprocess.PIPE,
Expand Down Expand Up @@ -1506,7 +1508,8 @@ def __getattr__(self, name):

def test_importing_multiprocessing_does_not_impact_whichmodule(self):
# non-regression test for #528
script = textwrap.dedent("""
script = textwrap.dedent(
"""
import multiprocessing
import cloudpickle
from cloudpickle.cloudpickle import dumps
Expand All @@ -1516,7 +1519,8 @@ def test_importing_multiprocessing_does_not_impact_whichmodule(self):
dumps.__module__ = None

print(cloudpickle.cloudpickle._whichmodule(dumps, dumps.__name__))
""")
"""
)
script_path = Path(self.tmpdir) / "whichmodule_and_multiprocessing.py"
with open(script_path, mode="w") as f:
f.write(script)
Expand All @@ -1530,7 +1534,6 @@ def test_importing_multiprocessing_does_not_impact_whichmodule(self):
self.assertEqual(proc.wait(), 0, msg="Stdout: " + str(out))
self.assertEqual(out.strip(), b"cloudpickle.cloudpickle")


def test_unrelated_faulty_module(self):
# Check that pickling a dynamically defined function or class does not
# fail when introspecting the currently loaded modules in sys.modules
Expand Down Expand Up @@ -1733,7 +1736,9 @@ def f5(x):

cloned = subprocess_pickle_echo(f5, protocol={protocol})
assert cloned(7) == f5(7) == 7
""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(textwrap.dedent(code))

def test_interactively_defined_global_variable(self):
Expand Down Expand Up @@ -1872,7 +1877,9 @@ def interactive_function(x):
# previous definition of `interactive_function`:

assert w.run(wrapper_func, 41) == 40
""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(code)

def test_interactive_remote_function_calls_no_side_effect(self):
Expand Down Expand Up @@ -1916,7 +1923,9 @@ def is_in_main(name):
assert is_in_main("GLOBAL_VARIABLE")
assert not w.run(is_in_main, "GLOBAL_VARIABLE")

""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(code)

def test_interactive_dynamic_type_and_remote_instances(self):
Expand Down Expand Up @@ -1955,7 +1964,9 @@ def echo(*args):
assert isinstance(c1, CustomCounter)
assert isinstance(c2, CustomCounter)

""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(code)

def test_interactive_dynamic_type_and_stored_remote_instances(self):
Expand Down Expand Up @@ -2032,7 +2043,9 @@ class A:
# method:
assert w.run(lambda obj_id: lookup(obj_id).echo(43), id2) == 43

""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(code)

def test_dynamic_func_deterministic_roundtrip(self):
Expand Down Expand Up @@ -2220,7 +2233,9 @@ def process_data():
# iterations instead of 100 as used now (100x more data)
assert growth < 5e7, growth

""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(code)

def test_pickle_reraise(self):
Expand Down Expand Up @@ -2422,7 +2437,9 @@ def check_positive(x):

result = w.run(check_positive, 1)
assert result is Color.BLUE
""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(code)

def test_relative_import_inside_function(self):
Expand Down Expand Up @@ -2476,7 +2493,9 @@ def f(a, /, b=1):
with pytest.raises(TypeError):
func(a=2)

""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(textwrap.dedent(code))

def test___reduce___returns_string(self):
Expand Down Expand Up @@ -3049,7 +3068,9 @@ def echo(*args):
cloned_value, cloned_type = w.run(echo, value, SampleDataclass)
assert cloned_type is SampleDataclass
assert isinstance(cloned_value, SampleDataclass)
""".format(protocol=self.protocol)
""".format(
protocol=self.protocol
)
assert_run_python_script(code)


Expand Down
1 change: 0 additions & 1 deletion tests/cloudpickle_testpkg/_cloudpickle_testpkg/mod.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import sys
import types


# #354: To emulate package capabilities while being a single file, an extension
# module (for instance a mod.so file) can dynamically create a module object
# (most likely using the *package_name*.*parent_module_name*.*submodule_name*
Expand Down
2 changes: 1 addition & 1 deletion tests/old_pickles/cpython_310/cloudpickle_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.2.1
2.2.1
2 changes: 1 addition & 1 deletion tests/old_pickles/cpython_311/cloudpickle_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.2.1
2.2.1
2 changes: 1 addition & 1 deletion tests/old_pickles/cpython_38/cloudpickle_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.4.1
1.4.1
2 changes: 1 addition & 1 deletion tests/old_pickles/cpython_39/cloudpickle_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.4.1
1.4.1
5 changes: 1 addition & 4 deletions tests/testutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,7 @@ def check_deterministic_pickle(a, b):
full_diff = "".join(full_diff)
if len(full_diff) > 1500:
full_diff = full_diff[:1494] + " [...]"
raise AssertionError(
"Pickle payloads are not bitwise equal:\n"
+ full_diff
)
raise AssertionError("Pickle payloads are not bitwise equal:\n" + full_diff)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py{38, 39, 310, 311, 312, 313, py3}
envlist = py{38, 39, 310, 311, 312, 313, 314, py3}

[testenv]
deps = -rdev-requirements.txt
Expand Down