diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index a7becfb44..587fd9015 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -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 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9bac7d409..140a689da 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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"] diff --git a/cloudpickle/__init__.py b/cloudpickle/__init__.py index 9faf0b6d8..bc99dacd1 100644 --- a/cloudpickle/__init__.py +++ b/cloudpickle/__init__.py @@ -3,7 +3,7 @@ __doc__ = cloudpickle.__doc__ -__version__ = "3.1.2" +__version__ = "3.2.0.dev0" __all__ = [ # noqa "__version__", diff --git a/cloudpickle/cloudpickle.py b/cloudpickle/cloudpickle.py index e600b35f2..61068b6b6 100644 --- a/cloudpickle/cloudpickle.py +++ b/cloudpickle/cloudpickle.py @@ -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: @@ -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] diff --git a/dev/make-distribution.sh b/dev/make-distribution.sh index f9400f243..87a9f7712 100755 --- a/dev/make-distribution.sh +++ b/dev/make-distribution.sh @@ -11,4 +11,3 @@ rm -rf cloudpickle.egg-info python setup.py sdist python setup.py bdist_wheel --universal twine upload dist/* - diff --git a/tests/cloudpickle_test.py b/tests/cloudpickle_test.py index 7b9cb7493..e2097d1cb 100644 --- a/tests/cloudpickle_test.py +++ b/tests/cloudpickle_test.py @@ -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" @@ -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): @@ -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() @@ -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, @@ -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 @@ -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) @@ -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 @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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) diff --git a/tests/cloudpickle_testpkg/_cloudpickle_testpkg/mod.py b/tests/cloudpickle_testpkg/_cloudpickle_testpkg/mod.py index f38cdb701..3a4681640 100644 --- a/tests/cloudpickle_testpkg/_cloudpickle_testpkg/mod.py +++ b/tests/cloudpickle_testpkg/_cloudpickle_testpkg/mod.py @@ -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* diff --git a/tests/old_pickles/cpython_310/cloudpickle_version.txt b/tests/old_pickles/cpython_310/cloudpickle_version.txt index fae692e41..c043eea77 100644 --- a/tests/old_pickles/cpython_310/cloudpickle_version.txt +++ b/tests/old_pickles/cpython_310/cloudpickle_version.txt @@ -1 +1 @@ -2.2.1 \ No newline at end of file +2.2.1 diff --git a/tests/old_pickles/cpython_311/cloudpickle_version.txt b/tests/old_pickles/cpython_311/cloudpickle_version.txt index fae692e41..c043eea77 100644 --- a/tests/old_pickles/cpython_311/cloudpickle_version.txt +++ b/tests/old_pickles/cpython_311/cloudpickle_version.txt @@ -1 +1 @@ -2.2.1 \ No newline at end of file +2.2.1 diff --git a/tests/old_pickles/cpython_38/cloudpickle_version.txt b/tests/old_pickles/cpython_38/cloudpickle_version.txt index 13175fdc4..347f5833e 100644 --- a/tests/old_pickles/cpython_38/cloudpickle_version.txt +++ b/tests/old_pickles/cpython_38/cloudpickle_version.txt @@ -1 +1 @@ -1.4.1 \ No newline at end of file +1.4.1 diff --git a/tests/old_pickles/cpython_39/cloudpickle_version.txt b/tests/old_pickles/cpython_39/cloudpickle_version.txt index 13175fdc4..347f5833e 100644 --- a/tests/old_pickles/cpython_39/cloudpickle_version.txt +++ b/tests/old_pickles/cpython_39/cloudpickle_version.txt @@ -1 +1 @@ -1.4.1 \ No newline at end of file +1.4.1 diff --git a/tests/testutils.py b/tests/testutils.py index bf2d3bcad..f90bb515c 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -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__": diff --git a/tox.ini b/tox.ini index a9d3eded3..5c5ec7e22 100644 --- a/tox.ini +++ b/tox.ini @@ -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