Przeglądaj źródła

fix pickle array2d

blueloveTH 1 tydzień temu
rodzic
commit
128fc43667
3 zmienionych plików z 15 dodań i 38 usunięć
  1. 3 0
      docs/modules/pickle.md
  2. 0 30
      src/modules/pickle.c
  3. 12 8
      tests/904_pickle.py

+ 3 - 0
docs/modules/pickle.md

@@ -24,6 +24,9 @@ The following types can be pickled:
 - [x] classes accessible from the top level of a module;
 - [x] classes accessible from the top level of a module;
 - [x] instances of such classes
 - [x] instances of such classes
 
 
+`array2d` instances cannot be pickled. Calling `pickle.dumps()` on an `array2d`
+raises `TypeError`. Previously pickled `array2d` data is no longer supported.
+
 Cyclic and shared references are preserved: `list`, `dict` and instances of
 Cyclic and shared references are preserved: `list`, `dict` and instances of
 python classes are memoized before their contents are written, so an object
 python classes are memoized before their contents are written, so an object
 graph containing reference cycles round-trips correctly and object identity
 graph containing reference cycles round-trips correctly and object identity

+ 0 - 30
src/modules/pickle.c

@@ -5,7 +5,6 @@
 #include "pocketpy/common/utils.h"
 #include "pocketpy/common/utils.h"
 #include "pocketpy/common/sstream.h"
 #include "pocketpy/common/sstream.h"
 #include "pocketpy/interpreter/vm.h"
 #include "pocketpy/interpreter/vm.h"
-#include "pocketpy/interpreter/array2d.h"
 #include <stdint.h>
 #include <stdint.h>
 
 
 typedef enum {
 typedef enum {
@@ -28,7 +27,6 @@ typedef enum {
     PKL_VEC2, PKL_VEC3,
     PKL_VEC2, PKL_VEC3,
     PKL_VEC2I, PKL_VEC3I,
     PKL_VEC2I, PKL_VEC3I,
     PKL_TYPE,
     PKL_TYPE,
-    PKL_ARRAY2D,
     PKL_IMPORT_PATH,
     PKL_IMPORT_PATH,
     PKL_GETATTR,
     PKL_GETATTR,
     PKL_TVALUE,
     PKL_TVALUE,
@@ -396,22 +394,6 @@ static bool pkl__write_object(PickleObject* buf, py_TValue* obj) {
             pkl__emit_cstr(buf, name->data);
             pkl__emit_cstr(buf, name->data);
             return true;
             return true;
         }
         }
-        case tp_array2d: {
-            if(pkl__try_memo(buf, obj->_obj)) return true;
-            c11_array2d* arr = py_touserdata(obj);
-            for(int i = 0; i < arr->header.numel; i++) {
-                if(arr->data[i].is_ptr)
-                    return TypeError(
-                        "'array2d' object is not picklable because it contains heap-allocated objects");
-                buf->used_types[arr->data[i].type] = true;
-            }
-            pkl__emit_op(buf, PKL_ARRAY2D);
-            pkl__emit_int(buf, arr->header.n_cols);
-            pkl__emit_int(buf, arr->header.n_rows);
-            PickleObject__write_bytes(buf, arr->data, arr->header.numel * sizeof(py_TValue));
-            pkl__store_memo(buf, obj->_obj);
-            return true;
-        }
         default: {
         default: {
             if(!obj->is_ptr) {
             if(!obj->is_ptr) {
                 pkl__emit_op(buf, PKL_TVALUE);
                 pkl__emit_op(buf, PKL_TVALUE);
@@ -732,18 +714,6 @@ bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_
                 py_push(py_tpobject(type));
                 py_push(py_tpobject(type));
                 break;
                 break;
             }
             }
-            case PKL_ARRAY2D: {
-                int n_cols = pkl__read_int(&p);
-                int n_rows = pkl__read_int(&p);
-                c11_array2d* arr = c11_newarray2d(py_pushtmp(), n_cols, n_rows);
-                int total_size = arr->header.numel * sizeof(py_TValue);
-                memcpy(arr->data, p, total_size);
-                for(int i = 0; i < arr->header.numel; i++) {
-                    arr->data[i].type = pkl__fix_type(arr->data[i].type, type_mapping);
-                }
-                p += total_size;
-                break;
-            }
             case PKL_IMPORT_PATH: {
             case PKL_IMPORT_PATH: {
                 const char* path = pkl__read_cstr(&p);
                 const char* path = pkl__read_cstr(&p);
                 int res = py_import(path);
                 int res = py_import(path);

+ 12 - 8
tests/904_pickle.py

@@ -1,5 +1,12 @@
 import pickle as pkl
 import pickle as pkl
 
 
+def assert_not_picklable(data):
+    try:
+        pkl.dumps(data)
+        assert False, 'array2d must not be picklable'
+    except TypeError as e:
+        assert str(e) == "'array2d' object is not picklable"
+
 def test(data): # type: ignore
 def test(data): # type: ignore
     print('-'*50)
     print('-'*50)
     b = pkl.dumps(data)
     b = pkl.dumps(data)
@@ -37,13 +44,10 @@ a = array2d[int | bool | vec2i].fromlist([
     [1, 2, vec2i.LEFT],
     [1, 2, vec2i.LEFT],
     [4, True, 6]
     [4, True, 6]
 ])
 ])
-a_encoded = pkl.dumps(a)
-print(a_encoded)
-a_decoded = pkl.loads(a_encoded)
-assert isinstance(a_decoded, array2d)
-assert a_decoded.width == 3 and a_decoded.height == 2
-assert (a == a_decoded).all()
-print(a_decoded)
+assert_not_picklable(a)
+assert_not_picklable([a])
+assert_not_picklable({'array': a})
+assert_not_picklable(array2d.fromlist([['hello', []]]))
 
 
 test([1, 2, 3])                 # PKL_LIST
 test([1, 2, 3])                 # PKL_LIST
 test((1, 2, 3))                 # PKL_TUPLE
 test((1, 2, 3))                 # PKL_TUPLE
@@ -99,7 +103,7 @@ print(pkl.dumps(decoded))
 a = array2d[TVal].fromlist([
 a = array2d[TVal].fromlist([
     [TVal(1), TVal(2)],
     [TVal(1), TVal(2)],
     [TVal(3), 1]])
     [TVal(3), 1]])
-test(a)
+assert_not_picklable(a)
 
 
 # test __reduce__
 # test __reduce__