Merge lp:~gz/brz/py3_static_tuple_start into lp:brz
- py3_static_tuple_start
- Merge into trunk
Proposed by
Martin Packman
Status: | Merged |
---|---|
Approved by: | Martin Packman |
Approved revision: | no longer in the source branch. |
Merge reported by: | The Breezy Bot |
Merged at revision: | not available |
Proposed branch: | lp:~gz/brz/py3_static_tuple_start |
Merge into: | lp:brz |
Diff against target: |
432 lines (+118/-103) 4 files modified
breezy/_export_c_api.h (+3/-5) breezy/_static_tuple_c.c (+61/-76) breezy/python-compat.h (+31/-0) breezy/tests/test__static_tuple.py (+23/-22) |
To merge this branch: | bzr merge lp:~gz/brz/py3_static_tuple_start |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+326117@code.launchpad.net |
Commit message
Start of making _static_tuple_c compatible with Python 3
Description of the change
This is not everything done to make StaticTuple work on Python 3, but is a reasonable checkpoint. The code compiles, runs tests, and fails in a few relevant ways. The C API level import is also broken.
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
http://
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/_export_c_api.h' |
2 | --- breezy/_export_c_api.h 2009-10-12 21:44:27 +0000 |
3 | +++ breezy/_export_c_api.h 2017-06-25 23:38:37 +0000 |
4 | @@ -15,6 +15,7 @@ |
5 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
6 | */ |
7 | |
8 | +/* GZ 2017-06-22: This header needs updating to use Capsules over CObjects */ |
9 | |
10 | /* This file contains helper functions for exporting a C API for a CPython |
11 | * extension module. |
12 | @@ -45,17 +46,14 @@ |
13 | PyObject *d = NULL; |
14 | PyObject *c_obj = NULL; |
15 | |
16 | - /* (char *) is because python2.4 declares this api as 'char *' rather than |
17 | - * const char* which it really is. |
18 | - */ |
19 | - d = PyObject_GetAttrString(module, (char *)_C_API_NAME); |
20 | + d = PyObject_GetAttrString(module, _C_API_NAME); |
21 | if (!d) { |
22 | PyErr_Clear(); |
23 | d = PyDict_New(); |
24 | if (!d) |
25 | goto bad; |
26 | Py_INCREF(d); |
27 | - if (PyModule_AddObject(module, (char *)_C_API_NAME, d) < 0) |
28 | + if (PyModule_AddObject(module, _C_API_NAME, d) < 0) |
29 | goto bad; |
30 | } |
31 | c_obj = PyCObject_FromVoidPtrAndDesc(func, signature, 0); |
32 | |
33 | === modified file 'breezy/_static_tuple_c.c' |
34 | --- breezy/_static_tuple_c.c 2017-05-21 18:10:28 +0000 |
35 | +++ breezy/_static_tuple_c.c 2017-06-25 23:38:37 +0000 |
36 | @@ -26,12 +26,6 @@ |
37 | #include "_static_tuple_c.h" |
38 | #include "_export_c_api.h" |
39 | |
40 | -/* Pyrex 0.9.6.4 exports _simple_set_pyx_api as |
41 | - * import__simple_set_pyx(), while Pyrex 0.9.8.5 and Cython 0.11.3 export them |
42 | - * as import_breezy___simple_set_pyx(). As such, we just #define one to be |
43 | - * equivalent to the other in our internal code. |
44 | - */ |
45 | -#define import__simple_set_pyx import_breezy___simple_set_pyx |
46 | #include "_simple_set_pyx_api.h" |
47 | |
48 | #if defined(__GNUC__) |
49 | @@ -242,11 +236,14 @@ |
50 | " should not have a NULL entry."); |
51 | return 0; |
52 | } |
53 | - if (PyString_CheckExact(obj) |
54 | + if (PyBytes_CheckExact(obj) |
55 | || StaticTuple_CheckExact(obj) |
56 | || obj == Py_None |
57 | || PyBool_Check(obj) |
58 | +#if PY_MAJOR_VERSION >= 3 |
59 | +#else |
60 | || PyInt_CheckExact(obj) |
61 | +#endif |
62 | || PyLong_CheckExact(obj) |
63 | || PyFloat_CheckExact(obj) |
64 | || PyUnicode_CheckExact(obj) |
65 | @@ -314,8 +311,12 @@ |
66 | if (tuple_repr == NULL) { |
67 | return NULL; |
68 | } |
69 | +#if PY_MAJOR_VERSION >= 3 |
70 | + result = PyUnicode_FromFormat("StaticTuple%U", tuple_repr); |
71 | +#else |
72 | result = PyString_FromFormat("StaticTuple%s", |
73 | PyString_AsString(tuple_repr)); |
74 | +#endif |
75 | return result; |
76 | } |
77 | |
78 | @@ -362,7 +363,7 @@ |
79 | { |
80 | PyObject *vt; |
81 | PyObject *result = NULL; |
82 | - |
83 | + |
84 | vt = StaticTuple_as_tuple((StaticTuple *)v); |
85 | if (vt == NULL) { |
86 | goto done; |
87 | @@ -478,7 +479,7 @@ |
88 | vlen = v_st->size; |
89 | wlen = w_st->size; |
90 | min_len = (vlen < wlen) ? vlen : wlen; |
91 | - string_richcompare = PyString_Type.tp_richcompare; |
92 | + string_richcompare = PyBytes_Type.tp_richcompare; |
93 | for (i = 0; i < min_len; i++) { |
94 | PyObject *result = NULL; |
95 | v_obj = StaticTuple_GET_ITEM(v_st, i); |
96 | @@ -487,7 +488,7 @@ |
97 | /* Shortcut case, these must be identical */ |
98 | continue; |
99 | } |
100 | - if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) { |
101 | + if (PyBytes_CheckExact(v_obj) && PyBytes_CheckExact(w_obj)) { |
102 | result = string_richcompare(v_obj, w_obj, Py_EQ); |
103 | } else if (StaticTuple_CheckExact(v_obj) && |
104 | StaticTuple_CheckExact(w_obj)) |
105 | @@ -547,7 +548,7 @@ |
106 | return Py_True; |
107 | } |
108 | /* It is some other comparison, go ahead and do the real check. */ |
109 | - if (PyString_CheckExact(v_obj) && PyString_CheckExact(w_obj)) |
110 | + if (PyBytes_CheckExact(v_obj) && PyBytes_CheckExact(w_obj)) |
111 | { |
112 | return string_richcompare(v_obj, w_obj, op); |
113 | } else if (StaticTuple_CheckExact(v_obj) && |
114 | @@ -679,6 +680,8 @@ |
115 | return obj; |
116 | } |
117 | |
118 | +#if PY_MAJOR_VERSION >= 3 |
119 | +#else |
120 | static PyObject * |
121 | StaticTuple_slice(StaticTuple *self, Py_ssize_t ilow, Py_ssize_t ihigh) |
122 | { |
123 | @@ -692,6 +695,21 @@ |
124 | Py_DECREF(as_tuple); |
125 | return result; |
126 | } |
127 | +#endif |
128 | + |
129 | +static PyObject * |
130 | +StaticTuple_subscript(StaticTuple *self, PyObject *key) |
131 | +{ |
132 | + PyObject *as_tuple, *result; |
133 | + |
134 | + as_tuple = StaticTuple_as_tuple(self); |
135 | + if (as_tuple == NULL) { |
136 | + return NULL; |
137 | + } |
138 | + result = PyTuple_Type.tp_as_mapping->mp_subscript(as_tuple, key); |
139 | + Py_DECREF(as_tuple); |
140 | + return result; |
141 | +} |
142 | |
143 | static int |
144 | StaticTuple_traverse(StaticTuple *self, visitproc visit, void *arg) |
145 | @@ -759,29 +777,36 @@ |
146 | 0, /* nb_or */ |
147 | 0, /* nb_coerce */ |
148 | }; |
149 | - |
150 | + |
151 | |
152 | static PySequenceMethods StaticTuple_as_sequence = { |
153 | (lenfunc)StaticTuple_length, /* sq_length */ |
154 | 0, /* sq_concat */ |
155 | 0, /* sq_repeat */ |
156 | (ssizeargfunc)StaticTuple_item, /* sq_item */ |
157 | +#if PY_MAJOR_VERSION >= 3 |
158 | +#else |
159 | (ssizessizeargfunc)StaticTuple_slice, /* sq_slice */ |
160 | +#endif |
161 | 0, /* sq_ass_item */ |
162 | 0, /* sq_ass_slice */ |
163 | 0, /* sq_contains */ |
164 | -}; |
165 | - |
166 | -/* TODO: Implement StaticTuple_as_mapping. |
167 | - * The only thing we really want to support from there is mp_subscript, |
168 | - * so that we could support extended slicing (foo[::2]). Not worth it |
169 | - * yet, though. |
170 | - */ |
171 | +#if PY_MAJOR_VERSION >= 3 |
172 | + 0, /* sq_inplace_concat */ |
173 | + 0, /* sq_inplace_repeat */ |
174 | +#endif |
175 | +}; |
176 | + |
177 | + |
178 | +static PyMappingMethods StaticTuple_as_mapping = { |
179 | + (lenfunc)StaticTuple_length, /* mp_length */ |
180 | + (binaryfunc)StaticTuple_subscript, /* mp_subscript */ |
181 | + 0, /* mp_ass_subscript */ |
182 | +}; |
183 | |
184 | |
185 | PyTypeObject StaticTuple_Type = { |
186 | - PyObject_HEAD_INIT(NULL) |
187 | - 0, /* ob_size */ |
188 | + PyVarObject_HEAD_INIT(NULL, 0) |
189 | "breezy._static_tuple_c.StaticTuple", /* tp_name */ |
190 | sizeof(StaticTuple), /* tp_basicsize */ |
191 | sizeof(PyObject *), /* tp_itemsize */ |
192 | @@ -793,7 +818,7 @@ |
193 | (reprfunc)StaticTuple_repr, /* tp_repr */ |
194 | &StaticTuple_as_number, /* tp_as_number */ |
195 | &StaticTuple_as_sequence, /* tp_as_sequence */ |
196 | - 0, /* tp_as_mapping */ |
197 | + &StaticTuple_as_mapping, /* tp_as_mapping */ |
198 | (hashfunc)StaticTuple_hash, /* tp_hash */ |
199 | 0, /* tp_call */ |
200 | 0, /* tp_str */ |
201 | @@ -887,72 +912,32 @@ |
202 | } |
203 | |
204 | |
205 | -static int |
206 | -_workaround_pyrex_096(void) |
207 | -{ |
208 | - /* Work around an incompatibility in how pyrex 0.9.6 exports a module, |
209 | - * versus how pyrex 0.9.8 and cython 0.11 export it. |
210 | - * Namely 0.9.6 exports import__simple_set_pyx and tries to |
211 | - * "import _simple_set_pyx" but it is available only as |
212 | - * "import breezy._simple_set_pyx" |
213 | - * It is a shame to hack up sys.modules, but that is what we've got to do. |
214 | - */ |
215 | - PyObject *sys_module = NULL, *modules = NULL, *set_module = NULL; |
216 | - int retval = -1; |
217 | - |
218 | - /* Clear out the current ImportError exception, and try again. */ |
219 | - PyErr_Clear(); |
220 | - /* Note that this only seems to work if somewhere else imports |
221 | - * breezy._simple_set_pyx before importing breezy._static_tuple_c |
222 | - */ |
223 | - set_module = PyImport_ImportModule("breezy._simple_set_pyx"); |
224 | - if (set_module == NULL) { |
225 | - goto end; |
226 | - } |
227 | - /* Add the _simple_set_pyx into sys.modules at the appropriate location. */ |
228 | - sys_module = PyImport_ImportModule("sys"); |
229 | - if (sys_module == NULL) { |
230 | - goto end; |
231 | - } |
232 | - modules = PyObject_GetAttrString(sys_module, "modules"); |
233 | - if (modules == NULL || !PyDict_Check(modules)) { |
234 | - goto end; |
235 | - } |
236 | - PyDict_SetItemString(modules, "_simple_set_pyx", set_module); |
237 | - /* Now that we have hacked it in, try the import again. */ |
238 | - retval = import_breezy___simple_set_pyx(); |
239 | -end: |
240 | - Py_XDECREF(set_module); |
241 | - Py_XDECREF(sys_module); |
242 | - Py_XDECREF(modules); |
243 | - return retval; |
244 | -} |
245 | - |
246 | - |
247 | -PyMODINIT_FUNC |
248 | -init_static_tuple_c(void) |
249 | +PYMOD_INIT_FUNC(_static_tuple_c) |
250 | { |
251 | PyObject* m; |
252 | |
253 | StaticTuple_Type.tp_getattro = PyObject_GenericGetAttr; |
254 | - if (PyType_Ready(&StaticTuple_Type) < 0) |
255 | - return; |
256 | + if (PyType_Ready(&StaticTuple_Type) < 0) { |
257 | + return PYMOD_ERROR; |
258 | + } |
259 | |
260 | - m = Py_InitModule3("_static_tuple_c", static_tuple_c_methods, |
261 | - "C implementation of a StaticTuple structure"); |
262 | - if (m == NULL) |
263 | - return; |
264 | + PYMOD_CREATE(m, "_static_tuple_c", |
265 | + "C implementation of a StaticTuple structure", |
266 | + static_tuple_c_methods); |
267 | + if (m == NULL) { |
268 | + return PYMOD_ERROR; |
269 | + } |
270 | |
271 | Py_INCREF(&StaticTuple_Type); |
272 | PyModule_AddObject(m, "StaticTuple", (PyObject *)&StaticTuple_Type); |
273 | - if (import_breezy___simple_set_pyx() == -1 |
274 | - && _workaround_pyrex_096() == -1) |
275 | - { |
276 | - return; |
277 | + if (import_breezy___simple_set_pyx() == -1) { |
278 | + return PYMOD_ERROR; |
279 | } |
280 | setup_interned_tuples(m); |
281 | setup_empty_tuple(m); |
282 | setup_c_api(m); |
283 | + |
284 | + return PYMOD_SUCCESS(m); |
285 | } |
286 | |
287 | // vim: tabstop=4 sw=4 expandtab |
288 | |
289 | === modified file 'breezy/python-compat.h' |
290 | --- breezy/python-compat.h 2017-06-05 23:59:08 +0000 |
291 | +++ breezy/python-compat.h 2017-06-25 23:38:37 +0000 |
292 | @@ -25,6 +25,37 @@ |
293 | #ifndef _BZR_PYTHON_COMPAT_H |
294 | #define _BZR_PYTHON_COMPAT_H |
295 | |
296 | +#if PY_MAJOR_VERSION >= 3 |
297 | + |
298 | +#define PyInt_FromSsize_t PyLong_FromSsize_t |
299 | + |
300 | +/* In Python 3 the Py_TPFLAGS_CHECKTYPES behaviour is on by default */ |
301 | +#define Py_TPFLAGS_CHECKTYPES 0 |
302 | + |
303 | +#define PYMOD_ERROR NULL |
304 | +#define PYMOD_SUCCESS(val) val |
305 | +#define PYMOD_INIT_FUNC(name) PyMODINIT_FUNC PyInit_##name(void) |
306 | +#define PYMOD_CREATE(ob, name, doc, methods) do { \ |
307 | + static struct PyModuleDef moduledef = { \ |
308 | + PyModuleDef_HEAD_INIT, name, doc, -1, methods \ |
309 | + }; \ |
310 | + ob = PyModule_Create(&moduledef); \ |
311 | + } while(0) |
312 | + |
313 | +#else |
314 | + |
315 | +#define PyBytes_Type PyString_Type |
316 | +#define PyBytes_CheckExact PyString_CheckExact |
317 | + |
318 | +#define PYMOD_ERROR |
319 | +#define PYMOD_SUCCESS(val) |
320 | +#define PYMOD_INIT_FUNC(name) void init##name(void) |
321 | +#define PYMOD_CREATE(ob, name, doc, methods) do { \ |
322 | + ob = Py_InitModule3(name, methods, doc); \ |
323 | + } while(0) |
324 | + |
325 | +#endif |
326 | + |
327 | #if defined(_WIN32) || defined(WIN32) |
328 | /* Defining WIN32_LEAN_AND_MEAN makes including windows quite a bit |
329 | * lighter weight. |
330 | |
331 | === modified file 'breezy/tests/test__static_tuple.py' |
332 | --- breezy/tests/test__static_tuple.py 2017-05-23 14:08:03 +0000 |
333 | +++ breezy/tests/test__static_tuple.py 2017-06-25 23:38:37 +0000 |
334 | @@ -16,7 +16,10 @@ |
335 | |
336 | """Tests for the StaticTuple type.""" |
337 | |
338 | -import cPickle |
339 | +try: |
340 | + import cPickle as pickle |
341 | +except ImportError: |
342 | + import pickle |
343 | import sys |
344 | |
345 | from breezy import ( |
346 | @@ -26,6 +29,10 @@ |
347 | static_tuple, |
348 | tests, |
349 | ) |
350 | +from breezy.sixish import ( |
351 | + PY3, |
352 | + text_type, |
353 | + ) |
354 | from breezy.tests import ( |
355 | features, |
356 | ) |
357 | @@ -213,6 +220,8 @@ |
358 | self.assertRaises(TypeError, self.module.StaticTuple, subint(2)) |
359 | |
360 | def test_holds_long(self): |
361 | + if PY3: |
362 | + self.skipTest("No long type on Python 3") |
363 | k1 = self.module.StaticTuple(2**65) |
364 | class sublong(long): |
365 | pass |
366 | @@ -225,15 +234,15 @@ |
367 | pass |
368 | self.assertRaises(TypeError, self.module.StaticTuple, subfloat(1.5)) |
369 | |
370 | - def test_holds_str(self): |
371 | - k1 = self.module.StaticTuple('astring') |
372 | - class substr(str): |
373 | + def test_holds_bytes(self): |
374 | + k1 = self.module.StaticTuple(b'astring') |
375 | + class substr(bytes): |
376 | pass |
377 | - self.assertRaises(TypeError, self.module.StaticTuple, substr('a')) |
378 | + self.assertRaises(TypeError, self.module.StaticTuple, substr(b'a')) |
379 | |
380 | def test_holds_unicode(self): |
381 | k1 = self.module.StaticTuple(u'\xb5') |
382 | - class subunicode(unicode): |
383 | + class subunicode(text_type): |
384 | pass |
385 | self.assertRaises(TypeError, self.module.StaticTuple, |
386 | subunicode(u'\xb5')) |
387 | @@ -416,16 +425,8 @@ |
388 | k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing') |
389 | self.assertEqual(('foo', 'bar'), k[:2]) |
390 | self.assertEqual(('baz',), k[2:-1]) |
391 | - try: |
392 | - val = k[::2] |
393 | - except TypeError: |
394 | - # C implementation raises a TypeError, we don't need the |
395 | - # implementation yet, so allow this to pass |
396 | - pass |
397 | - else: |
398 | - # Python implementation uses a regular Tuple, so make sure it gives |
399 | - # the right result |
400 | - self.assertEqual(('foo', 'baz'), val) |
401 | + self.assertEqual(('foo', 'baz',), k[::2]) |
402 | + self.assertRaises(TypeError, k.__getitem__, 'not_slice') |
403 | |
404 | def test_referents(self): |
405 | # We implement tp_traverse so that things like 'meliae' can measure the |
406 | @@ -582,20 +583,20 @@ |
407 | |
408 | def test_pickle(self): |
409 | st = self.module.StaticTuple('foo', 'bar') |
410 | - pickled = cPickle.dumps(st) |
411 | - unpickled = cPickle.loads(pickled) |
412 | + pickled = pickle.dumps(st) |
413 | + unpickled = pickle.loads(pickled) |
414 | self.assertEqual(unpickled, st) |
415 | |
416 | def test_pickle_empty(self): |
417 | st = self.module.StaticTuple() |
418 | - pickled = cPickle.dumps(st) |
419 | - unpickled = cPickle.loads(pickled) |
420 | + pickled = pickle.dumps(st) |
421 | + unpickled = pickle.loads(pickled) |
422 | self.assertIs(st, unpickled) |
423 | |
424 | def test_pickle_nested(self): |
425 | st = self.module.StaticTuple('foo', self.module.StaticTuple('bar')) |
426 | - pickled = cPickle.dumps(st) |
427 | - unpickled = cPickle.loads(pickled) |
428 | + pickled = pickle.dumps(st) |
429 | + unpickled = pickle.loads(pickled) |
430 | self.assertEqual(unpickled, st) |
431 | |
432 | def test_static_tuple_thunk(self): |
Running landing tests failed 10.242. 247.184: 8080/job/ brz-dev/ 168/
http://