nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: jsonpickle/jsonpickle
Pull request #218 (2018-08-25 19:50:41)

Allow iterators to be reduced and encoded
In #216, we see a practical case where at iterator should be reducible.

This PR adds a test for this need and removes the code that prevents it from working as expected. No tests seem to be relying on the other expectation, so this seems like this behavior aligns better with what stdlib pickle does.


Patch:
diff --git a/jsonpickle/compat.py b/jsonpickle/compat.py
index 21a3f17..d3d8116 100644
--- a/jsonpickle/compat.py
+++ b/jsonpickle/compat.py
@@ -18,3 +18,9 @@ else:
     ustr = unicode
     from base64 import encodestring as encodebytes
     from base64 import decodestring as decodebytes
+
+
+def iterator(class_):
+    if PY2 and hasattr(class_, '__next__'):
+        class_.next = class_.__next__
+    return class_
diff --git a/jsonpickle/util.py b/jsonpickle/util.py
index f9ad547..a410220 100644
--- a/jsonpickle/util.py
+++ b/jsonpickle/util.py
@@ -372,7 +372,6 @@ def is_reducible(obj):
                 is_sequence_subclass(obj) or
                 is_function(obj) or
                 is_module(obj) or
-                is_iterator(obj) or
                 type(getattr(obj, '__slots__', None)) is IteratorType or
                 type(obj) is object or
                 obj is object or


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index c7ca1fd..6ab4757 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -937,6 +937,18 @@ class PickleProtocol2ReduceTuple(object):
                 )
 
 
+@compat.iterator
+class ReducibleIterator(object):
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        raise StopIteration()
+
+    def __reduce__(self):
+        return ReducibleIterator, ()
+
+
 def protocol_2_reduce_tuple_func(*args):
     return PickleProtocol2ReduceTupleFunc(*args)
 
@@ -1267,6 +1279,17 @@ class PicklingProtocol2TestCase(SkippableTest):
         self.assertEqual(next(decoded), '2')
         self.assertEqual(next(decoded), '3')
 
+    def test_reduce_iterable(self):
+        """
+        An reducible object should be pickleable even if
+        it is also iterable.
+        """
+        instance = ReducibleIterator()
+        self.assertTrue(util.is_iterator(instance))
+        encoded = jsonpickle.encode(instance)
+        decoded = jsonpickle.decode(encoded)
+        self.assertIsInstance(decoded, ReducibleIterator)
+
     def test_reduce_string(self):
         """
         Ensure json pickle will accept the redirection to another object when
Repository: jsonpickle/jsonpickle
Pull request #400 (2022-07-27 14:15:20)

Pickling a function returns None as the module
Pickling the readline function of io.BytesIO returns a None module instead of _io

```
>>> jsonpickle.encode(BytesIO(b'bytes').readline)
'{"py/function": "None.BytesIO.readline"}'
```


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index f37959e..ac07000 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -18,6 +18,7 @@ v3.0.0
       into different classes. (#148) (+392)
     * Fix bug with deserializing `numpy.poly1d`. (#391)
     * Allow frozen dataclasses to be deserialized. (#240)
+    * Fixed a bug where pickling a function could return a ``None`` module. (#399)
 
 v2.2.0
 ======
diff --git a/jsonpickle/util.py b/jsonpickle/util.py
index 92ae3cd..7a86300 100644
--- a/jsonpickle/util.py
+++ b/jsonpickle/util.py
@@ -515,6 +515,9 @@ def importable_name(cls):
     # Use the fully-qualified name if available (Python >= 3.3)
     name = getattr(cls, '__qualname__', cls.__name__)
     module = translate_module_name(cls.__module__)
+    if not module:
+        if hasattr(cls, '__self__'):
+            module = cls.__self__.__class__.__module__
     return '{}.{}'.format(module, name)
 
 


Test patch:
diff --git a/tests/util_test.py b/tests/util_test.py
index 331411d..355fb89 100644
--- a/tests/util_test.py
+++ b/tests/util_test.py
@@ -8,6 +8,7 @@
 from __future__ import absolute_import, division, unicode_literals
 
 import doctest
+import io
 import time
 import unittest
 
@@ -227,6 +228,13 @@ class UtilTestCase(unittest.TestCase):
         self.assertTrue(has_method(old_instance, 'bound_method'))
         self.assertFalse(has_method(MethodTestOldStyle, 'bound_method'))
 
+    def test_importable_name(self):
+        func_being_tested_obj = util.importable_name
+        io_method_obj = io.BytesIO(b'bytes').readline
+        self.assertEqual(util.importable_name(func_being_tested_obj), 'jsonpickle.util.importable_name')
+        self.assertEqual(util.importable_name(io_method_obj), '_io.BytesIO.readline')
+        self.assertEqual(util.importable_name(dict), 'builtins.dict')
+
 
 def suite():
     suite = unittest.TestSuite()
Repository: jsonpickle/jsonpickle
Pull request #433 (2022-12-28 12:10:00)

Warn if a custom pickling handler returns None
The docstring for the encode function says
```
    :param warn: If set to True then jsonpickle will warn when it
        returns None for an object which it cannot pickle
        (e.g. file descriptors).
```

However, if you pass in a file descriptor when running python 3.8 or higher the `TextIOHandler` gets used. This means that no warning is raised because there’s no check if a handler has returned None.


Patch:
diff --git a/jsonpickle/pickler.py b/jsonpickle/pickler.py
index 1b8a88d..d17edb1 100644
--- a/jsonpickle/pickler.py
+++ b/jsonpickle/pickler.py
@@ -521,7 +521,11 @@ class Pickler(object):
         if handler is not None:
             if self.unpicklable:
                 data[tags.OBJECT] = class_name
-            return handler(self).flatten(obj, data)
+            result = handler(self).flatten(obj, data)
+            if result is None:
+                self._pickle_warning(obj)
+            return result
+
 
         reduce_val = None
 


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index 78b14fc..c2b86fc 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -563,6 +563,14 @@ class PicklingTestCase(unittest.TestCase):
             jsonpickle.decode(encoded, classes={"MyPropertiesSlots": MyPropertiesDict}),
         )
 
+    def test_warnings(self):
+        data = os.fdopen(os.pipe()[0])
+        with warnings.catch_warnings(record=True) as w:
+            jsonpickle.encode(data, warn=True)
+            assert len(w) == 1
+            assert issubclass(w[-1].category, UserWarning)
+            assert "replaced with None" in str(w[-1].message)
+
 
 class JSONPickleTestCase(SkippableTest):
     def setUp(self):
Repository: jsonpickle/jsonpickle
Pull request #489 (2024-04-09 06:46:09)

numpy: forward constructor arguments through register_handlers()
Expose the NumpyNDArrayHandler constructor arguments to the user-facing `def register_handlers()`. This allows users to opt-out of warnings and customize ndarray parameters.

davvid: This changes the public API (in a non-breaking way) so this is worth reviewing.

This might be considered a new feature, so if we need to bump the minor version we should probably tag the current state and release the next patch version before merging these changes.

We're exposing a few new keyword arguments and the names of the arguments will be part of the public API so that's definitely worth a look.

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index a9d69a1..11d99d7 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,8 @@
+v3.1.0
+======
+    * `jsonpickle.ext.numpy.register_handlers` now provides options that are forwarded
+      to the `NumpyNDArrayHandler` constructor. (+489)
+
 v3.0.4
 ======
     * Fixed an issue with django.SafeString and other classes inheriting from
diff --git a/jsonpickle/ext/numpy.py b/jsonpickle/ext/numpy.py
index fd321d3..3c96ae8 100644
--- a/jsonpickle/ext/numpy.py
+++ b/jsonpickle/ext/numpy.py
@@ -342,10 +342,25 @@ class NumpyNDArrayHandlerView(NumpyNDArrayHandlerBinary):
         return arr
 
 
-def register_handlers():
+def register_handlers(
+    ndarray_mode='warn',
+    ndarray_size_threshold=16,
+    ndarray_compression=zlib,
+):
+    """Register handlers for numpy types
+
+    :param ndarray_abc_xyz: Forward constructor arguments to NumpyNDArrayHandlerView.
+        Options with an 'ndarray_' prefix correspond to the same-named
+        NumpyNDArrayHandlerView constructor options, sans the 'ndarray_' prefix.
+    """
+    ndarray_handler = NumpyNDArrayHandlerView(
+        mode=ndarray_mode,
+        size_threshold=ndarray_size_threshold,
+        compression=ndarray_compression,
+    )
+    register(np.ndarray, ndarray_handler, base=True)
     register(np.dtype, NumpyDTypeHandler, base=True)
     register(np.generic, NumpyGenericHandler, base=True)
-    register(np.ndarray, NumpyNDArrayHandlerView(), base=True)
     # Numpy 1.20 has custom dtypes that must be registered separately.
     register(np.dtype(np.void).__class__, NumpyDTypeHandler, base=True)
     register(np.dtype(np.float32).__class__, NumpyDTypeHandler, base=True)
@@ -354,6 +369,7 @@ def register_handlers():
 
 
 def unregister_handlers():
+    """Remove numpy handlers from the handler registry"""
     unregister(np.dtype)
     unregister(np.generic)
     unregister(np.ndarray)


Test patch:
diff --git a/tests/numpy_test.py b/tests/numpy_test.py
index 694f21f..e271725 100644
--- a/tests/numpy_test.py
+++ b/tests/numpy_test.py
@@ -19,7 +19,7 @@ from jsonpickle import handlers
 @pytest.fixture(scope='module', autouse=True)
 def numpy_extension():
     """Initialize the numpy extension for this test module"""
-    jsonpickle.ext.numpy.register_handlers()
+    jsonpickle.ext.numpy.register_handlers(ndarray_mode='warn')
     yield  # control to the test function.
     jsonpickle.ext.numpy.unregister_handlers()
Repository: jsonpickle/jsonpickle
Pull request #494 (2024-04-19 22:08:38)

classes should support replacing with dict
Without this change, passing a dict in `.decode()` will completely
ignore the key, and just substitute the value directly.

Consider the serialized data (`json_str`):
```
{
  "x": "value",
  "py/object": "older.pkg.Class",
}
```

If `Class` is now moved to `newer.pkg`, I'd expect to use the API like:

```
jsonpickle.decode(json_str, classes={"older.pkg.Class": newer.pkg.Class})
```

Currently the above API doesn't work, it will populate `self._classes` as:
```
{"newer.pkg.Class": new.pkg.Class}
```

The `"older.pkg.Class"` is completely ignored, even though `loadclass` is
implemented to support this case of class replacement. 


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 11d99d7..28225a2 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,6 +2,9 @@ v3.1.0
 ======
     * `jsonpickle.ext.numpy.register_handlers` now provides options that are forwarded
       to the `NumpyNDArrayHandler` constructor. (+489)
+    * Fix bug of not handling ``classes`` argument to `jsonpickle.decode`
+      being a dict. Previously, the keys were ignored and only values were
+      used. (+494)
 
 v3.0.4
 ======
diff --git a/jsonpickle/unpickler.py b/jsonpickle/unpickler.py
index ec1e9dc..e7e5eaa 100644
--- a/jsonpickle/unpickler.py
+++ b/jsonpickle/unpickler.py
@@ -390,8 +390,7 @@ class Unpickler(object):
             for cls in classes:
                 self.register_classes(cls)
         elif isinstance(classes, dict):
-            for cls in classes.values():
-                self.register_classes(cls)
+            self._classes.update(classes)
         else:
             self._classes[util.importable_name(classes)] = classes
 


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index bf7ff74..4eab17e 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -571,10 +571,9 @@ class PicklingTestCase(unittest.TestCase):
         obj = MyPropertiesSlots()
         encoded = jsonpickle.encode(obj)
         # MyPropertiesSlots and MyPropertiesDict have compatible eq methods
-        self.assertEqual(
-            obj,
-            jsonpickle.decode(encoded, classes={"MyPropertiesSlots": MyPropertiesDict}),
-        )
+        decoded = jsonpickle.decode(encoded, classes={"MyPropertiesSlots": MyPropertiesDict})
+        self.assertIsInstance(decoded, MyPropertiesDict)
+        self.assertEqual(obj, decoded)
 
     def test_warnings(self):
         data = os.fdopen(os.pipe()[0])
Repository: jsonpickle/jsonpickle
Pull request #507 (2024-06-08 01:17:12)

Add support for (de)serializing NoneType correctly
The present `loadclass` implementation fails to correctly loadclass for `builtins.NoneType`.

The PR adds support for this such that decoding will behave appropriately for following example:

```py

some_parms = dict( value_type=(str, type(None)), default=None, some_other_key=42 )
some_parms_enc = jsonpickle.encode(some_parms)
some_parms_dec = jsonpickle.decode(some_parms_enc)

some_parms == some_pars_dec
```

bhaveshpandey: > Looks great to me, apart from a few relatively unimportant nitpicks. Only other thing is a CHANGELOG entry would be nice, but I can do that if you'd rather me take care of it.

It would be great if you could do it for me please @Theelx ? I am not sure how I should go about adding to the changelist.

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 49cf1e1..175a3b6 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,8 @@
+v3.2.2
+======
+    * A bug with the incorrect (de)serialization of NoneType objects has been fixed.
+      (+507)
+
 v3.2.1
 ======
     * The ``ignorereserved`` parameter to the private ``_restore_from_dict()``
diff --git a/jsonpickle/unpickler.py b/jsonpickle/unpickler.py
index 7e2f137..735cc86 100644
--- a/jsonpickle/unpickler.py
+++ b/jsonpickle/unpickler.py
@@ -208,6 +208,9 @@ def loadclass(module_and_name, classes=None):
             return obj
         except (AttributeError, ImportError, ValueError):
             continue
+    # NoneType is a special case and can not be imported/created
+    if module_and_name == "builtins.NoneType":
+        return type(None)
     return None
 
 


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index cb2f48d..01e417b 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -257,6 +257,12 @@ class PicklingTestCase(unittest.TestCase):
         self.assertEqual(listD, self.pickler.flatten(listD))
         self.assertEqual(listD, self.unpickler.restore(listD))
 
+    def test_nonetype(self):
+        typ = type(None)
+        typ_pickled = jsonpickle.encode(typ)
+        typ_unpickled = jsonpickle.decode(typ_pickled)
+        self.assertEqual(typ, typ_unpickled)
+
     def test_set(self):
         setlist = ['orange', 'apple', 'grape']
         setA = set(setlist)
Repository: jsonpickle/jsonpickle
Pull request #544 (2024-12-08 21:49:28)

unpickler: guard against malformed py/reduce values
The stored value may not be iterable. Restore to an empty list when invalid py/reduce contents are encountered.

davvid: This is similar in spirit to the earlier ossfuzz-detected errors.

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 55fadcb..f9a43ab 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,7 +1,7 @@
 Upcoming
 ========
-    * The unpickler is now more resilient to malformed "py/set", "py/tuple", and
-      "py/iterator" input data.
+    * The unpickler is now more resilient to malformed "py/reduce", "py/set",
+      "py/tuple", and "py/iterator" input data. (+544)
     * The test suite was updated to leverage more pytest features.
     * The ``jsonpickle.compat`` module is no longer used. It is still provided
       for backwards compatibility but it may be removed in a future version.
diff --git a/jsonpickle/unpickler.py b/jsonpickle/unpickler.py
index 022a98b..ea74a20 100644
--- a/jsonpickle/unpickler.py
+++ b/jsonpickle/unpickler.py
@@ -513,7 +513,13 @@ class Unpickler:
         """
         proxy = _Proxy()
         self._mkref(proxy)
-        reduce_val = list(map(self._restore, obj[tags.REDUCE]))
+        try:
+            reduce_val = list(map(self._restore, obj[tags.REDUCE]))
+        except TypeError:
+            result = []
+            proxy.reset(result)
+            self._swapref(proxy, result)
+            return result
         if len(reduce_val) < 5:
             reduce_val.extend([None] * (5 - len(reduce_val)))
         f, args, state, listitems, dictitems = reduce_val
@@ -525,6 +531,11 @@ class Unpickler:
                 cls = self._restore(cls)
             stage1 = cls.__new__(cls, *args[1:])
         else:
+            if not callable(f):
+                result = []
+                proxy.reset(result)
+                self._swapref(proxy, result)
+                return result
             stage1 = f(*args)
 
         if state:


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index af0c40b..ecf74cb 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -317,6 +317,14 @@ def test_iterator_with_invalid_data(unpickler):
         assert next(result) == set()
 
 
+@pytest.mark.parametrize('value', ['', 0, True, None, [], {}, ('x',), {'x': True}])
+def test_reduce_with_invalid_data(value, unpickler):
+    """Invalid serialized reduce data results in an empty list"""
+    data = {tags.REDUCE: value}
+    result = unpickler.restore(data)
+    assert result == []
+
+
 def test_dict(pickler, unpickler):
     """Our custom keys are preserved when user dicts contain them"""
     dict_a = {'key1': 1.0, 'key2': 20, 'key3': 'thirty', tags.JSON_KEY + '6': 6}
Repository: jsonpickle/jsonpickle
Pull request #547 (2025-01-06 09:36:07)

unpickler: guard against UnicodeEncodeError when restoring base64/85


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index ff917d4..462648c 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,6 +2,7 @@ Upcoming
 ========
     * The unpickler is now more resilient to malformed "py/id" and "py/repr" data.
       (+546)
+    * The unpickler is now more resilient to invalid "py/b85" and "py/b64" data.
 
 v4.0.1
 ======
diff --git a/jsonpickle/unpickler.py b/jsonpickle/unpickler.py
index dee0894..93e7d35 100644
--- a/jsonpickle/unpickler.py
+++ b/jsonpickle/unpickler.py
@@ -445,13 +445,13 @@ class Unpickler:
     def _restore_base64(self, obj):
         try:
             return util.b64decode(obj[tags.B64].encode('utf-8'))
-        except AttributeError:
+        except (AttributeError, UnicodeEncodeError):
             return b''
 
     def _restore_base85(self, obj):
         try:
             return util.b85decode(obj[tags.B85].encode('utf-8'))
-        except AttributeError:
+        except (AttributeError, UnicodeEncodeError):
             return b''
 
     def _refname(self):


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index 0b240b6..daa33ba 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -217,7 +217,7 @@ def test_decode_base85(unpickler):
     assert unpickler.restore(pickled) == expected
 
 
-@pytest.mark.parametrize('value', ['', '/', 1, True, False, None, [], {}])
+@pytest.mark.parametrize('value', ['', '/', '\udc00', 1, True, False, None, [], {}])
 def test_decode_invalid_b85(value, unpickler):
     """Invalid base85 data restores to an empty string"""
     expected = b''
@@ -232,7 +232,9 @@ def test_base85_still_handles_base64(unpickler):
     assert unpickler.restore(pickled) == expected
 
 
-@pytest.mark.parametrize('value', ['', 'x', '!', 0, 1, True, False, None, [], {}])
+@pytest.mark.parametrize(
+    'value', ['', 'x', '!', '\udc00', 0, 1, True, False, None, [], {}]
+)
 def test_decode_invalid_b64(value, unpickler):
     """Invalid base85 data restores to an empty string"""
     expected = b''
Repository: jsonpickle/jsonpickle
Pull request #548 (2025-01-11 01:00:20)

unpickler: improve support for unpickling readonly str attributes
Fixes: #478


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 423c220..671c7c3 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,8 @@ Upcoming
       (+546)
     * The unpickler is now more resilient to invalid "py/b85" and "py/b64" data.
       (+547)
+    * The unpickler's support for read-only str attributes was improved.
+      (+548) (#478)
 
 v4.0.1
 ======
diff --git a/jsonpickle/unpickler.py b/jsonpickle/unpickler.py
index 93e7d35..2e77320 100644
--- a/jsonpickle/unpickler.py
+++ b/jsonpickle/unpickler.py
@@ -725,10 +725,9 @@ class Unpickler:
                         if (
                             hasattr(instance, '__slots__')
                             and not len(instance.__slots__)
-                            and issubclass(instance.__class__, int)
-                            and self.handle_readonly
                             # we have to handle this separately because of +483
-                            and issubclass(instance.__class__, str)
+                            and issubclass(instance.__class__, (int, str))
+                            and self.handle_readonly
                         ):
                             continue
                         raise e


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index daa33ba..62acd7e 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -1185,6 +1185,20 @@ def test_readonly_attrs():
     assert safe_str == unpickled
 
 
+def test_readonly_str_attrs():
+    """Objects with readonly string attributes can roundtrip"""
+    safe_str = SafeString('test')
+    # We'll first try setting handle_readonly=True when encoding.
+    encoded = jsonpickle.encode(safe_str, handle_readonly=True)
+    actual = jsonpickle.decode(encoded, handle_readonly=True)
+    assert safe_str == actual
+    # Next we'll ensure that we can decode a payload that contains readonly attributes
+    # by omitting the handle_readonly option when pickling.
+    encoded = jsonpickle.encode(safe_str)
+    actual = jsonpickle.decode(encoded, handle_readonly=True)
+    assert safe_str == actual
+
+
 class PicklableNamedTuple:
     """A namedtuple wrapper that uses ``__getnewargs__``