瀏覽代碼

Enhancement in tests & set op token pointer to null before serialization

Yann Weber 2 年之前
父節點
當前提交
148afe7adc
共有 3 個檔案被更改,包括 102 行新增11 行删除
  1. 55
    3
      python_rpnexpr.c
  2. 10
    2
      python_rpnexpr.h
  3. 37
    6
      tests/tests_pyrpn.py

+ 55
- 3
python_rpnexpr.c 查看文件

@@ -27,6 +27,8 @@ PyMethodDef RPNExpr_methods[] = {
27 27
 and the stack state."},
28 28
 	{"__setstate__", (PyCFunction)rpnexpr_setstate, METH_O,
29 29
 		"Unpickling method"},
30
+	{"uid", (PyCFunction)rpnexpr_getexprstate, METH_NOARGS,
31
+		"Return a base64 uid for expression"},
30 32
 	{NULL} //Sentinel
31 33
 };
32 34
 
@@ -191,12 +193,50 @@ void rpnexpr_del(PyObject *self)
191 193
 }
192 194
 
193 195
 
196
+PyObject* rpnexpr_getexprstate(PyObject *self, PyObject *noargs)
197
+{
198
+	/*
199
+	PyObject *base64_mod, *base64_encode, *gzip, *compress;
200
+	PyObject *bytes_repr, *comp, *res;
201
+	if(!(base64_mod = PyImport_ImportModule("base64")))
202
+	{
203
+		return NULL;
204
+	}
205
+	if(!(base64_encode = PyObject_GetAttrString(base64_mod, "b64encode")))
206
+	{
207
+		return NULL;
208
+	}
209
+	if(!(gzip = PyImport_ImportModule("gzip")))
210
+	{
211
+		return NULL;
212
+	}
213
+	if(!(compress = PyObject_GetAttrString(gzip, "compress")))
214
+	{
215
+		return NULL;
216
+	}
217
+
218
+	bytes_repr = _rpnexpr_getstate(self, noargs, 0);
219
+
220
+	res = PyObject_CallOneArg(base64_encode, bytes_repr);
221
+	Py_DECREF(bytes_repr);
222
+	return res;
223
+
224
+	comp = PyObject_CallOneArg(compress, bytes_repr);
225
+	Py_DECREF(bytes_repr);
226
+	
227
+	res = PyObject_CallOneArg(base64_encode,  comp);
228
+	Py_DECREF(comp);
229
+	return res;
230
+	*/
231
+	return NULL;
232
+}
233
+
194 234
 PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
195 235
 {
196 236
 	PyObject *res, *part;
197 237
 	PyRPNExpr_state_t resbuf;
198 238
 	PyRPNExpr_t *expr_self;
199
-	size_t total_sz;
239
+	size_t total_sz, i;
200 240
 	char err_str[128];
201 241
 
202 242
 	expr_self = (PyRPNExpr_t*)self;
@@ -239,12 +279,24 @@ PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
239 279
 	}
240 280
 	if(resbuf.token_sz)
241 281
 	{
282
+		for(i=0; i<expr_self->rpn->toks.tokens_sz;i++)
283
+		{
284
+			// restore op pointers
285
+			expr_self->rpn->toks.tokens[i].op = NULL;
286
+		}
287
+	
242 288
 		if(!(part=PyBytes_FromStringAndSize(
243 289
 				(char*)expr_self->rpn->toks.tokens,
244 290
 				sizeof(rpn_token_t) * resbuf.token_sz)))
245 291
 		{
246 292
 			return NULL;
247 293
 		}
294
+		for(i=0; i<expr_self->rpn->toks.tokens_sz;i++)
295
+		{
296
+			// restore op pointers
297
+			expr_self->rpn->toks.tokens[i].op = &(rpn_ops[expr_self->rpn->toks.tokens[i].op_n]);
298
+		}
299
+	
248 300
 		PyBytes_ConcatAndDel(&res, part);
249 301
 		if(!res)
250 302
 		{
@@ -393,8 +445,6 @@ args buffer : %s",
393 445
 		toks.tokens[i].op = &(rpn_ops[toks.tokens[i].op_n]);
394 446
 	}
395 447
 	
396
-	expr_self->rpn->toks = toks;
397
-	
398 448
 	if(rpn_expr_untokenize(expr_self->rpn, &toks, 0) < 0)
399 449
 	{
400 450
 		snprintf(err_str, 256,
@@ -403,6 +453,8 @@ args buffer : %s",
403 453
 		PyErr_SetString(PyExc_RuntimeError, err_str);
404 454
 		goto close_err;
405 455
 	}
456
+	expr_self->rpn->toks = toks;
457
+	
406 458
 
407 459
 	Py_RETURN_NONE;
408 460
 	close_err:

+ 10
- 2
python_rpnexpr.h 查看文件

@@ -99,13 +99,21 @@ int rpnexpr_init(PyObject *self, PyObject *args, PyObject *kwds);
99 99
  */
100 100
 void rpnexpr_del(PyObject *self);
101 101
 
102
+/**@brief Returns a byte representation of expression (like getstate but
103
+ * without the stack informations
104
+ * @param self RPNExpr instance
105
+ * @param noargs Not an argument...
106
+ * @return A bytes Python instance
107
+ */
108
+PyObject* rpnexpr_getexprstate(PyObject *self, PyObject *noargs);
109
+
102 110
 /**@brief RPNExpr __getstate__ method for pickling
103
- * @param cls RPNExpr type object
111
+ * @param self RPNExpr type object
104 112
  * @param noargs Not an argument...
105 113
  * @return A bytes Python instance suitable as argument for
106 114
  * @ref rpnexpr_setstate
107 115
  */
108
-PyObject* rpnexpr_getstate(PyObject *cls, PyObject *noargs);
116
+PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs);
109 117
 
110 118
 /**@brief RPNExpr __setstate__ method for pickling
111 119
  * @param cls RPNExpr type object

+ 37
- 6
tests/tests_pyrpn.py 查看文件

@@ -34,6 +34,29 @@ except (ImportError, NameError) as e:
34 34
           file=sys.stderr)
35 35
     raise e
36 36
 
37
+## TODO : move this function somewhere or implement it in C
38
+def decode_state(state):
39
+    """ Return a dict containing rpn state dump fields
40
+    """
41
+    res = dict()
42
+    res['real_sz'] = len(state)
43
+    res['total_sz'] = int.from_bytes(state[0:8], byteorder="little")
44
+    res['argc'] =  int.from_bytes(state[8:16], byteorder="little")
45
+    res['stack_sz_bytes'] = state[16:24]
46
+    res['stack_sz'] = state[16]
47
+    res['token_sz'] = int.from_bytes(state[24:32], byteorder="little", signed=True)
48
+    res['stack'] = [int.from_bytes(state[i:i+8], byteorder="little")
49
+                    for i in range(32, 32 + (8*res['stack_sz']),8)]
50
+    res['tokens_off'] = 32 + (8*res['stack_sz'])
51
+    res['tokens_real_sz'] = res['real_sz'] - res['tokens_off']
52
+    res['tokens'] = [state[i:i+24]
53
+                      for i in range(res['tokens_off'],
54
+                                     res['tokens_off'] + (24*res['token_sz']),
55
+                                     24)]
56
+    return res
57
+    pass
58
+
59
+
37 60
 class Test0RpnModule(unittest.TestCase):
38 61
 
39 62
     def test_init(self):
@@ -121,16 +144,24 @@ class Test0RpnModule(unittest.TestCase):
121 144
     
122 145
     def test_pickle_state(self):
123 146
         """ Testing pickling/unpickling """
124
-        e = pyrpn.RPNExpr(pyrpn.random_expr(2), 2)
125
-
147
+        e = pyrpn.RPNExpr('0x42 + A0', 2)
126 148
         e2 = pickle.loads(pickle.dumps(e))
149
+        ds_e = decode_state(e.__getstate__())
150
+        ds_e2 = decode_state(e2.__getstate__())
151
+        self.assertEqual(e.__getstate__(), e2.__getstate__(),
152
+                         msg="EXPR: %r != %r (%r != %r)" % (e, e2, ds_e, ds_e2))
153
+        for i in range(100):
154
+            e = pyrpn.RPNExpr(pyrpn.random_expr(0), 2)
155
+
156
+            e2 = pickle.loads(pickle.dumps(e))
127 157
 
128
-        self.assertEqual(e.__getstate__(), e2.__getstate__())
158
+            self.assertEqual(e.__getstate__(), e2.__getstate__(),
159
+                             msg="EXPR#%d : %r != %r" % (i,e, e2))
129 160
 
130
-        e3 = pickle.loads(pickle.dumps(e2))
161
+            e3 = pickle.loads(pickle.dumps(e2))
131 162
 
132
-        self.assertEqual(e.__getstate__(), e3.__getstate__())
133
-        self.assertEqual(e2.__getstate__(), e3.__getstate__())
163
+            self.assertEqual(e.__getstate__(), e3.__getstate__(), msg=e)
164
+            self.assertEqual(e2.__getstate__(), e3.__getstate__(), msg=e)
134 165
 
135 166
 if __name__ == '__main__':
136 167
     unittest.main()

Loading…
取消
儲存