1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
# HG changeset patch
# User Jim Baker <jim.baker@rackspace.com>
# Date 1454384221 25200
# Node ID d06e29d100c04576735e86c75a26c5f33669bb72
# Parent b6735606c13df95f770527e629954407f82808c5
Do not deserialize PyFunction objects. Fixes #2454
Instead use standard Python pickling; or subclass PyFunction.
diff --git a/Lib/test/test_java_integration.py b/Lib/test/test_java_integration.py
--- a/Lib/test/test_java_integration.py
+++ b/Lib/test/test_java_integration.py
@@ -14,8 +14,9 @@ import re
from collections import deque
from test import test_support
-from java.lang import (ClassCastException, ExceptionInInitializerError, String, Runnable, System,
- Runtime, Math, Byte)
+from java.lang import (
+ ClassCastException, ExceptionInInitializerError, UnsupportedOperationException,
+ String, Runnable, System, Runtime, Math, Byte)
from java.math import BigDecimal, BigInteger
from java.net import URI
from java.io import (ByteArrayInputStream, ByteArrayOutputStream, File, FileInputStream,
@@ -656,13 +657,30 @@ class SerializationTest(unittest.TestCas
self.assertEqual(date_list, roundtrip_serialization(date_list))
def test_java_serialization_pycode(self):
-
def universal_answer():
return 42
serialized_code = roundtrip_serialization(universal_answer.func_code)
self.assertEqual(eval(serialized_code), universal_answer())
+ def test_java_serialization_pyfunction(self):
+ # Not directly supported due to lack of general utility
+ # (globals will usually be in the function object in
+ # func_globals), and problems with unserialization
+ # vulnerabilities. Users can always subclass from PyFunction
+ # for specific cases, as seen in PyCascading
+ import new
+ def f():
+ return 6 * 7 + max(0, 1, 2)
+ # However, using the new module, it's possible to create a
+ # function with no globals, which means the globals will come
+ # from the current context
+ g = new.function(f.func_code, {}, "g")
+ # But still forbid Java deserialization of this function
+ # object. Use pickling or other support instead.
+ with self.assertRaises(UnsupportedOperationException):
+ roundtrip_serialization(g)
+
def test_builtin_names(self):
import __builtin__
names = [x for x in dir(__builtin__)]
@@ -872,7 +890,7 @@ class SingleMethodInterfaceTest(unittest
future.get()
self.assertEqual(x, [42])
- @unittest.skip("FIXME: not working")
+ @unittest.skip("FIXME: not working; see http://bugs.jython.org/issue2115")
def test_callable_object(self):
callable_obj = CallableObject()
future = self.executor.submit(callable_obj)
diff --git a/Lib/test/test_new.py b/Lib/test/test_new.py
--- a/Lib/test/test_new.py
+++ b/Lib/test/test_new.py
@@ -24,18 +24,10 @@ class NewTest(unittest.TestCase):
c = new.instance(C, {'yolks': 3})
o = new.instance(C)
-
- # __dict__ is a non dict mapping in Jython
- if test_support.is_jython:
- self.assertEqual(len(o.__dict__), 0, "new __dict__ should be empty")
- else:
- self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
+ self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
del o
o = new.instance(C, None)
- if test_support.is_jython:
- self.assertEqual(len(o.__dict__), 0, "new __dict__ should be empty")
- else:
- self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
+ self.assertEqual(o.__dict__, {}, "new __dict__ should be empty")
del o
def break_yolks(self):
@@ -109,7 +101,14 @@ class NewTest(unittest.TestCase):
test_closure(g, (1, 1), ValueError) # closure is wrong size
test_closure(f, g.func_closure, ValueError) # no closure needed
- if hasattr(new, 'code') and not test_support.is_jython:
+ # [Obsolete] Note: Jython will never have new.code()
+ #
+ # Who said that?!!! guess what, we do! :)
+ #
+ # Unfortunately we still need a way to compile to Python bytecode,
+ # so support is still incomplete, as seen in the fact that we need
+ # to get values from CPython 2.7.
+ if hasattr(new, 'code'):
def test_code(self):
# bogus test of new.code()
def f(a): pass
@@ -117,16 +116,16 @@ class NewTest(unittest.TestCase):
c = f.func_code
argcount = c.co_argcount
nlocals = c.co_nlocals
- stacksize = c.co_stacksize
+ stacksize = 1 # TODO c.co_stacksize
flags = c.co_flags
- codestring = c.co_code
- constants = c.co_consts
- names = c.co_names
+ codestring = 'd\x00\x00S' # TODO c.co_code
+ constants = (None,) # TODO c.co_consts
+ names = () # TODO c.co_names
varnames = c.co_varnames
filename = c.co_filename
name = c.co_name
firstlineno = c.co_firstlineno
- lnotab = c.co_lnotab
+ lnotab = '' # TODO c.co_lnotab, but also see http://bugs.jython.org/issue1638
freevars = c.co_freevars
cellvars = c.co_cellvars
diff --git a/src/org/python/core/PyBytecode.java b/src/org/python/core/PyBytecode.java
--- a/src/org/python/core/PyBytecode.java
+++ b/src/org/python/core/PyBytecode.java
@@ -66,6 +66,12 @@ public class PyBytecode extends PyBaseCo
debug = defaultDebug;
+ if (argcount < 0) {
+ throw Py.ValueError("code: argcount must not be negative");
+ } else if (nlocals < 0) {
+ throw Py.ValueError("code: nlocals must not be negative");
+ }
+
co_argcount = nargs = argcount;
co_varnames = varnames;
co_nlocals = nlocals; // maybe assert = varnames.length;
diff --git a/src/org/python/core/PyFunction.java b/src/org/python/core/PyFunction.java
--- a/src/org/python/core/PyFunction.java
+++ b/src/org/python/core/PyFunction.java
@@ -545,6 +545,9 @@ public class PyFunction extends PyObject
@Override
public boolean isSequenceType() { return false; }
+ private Object readResolve() {
+ throw new UnsupportedOperationException();
+ }
/* Traverseproc implementation */
@Override
|