Merge lp:~flacoste/storm/bug-360846 into lp:storm

Proposed by Francis J. Lacoste
Status: Rejected
Rejected by: James Henstridge
Proposed branch: lp:~flacoste/storm/bug-360846
Merge into: lp:storm
Diff against target: 3708 lines (has conflicts)
Text conflict in Makefile
Text conflict in NEWS
Text conflict in storm/__init__.py
Text conflict in storm/cextensions.c
Text conflict in storm/databases/postgres.py
Text conflict in storm/sqlobject.py
Text conflict in storm/store.py
Text conflict in storm/tracer.py
Text conflict in storm/variables.py
Text conflict in storm/zope/__init__.py
Text conflict in tests/expr.py
Text conflict in tests/store/base.py
Text conflict in tests/tracer.py
Text conflict in tests/zope/zstorm.py
To merge this branch: bzr merge lp:~flacoste/storm/bug-360846
Reviewer Review Type Date Requested Status
James Henstridge Needs Resubmitting
Review via email: mp+6271@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Francis J. Lacoste (flacoste) wrote :

Hi storm developers,

In Launchpad, we are encountering an error which isn't recognized as a disconnection error (and thus should trigger the reconnection code).

Since I didn't see tests for the existing ones, I didn't bother adding one.

Revision history for this message
James Henstridge (jamesh) wrote :

> Hi storm developers,
>
> In Launchpad, we are encountering an error which isn't recognized as a
> disconnection error (and thus should trigger the reconnection code).
>
> Since I didn't see tests for the existing ones, I didn't bother adding one.

This branch doesn't apply to Storm's trunk. It looks like you're missing about 8 months of development in the version of Storm Launchpad is using. There have been important bug fixes in that time (e.g. bug 276690), so you should seriously consider upgrading.

Looking at the diff against Launchpad's version of Storm, the change looks worth merging although it lacks a test.

IIRC, this message only occurs if you try to use the connection a second time after libpq reports that the connection was lost. Storm should be catching the first message just fine, so this probably indicates that there was some use of the underlying connection object outside of Storm that reported the initial error. You'd probably need to do the same sort of thing to test it.

review: Needs Resubmitting
Revision history for this message
Francis J. Lacoste (flacoste) wrote :

On Thursday 07 May 2009, James Henstridge wrote:
> Review: Resubmit
>
> > Hi storm developers,
> >
> > In Launchpad, we are encountering an error which isn't recognized as a
> > disconnection error (and thus should trigger the reconnection code).
> >
> > Since I didn't see tests for the existing ones, I didn't bother adding
> > one.
>
> This branch doesn't apply to Storm's trunk. It looks like you're missing
> about 8 months of development in the version of Storm Launchpad is using.
> There have been important bug fixes in that time (e.g. bug 276690), so you
> should seriously consider upgrading.
>
> Looking at the diff against Launchpad's version of Storm, the change looks
> worth merging although it lacks a test.
>
> IIRC, this message only occurs if you try to use the connection a second
> time after libpq reports that the connection was lost. Storm should be
> catching the first message just fine, so this probably indicates that there
> was some use of the underlying connection object outside of Storm that
> reported the initial error. You'd probably need to do the same sort of
> thing to test it.

I didn't found tests for the existing functionality. Are there any? I don't
mean the general reconnecting facility, but about which errors are caught. To
me this is simply another kind of these errors.

--
Francis J. Lacoste
<email address hidden>

Unmerged revisions

122. By Francis J. Lacoste

InterfaceError: connection already closed should trigger a reconnection.

121. By Launchpad PQM Bot

[rs=salgado] Backport ISQLObjectResultSet to IResultSet adapter from
 trunk.

120. By Launchpad PQM Bot

[r=flacoste][!log] Pull changes from storm's trunk.

119. By Launchpad PQM Bot

[r=flacoste][release-critical=joey] Implementation of Store.reset
 (from radix), which we're going to use after every request

118. By Launchpad PQM Bot

[r=thumper] Implement SQLObjectResultSet.__contains__()

117. By Launchpad PQM Bot

[rs=jamesh] merge Storm trunk and ~jamesh/storm/slots

116. By Launchpad PQM Bot

[rs=jamesh] merge Gustavo's need-for-speed-revenge branch. Renable
 ZStormTest.test_wb_reset test. Disable event emission in Store.flush()

115. By Launchpad PQM Bot

[rs=jamesh] merge Storm trunk to rocketfuel

114. By Launchpad PQM Bot

[r=jamesh][!log] Disable an intermittently failing test in the storm
 suite. See bug 240801.

113. By Launchpad PQM Bot

[r=jamesh] adjust PostgresConnection.is_disconnection_error() to
 accept some forms that weren't being caught

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2008-11-19 18:22:29 +0000
3+++ Makefile 2009-05-06 21:20:15 +0000
4@@ -1,3 +1,4 @@
5+<<<<<<< TREE
6 PYTHON ?= python
7
8 TEST_COMMAND = $(PYTHON) test
9@@ -28,3 +29,29 @@
10 find . -name "*~" -type f -exec rm -f {} \;
11
12 .PHONY: all build test
13+=======
14+PYTHON = python
15+
16+TEST_COMMAND = $(PYTHON) test
17+
18+STORM_POSTGRES_URI = postgres:storm_test
19+STORM_POSTGRES_HOST_URI = postgres://localhost/storm_test
20+STORM_MYSQL_URI = mysql:storm_test
21+STORM_MYSQL_HOST_URI = mysql://localhost/storm_test
22+
23+export STORM_POSTGRES_URI
24+export STORM_POSTGRES_HOST_URI
25+export STORM_MYSQL_URI
26+export STORM_MYSQL_HOST_URI
27+
28+all: build
29+
30+build:
31+ $(PYTHON) setup.py build_ext -i
32+
33+check: build
34+ # Run the tests once with cextensions and once without them.
35+ $(TEST_COMMAND) && STORM_CEXTENSIONS=1 $(TEST_COMMAND)
36+
37+.PHONY: all build test
38+>>>>>>> MERGE-SOURCE
39
40=== modified file 'NEWS'
41--- NEWS 2009-03-18 07:11:14 +0000
42+++ NEWS 2009-05-06 21:20:15 +0000
43@@ -1,3 +1,4 @@
44+<<<<<<< TREE
45 0.15 (2009-XX-XX)
46 =================
47
48@@ -67,6 +68,17 @@
49 the "GROUP BY" and "HAVING" statements.
50 - Change tests/store to keep the connection during the tests to make it
51 faster.
52+=======
53+0.13 (2008-XX-XX)
54+=================
55+
56+Improvements
57+------------
58+ - Add group_by/having methods on ResultSet objects, to allow access to
59+ the "GROUP BY" and "HAVING" statements.
60+ - Change tests/store to keep the connection during the tests to make it
61+ faster.
62+>>>>>>> MERGE-SOURCE
63 - Implemented support for plugging generic "tracers". Statement
64 debugging is now implemented using a tracer, and easily enabled
65 with storm.tracer.debug(True) (storm.database.DEBUG = True is gone).
66@@ -76,6 +88,7 @@
67 the property. The value assigned to the property is the result
68 of the validator, so the original value should be returned if
69 changing it isn't intended.
70+<<<<<<< TREE
71 - Expressions can be passed to Store.find() as well as classes. This
72 makes it possible to request individual columns from a table,
73 computed expressions or aggregates.
74@@ -97,6 +110,26 @@
75 zope.interface and transaction packages installed. This makes it
76 easier to reuse the per-thread store management and global
77 transaction handling from other web frameworks.
78+=======
79+ - Expressions can be passed to Store.find() as well as classes. This
80+ makes it possible to request individual columns from a table,
81+ computed expressions or aggregates.
82+ - Objects will be flushed in the order they become dirty by default.
83+ This means that generally the order in which Python operations are
84+ performed will be used to define the order in which flushes are done,
85+ which is generally the most expected.
86+ - The cextensions module was fixed, optimized, and improved. It's now
87+ built by default, but to actually enable it the environment variable
88+ STORM_CEXTENSIONS=1 must be defined at runtime. The module will
89+ likely be enabled by default on a future release.
90+ - ClassAlias will now cache all explicitly named aliases, to prevent
91+ the cost of rebuilding it.
92+ - Result sets and reference sets now have a __contains__() method.
93+ While code like "item in set" was previously possible, it involved
94+ iterating over the result set, which is expensive for large
95+ databases.
96+
97+>>>>>>> MERGE-SOURCE
98
99 Bug fixes
100 ---------
101@@ -115,10 +148,15 @@
102 previously raise OrderLoopError.
103 - If the remote object in a back reference is removed, the reference
104 will now be broken.
105+<<<<<<< TREE
106 - Fixed a race condition when two threads try to initialize the
107 ClassInfo for a given class at the same time.
108 - Improve handling of AUTO INCREMENT columns in the MySQL backend to
109 remove an unnecessary query when adding objects to a store.
110+=======
111+ - Fixed a race condition when two threads try to initialize the
112+ ClassInfo for a given class at the same time.
113+>>>>>>> MERGE-SOURCE
114
115
116 0.12 (2008-01-28)
117
118=== modified file 'storm/__init__.py'
119--- storm/__init__.py 2009-01-09 17:40:25 +0000
120+++ storm/__init__.py 2009-05-06 21:20:16 +0000
121@@ -19,10 +19,17 @@
122 # along with this program. If not, see <http://www.gnu.org/licenses/>.
123 #
124
125+<<<<<<< TREE
126 import os
127
128
129 version = "0.14"
130+=======
131+import os
132+
133+
134+version = "0.12"
135+>>>>>>> MERGE-SOURCE
136 version_info = tuple([int(x) for x in version.split(".")])
137
138
139
140=== modified file 'storm/cextensions.c'
141--- storm/cextensions.c 2009-02-09 16:59:07 +0000
142+++ storm/cextensions.c 2009-05-06 21:20:16 +0000
143@@ -165,86 +165,165 @@
144
145 initialized = 1;
146
147- /* Import objects from storm module */
148- module = PyImport_ImportModule("storm");
149- if (!module)
150- return 0;
151-
152- Undef = PyObject_GetAttrString(module, "Undef");
153- if (!Undef)
154- return 0;
155-
156- Py_DECREF(module);
157-
158- /* Import objects from storm.variables module */
159- module = PyImport_ImportModule("storm.variables");
160- if (!module)
161- return 0;
162-
163- raise_none_error = PyObject_GetAttrString(module, "raise_none_error");
164- if (!raise_none_error)
165- return 0;
166-
167- LazyValue = PyObject_GetAttrString(module, "LazyValue");
168- if (!LazyValue)
169- return 0;
170-
171- Py_DECREF(module);
172-
173- /* Import objects from storm.info module */
174- module = PyImport_ImportModule("storm.info");
175- if (!module)
176- return 0;
177-
178- get_cls_info = PyObject_GetAttrString(module, "get_cls_info");
179- if (!get_cls_info)
180- return 0;
181-
182- Py_DECREF(module);
183-
184- /* Import objects from storm.event module */
185- module = PyImport_ImportModule("storm.event");
186- if (!module)
187- return 0;
188-
189- EventSystem = PyObject_GetAttrString(module, "EventSystem");
190- if (!EventSystem)
191- return 0;
192-
193- Py_DECREF(module);
194-
195- /* Import objects from storm.expr module */
196- module = PyImport_ImportModule("storm.expr");
197- if (!module)
198- return 0;
199-
200- SQLRaw = PyObject_GetAttrString(module, "SQLRaw");
201- if (!SQLRaw)
202- return 0;
203-
204- SQLToken = PyObject_GetAttrString(module, "SQLToken");
205- if (!SQLToken)
206- return 0;
207-
208- State = PyObject_GetAttrString(module, "State");
209- if (!State)
210- return 0;
211-
212- CompileError = PyObject_GetAttrString(module, "CompileError");
213- if (!CompileError)
214- return 0;
215-
216- Py_DECREF(module);
217-
218- /* A few frequently used objects which are part of the fast path. */
219-
220- parenthesis_format = PyUnicode_DecodeASCII("(%s)", 4, "strict");
221- default_compile_join = PyUnicode_DecodeASCII(", ", 2, "strict");
222+<<<<<<< TREE
223+ /* Import objects from storm module */
224+ module = PyImport_ImportModule("storm");
225+ if (!module)
226+ return 0;
227+
228+ Undef = PyObject_GetAttrString(module, "Undef");
229+ if (!Undef)
230+ return 0;
231+
232+ Py_DECREF(module);
233+
234+ /* Import objects from storm.variables module */
235+ module = PyImport_ImportModule("storm.variables");
236+ if (!module)
237+ return 0;
238+
239+ raise_none_error = PyObject_GetAttrString(module, "raise_none_error");
240+ if (!raise_none_error)
241+ return 0;
242+
243+ LazyValue = PyObject_GetAttrString(module, "LazyValue");
244+ if (!LazyValue)
245+ return 0;
246+
247+ Py_DECREF(module);
248+
249+ /* Import objects from storm.info module */
250+ module = PyImport_ImportModule("storm.info");
251+ if (!module)
252+ return 0;
253+
254+ get_cls_info = PyObject_GetAttrString(module, "get_cls_info");
255+ if (!get_cls_info)
256+ return 0;
257+
258+ Py_DECREF(module);
259+
260+ /* Import objects from storm.event module */
261+ module = PyImport_ImportModule("storm.event");
262+ if (!module)
263+ return 0;
264+
265+ EventSystem = PyObject_GetAttrString(module, "EventSystem");
266+ if (!EventSystem)
267+ return 0;
268+
269+ Py_DECREF(module);
270+
271+ /* Import objects from storm.expr module */
272+ module = PyImport_ImportModule("storm.expr");
273+ if (!module)
274+ return 0;
275+
276+ SQLRaw = PyObject_GetAttrString(module, "SQLRaw");
277+ if (!SQLRaw)
278+ return 0;
279+
280+ SQLToken = PyObject_GetAttrString(module, "SQLToken");
281+ if (!SQLToken)
282+ return 0;
283+
284+ State = PyObject_GetAttrString(module, "State");
285+ if (!State)
286+ return 0;
287+
288+ CompileError = PyObject_GetAttrString(module, "CompileError");
289+ if (!CompileError)
290+ return 0;
291+
292+ Py_DECREF(module);
293+
294+ /* A few frequently used objects which are part of the fast path. */
295+
296+ parenthesis_format = PyUnicode_DecodeASCII("(%s)", 4, "strict");
297+ default_compile_join = PyUnicode_DecodeASCII(", ", 2, "strict");
298+=======
299+ /* Import objects from storm module */
300+ module = PyImport_ImportModule("storm");
301+ if (!module)
302+ return 0;
303+
304+ Undef = PyObject_GetAttrString(module, "Undef");
305+ if (!Undef)
306+ return 0;
307+
308+ Py_DECREF(module);
309+
310+ /* Import objects from storm.variables module */
311+ module = PyImport_ImportModule("storm.variables");
312+ if (!module)
313+ return 0;
314+
315+ raise_none_error = PyObject_GetAttrString(module, "raise_none_error");
316+ if (!raise_none_error)
317+ return 0;
318+
319+ LazyValue = PyObject_GetAttrString(module, "LazyValue");
320+ if (!LazyValue)
321+ return 0;
322+
323+ Py_DECREF(module);
324+
325+ /* Import objects from storm.info module */
326+ module = PyImport_ImportModule("storm.info");
327+ if (!module)
328+ return 0;
329+
330+ get_cls_info = PyObject_GetAttrString(module, "get_cls_info");
331+ if (!get_cls_info)
332+ return 0;
333+
334+ Py_DECREF(module);
335+
336+ /* Import objects from storm.event module */
337+ module = PyImport_ImportModule("storm.event");
338+ if (!module)
339+ return 0;
340+
341+ EventSystem = PyObject_GetAttrString(module, "EventSystem");
342+ if (!EventSystem)
343+ return 0;
344+
345+ Py_DECREF(module);
346+
347+ /* Import objects from storm.expr module */
348+ module = PyImport_ImportModule("storm.expr");
349+ if (!module)
350+ return 0;
351+
352+ SQLRaw = PyObject_GetAttrString(module, "SQLRaw");
353+ if (!SQLRaw)
354+ return 0;
355+
356+ SQLToken = PyObject_GetAttrString(module, "SQLToken");
357+ if (!SQLToken)
358+ return 0;
359+
360+ State = PyObject_GetAttrString(module, "State");
361+ if (!State)
362+ return 0;
363+
364+ CompileError = PyObject_GetAttrString(module, "CompileError");
365+ if (!CompileError)
366+ return 0;
367+
368+ Py_DECREF(module);
369+
370+ /* A few frequently used objects which are part of the fast path. */
371+
372+ parenthesis_format = PyUnicode_DecodeASCII("(%s)", 4, "strict");
373+ default_compile_join = PyUnicode_DecodeASCII(", ", 2, "strict");
374+>>>>>>> MERGE-SOURCE
375
376 return 1;
377 }
378
379
380+<<<<<<< TREE
381 static int
382 EventSystem_init(EventSystemObject *self, PyObject *args, PyObject *kwargs)
383 {
384@@ -554,6 +633,317 @@
385 };
386
387
388+=======
389+static int
390+EventSystem_init(EventSystemObject *self, PyObject *args, PyObject *kwargs)
391+{
392+ static char *kwlist[] = {"owner", NULL};
393+ PyObject *owner;
394+ int result = -1;
395+
396+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &owner))
397+ return -1;
398+
399+ /* self._owner_ref = weakref.ref(owner) */
400+ self->_owner_ref = PyWeakref_NewRef(owner, NULL);
401+ if (self->_owner_ref) {
402+ /* self._hooks = {} */
403+ self->_hooks = PyDict_New();
404+ if (self->_hooks) {
405+ result = 0;
406+ }
407+ }
408+
409+ return result;
410+}
411+
412+static int
413+EventSystem_traverse(EventSystemObject *self, visitproc visit, void *arg)
414+{
415+ Py_VISIT(self->_owner_ref);
416+ Py_VISIT(self->_hooks);
417+ return 0;
418+}
419+
420+static int
421+EventSystem_clear(EventSystemObject *self)
422+{
423+ Py_CLEAR(self->_owner_ref);
424+ Py_CLEAR(self->_hooks);
425+ return 0;
426+}
427+
428+static void
429+EventSystem_dealloc(EventSystemObject *self)
430+{
431+ EventSystem_clear(self);
432+ self->ob_type->tp_free((PyObject *)self);
433+}
434+
435+static PyObject *
436+EventSystem_hook(EventSystemObject *self, PyObject *args)
437+{
438+ PyObject *result = NULL;
439+ PyObject *name, *callback, *data;
440+
441+ if (PyTuple_GET_SIZE(args) < 2) {
442+ PyErr_SetString(PyExc_TypeError, "Invalid number of arguments");
443+ return NULL;
444+ }
445+
446+ name = PyTuple_GET_ITEM(args, 0);
447+ callback = PyTuple_GET_ITEM(args, 1);
448+ data = PyTuple_GetSlice(args, 2, PyTuple_GET_SIZE(args));
449+ if (data) {
450+ /*
451+ callbacks = self._hooks.get(name)
452+ if callbacks is None:
453+ self._hooks.setdefault(name, set()).add((callback, data))
454+ else:
455+ callbacks.add((callback, data))
456+ */
457+ PyObject *callbacks = PyDict_GetItem(self->_hooks, name);
458+ if (!PyErr_Occurred()) {
459+ if (callbacks == NULL) {
460+ callbacks = PySet_New(NULL);
461+ if (callbacks &&
462+ PyDict_SetItem(self->_hooks, name, callbacks) == -1) {
463+ Py_DECREF(callbacks);
464+ callbacks = NULL;
465+ }
466+ } else {
467+ Py_INCREF(callbacks);
468+ }
469+ if (callbacks) {
470+ PyObject *tuple = PyTuple_New(2);
471+ if (tuple) {
472+ Py_INCREF(callback);
473+ PyTuple_SET_ITEM(tuple, 0, callback);
474+ Py_INCREF(data);
475+ PyTuple_SET_ITEM(tuple, 1, data);
476+ if (PySet_Add(callbacks, tuple) != -1) {
477+ Py_INCREF(Py_None);
478+ result = Py_None;
479+ }
480+ Py_DECREF(tuple);
481+ }
482+ Py_DECREF(callbacks);
483+ }
484+ }
485+ Py_DECREF(data);
486+ }
487+
488+ return result;
489+}
490+
491+static PyObject *
492+EventSystem_unhook(EventSystemObject *self, PyObject *args)
493+{
494+ PyObject *result = NULL;
495+ PyObject *name, *callback, *data;
496+
497+ if (PyTuple_GET_SIZE(args) < 2) {
498+ PyErr_SetString(PyExc_TypeError, "Invalid number of arguments");
499+ return NULL;
500+ }
501+
502+ name = PyTuple_GET_ITEM(args, 0);
503+ callback = PyTuple_GET_ITEM(args, 1);
504+ data = PyTuple_GetSlice(args, 2, PyTuple_GET_SIZE(args));
505+ if (data) {
506+ /*
507+ callbacks = self._hooks.get(name)
508+ if callbacks is not None:
509+ callbacks.discard((callback, data))
510+ */
511+ PyObject *callbacks = PyDict_GetItem(self->_hooks, name);
512+ if (callbacks) {
513+ PyObject *tuple = PyTuple_New(2);
514+ if (tuple) {
515+ Py_INCREF(callback);
516+ PyTuple_SET_ITEM(tuple, 0, callback);
517+ Py_INCREF(data);
518+ PyTuple_SET_ITEM(tuple, 1, data);
519+ if (PySet_Discard(callbacks, tuple) != -1) {
520+ Py_INCREF(Py_None);
521+ result = Py_None;
522+ }
523+ Py_DECREF(tuple);
524+ }
525+ } else if (!PyErr_Occurred()) {
526+ Py_INCREF(Py_None);
527+ result = Py_None;
528+ }
529+ Py_DECREF(data);
530+ }
531+
532+ return result;
533+}
534+
535+static PyObject *
536+EventSystem__do_emit_call(PyObject *callback, PyObject *owner,
537+ PyObject *args, PyObject *data)
538+{
539+ /* return callback(owner, *(args+data)) */
540+ PyObject *result = NULL;
541+ PyObject *tuple = PyTuple_New(PyTuple_GET_SIZE(args) +
542+ PyTuple_GET_SIZE(data) + 1);
543+ if (tuple) {
544+ Py_ssize_t i, tuple_i;
545+
546+ Py_INCREF(owner);
547+ PyTuple_SET_ITEM(tuple, 0, owner);
548+ tuple_i = 1;
549+ for (i = 0; i != PyTuple_GET_SIZE(args); i++) {
550+ PyObject *item = PyTuple_GET_ITEM(args, i);
551+ Py_INCREF(item);
552+ PyTuple_SET_ITEM(tuple, tuple_i++, item);
553+ }
554+ for (i = 0; i != PyTuple_GET_SIZE(data); i++) {
555+ PyObject *item = PyTuple_GET_ITEM(data, i);
556+ Py_INCREF(item);
557+ PyTuple_SET_ITEM(tuple, tuple_i++, item);
558+ }
559+ result = PyObject_Call(callback, tuple, NULL);
560+ Py_DECREF(tuple);
561+ }
562+ return result;
563+}
564+
565+static PyObject *
566+EventSystem_emit(EventSystemObject *self, PyObject *all_args)
567+{
568+ PyObject *result = NULL;
569+ PyObject *name, *args;
570+
571+ if (PyTuple_GET_SIZE(all_args) == 0) {
572+ PyErr_SetString(PyExc_TypeError, "Invalid number of arguments");
573+ return NULL;
574+ }
575+
576+ /* XXX In the following code we trust on the format inserted by
577+ * the hook() method. If it's hacked somehow, it may blow up. */
578+
579+ name = PyTuple_GET_ITEM(all_args, 0);
580+ args = PyTuple_GetSlice(all_args, 1, PyTuple_GET_SIZE(all_args));
581+ if (args) {
582+ /* owner = self._owner_ref() */
583+ PyObject *owner = PyWeakref_GET_OBJECT(self->_owner_ref);
584+ /* if owner is not None: */
585+ if (owner != Py_None) {
586+ /* callbacks = self._hooks.get(name) */
587+ PyObject *callbacks = PyDict_GetItem(self->_hooks, name);
588+ Py_INCREF(owner);
589+ /* if callbacks: */
590+ if (callbacks && PySet_GET_SIZE(callbacks) != 0) {
591+ /* for callback, data in tuple(callbacks): */
592+ PyObject *sequence = \
593+ PySequence_Fast(callbacks, "callbacks object isn't a set");
594+ if (sequence) {
595+ int failed = 0;
596+ Py_ssize_t i;
597+ for (i = 0; i != PySequence_Fast_GET_SIZE(sequence); i++) {
598+ PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
599+ PyObject *callback = PyTuple_GET_ITEM(item, 0);
600+ PyObject *data = PyTuple_GET_ITEM(item, 1);
601+ PyObject *res;
602+ /*
603+ if callback(owner, *(args+data)) is False:
604+ callbacks.discard((callback, data))
605+ */
606+ res = EventSystem__do_emit_call(callback, owner,
607+ args, data);
608+ Py_XDECREF(res);
609+ if (res == NULL ||
610+ (res == Py_False &&
611+ PySet_Discard(callbacks, item) == -1)) {
612+ failed = 1;
613+ break;
614+ }
615+ }
616+ if (!failed) {
617+ Py_INCREF(Py_None);
618+ result = Py_None;
619+ }
620+ Py_DECREF(sequence);
621+ }
622+ } else if (!PyErr_Occurred()) {
623+ Py_INCREF(Py_None);
624+ result = Py_None;
625+ }
626+ Py_DECREF(owner);
627+ } else {
628+ Py_INCREF(Py_None);
629+ result = Py_None;
630+ }
631+ Py_DECREF(args);
632+ }
633+
634+ return result;
635+}
636+
637+
638+static PyMethodDef EventSystem_methods[] = {
639+ {"hook", (PyCFunction)EventSystem_hook, METH_VARARGS, NULL},
640+ {"unhook", (PyCFunction)EventSystem_unhook, METH_VARARGS, NULL},
641+ {"emit", (PyCFunction)EventSystem_emit, METH_VARARGS, NULL},
642+ {NULL, NULL}
643+};
644+
645+#define OFFSETOF(x) offsetof(EventSystemObject, x)
646+static PyMemberDef EventSystem_members[] = {
647+ {"_object_ref", T_OBJECT, OFFSETOF(_owner_ref), READONLY, 0},
648+ {"_hooks", T_OBJECT, OFFSETOF(_hooks), READONLY, 0},
649+ {NULL}
650+};
651+#undef OFFSETOF
652+
653+statichere PyTypeObject EventSystem_Type = {
654+ PyObject_HEAD_INIT(NULL)
655+ 0, /*ob_size*/
656+ "storm.variables.EventSystem", /*tp_name*/
657+ sizeof(EventSystemObject), /*tp_basicsize*/
658+ 0, /*tp_itemsize*/
659+ (destructor)EventSystem_dealloc, /*tp_dealloc*/
660+ 0, /*tp_print*/
661+ 0, /*tp_getattr*/
662+ 0, /*tp_setattr*/
663+ 0, /*tp_compare*/
664+ 0, /*tp_repr*/
665+ 0, /*tp_as_number*/
666+ 0, /*tp_as_sequence*/
667+ 0, /*tp_as_mapping*/
668+ 0, /*tp_hash*/
669+ 0, /*tp_call*/
670+ 0, /*tp_str*/
671+ PyObject_GenericGetAttr,/*tp_getattro*/
672+ PyObject_GenericSetAttr,/*tp_setattro*/
673+ 0, /*tp_as_buffer*/
674+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
675+ 0, /*tp_doc*/
676+ (traverseproc)EventSystem_traverse, /*tp_traverse*/
677+ (inquiry)EventSystem_clear, /*tp_clear*/
678+ 0, /*tp_richcompare*/
679+ 0, /*tp_weaklistoffset*/
680+ 0, /*tp_iter*/
681+ 0, /*tp_iternext*/
682+ EventSystem_methods, /*tp_methods*/
683+ EventSystem_members, /*tp_members*/
684+ 0, /*tp_getset*/
685+ 0, /*tp_base*/
686+ 0, /*tp_dict*/
687+ 0, /*tp_descr_get*/
688+ 0, /*tp_descr_set*/
689+ 0, /*tp_dictoffset*/
690+ (initproc)EventSystem_init, /*tp_init*/
691+ PyType_GenericAlloc, /*tp_alloc*/
692+ PyType_GenericNew, /*tp_new*/
693+ PyObject_GC_Del, /*tp_free*/
694+ 0, /*tp_is_gc*/
695+};
696+
697+
698+>>>>>>> MERGE-SOURCE
699 static PyObject *
700 Variable_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
701 {
702@@ -1150,670 +1540,1337 @@
703
704
705 static PyObject *
706-Compile__update_cache(CompileObject *self, PyObject *args);
707-
708-static int
709-Compile_init(CompileObject *self, PyObject *args, PyObject *kwargs)
710-{
711- static char *kwlist[] = {"parent", NULL};
712-
713- PyObject *parent = Py_None;
714-
715- PyObject *module = NULL;
716- PyObject *WeakKeyDictionary = NULL;
717-
718- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &parent))
719- return -1;
720-
721- /*
722- self._local_dispatch_table = {}
723- self._local_precedence = {}
724- self._local_reserved_words = {}
725- self._dispatch_table = {}
726- self._precedence = {}
727- self._reserved_words = {}
728- */
729- CATCH(NULL, self->_local_dispatch_table = PyDict_New());
730- CATCH(NULL, self->_local_precedence = PyDict_New());
731- CATCH(NULL, self->_local_reserved_words = PyDict_New());
732- CATCH(NULL, self->_dispatch_table = PyDict_New());
733- CATCH(NULL, self->_precedence = PyDict_New());
734- CATCH(NULL, self->_reserved_words = PyDict_New());
735-
736- /* self._children = WeakKeyDictionary() */
737- CATCH(NULL, module = PyImport_ImportModule("weakref"));
738- CATCH(NULL, WeakKeyDictionary = \
739- PyObject_GetAttrString(module, "WeakKeyDictionary"));
740- Py_CLEAR(module);
741- CATCH(NULL, self->_children = \
742- PyObject_CallFunctionObjArgs(WeakKeyDictionary, NULL));
743- Py_CLEAR(WeakKeyDictionary);
744-
745- /* self._parents = [] */
746- CATCH(NULL, self->_parents = PyList_New(0));
747-
748- /* if parent: */
749- if (parent != Py_None) {
750- PyObject *tmp;
751-
752- /* self._parents.extend(parent._parents) */
753- CompileObject *parent_object = (CompileObject *)parent;
754- CATCH(-1, PyList_SetSlice(self->_parents, 0, 0,
755- parent_object->_parents));
756-
757- /* self._parents.append(parent) */
758- CATCH(-1, PyList_Append(self->_parents, parent));
759-
760- /* parent._children[self] = True */
761- CATCH(-1, PyObject_SetItem(parent_object->_children,
762- (PyObject *)self, Py_True));
763-
764- /* self._update_cache() */
765- CATCH(NULL, tmp = Compile__update_cache(self, NULL));
766- Py_DECREF(tmp);
767- }
768-
769- return 0;
770-
771-error:
772- Py_XDECREF(module);
773- Py_XDECREF(WeakKeyDictionary);
774- return -1;
775-}
776-
777-static int
778-Compile_traverse(CompileObject *self, visitproc visit, void *arg)
779-{
780- Py_VISIT(self->_local_dispatch_table);
781- Py_VISIT(self->_local_precedence);
782- Py_VISIT(self->_local_reserved_words);
783- Py_VISIT(self->_dispatch_table);
784- Py_VISIT(self->_precedence);
785- Py_VISIT(self->_reserved_words);
786- Py_VISIT(self->_children);
787- Py_VISIT(self->_parents);
788- return 0;
789-}
790-
791-static int
792-Compile_clear(CompileObject *self)
793-{
794- if (self->__weakreflist)
795- PyObject_ClearWeakRefs((PyObject *)self);
796- Py_CLEAR(self->_local_dispatch_table);
797- Py_CLEAR(self->_local_precedence);
798- Py_CLEAR(self->_local_reserved_words);
799- Py_CLEAR(self->_dispatch_table);
800- Py_CLEAR(self->_precedence);
801- Py_CLEAR(self->_reserved_words);
802- Py_CLEAR(self->_children);
803- Py_CLEAR(self->_parents);
804- return 0;
805-}
806-
807-static void
808-Compile_dealloc(CompileObject *self)
809-{
810- Compile_clear(self);
811- self->ob_type->tp_free((PyObject *)self);
812-}
813-
814-static PyObject *
815-Compile__update_cache(CompileObject *self, PyObject *args)
816-{
817- PyObject *iter = NULL;
818- PyObject *child = NULL;
819- Py_ssize_t size;
820- int i;
821-
822- /* for parent in self._parents: */
823- size = PyList_GET_SIZE(self->_parents);
824- for (i = 0; i != size; i++) {
825- CompileObject *parent = \
826- (CompileObject *)PyList_GET_ITEM(self->_parents, i);
827- /* self._dispatch_table.update(parent._local_dispatch_table) */
828- CATCH(-1, PyDict_Update(self->_dispatch_table,
829- parent->_local_dispatch_table));
830- /* self._precedence.update(parent._local_precedence) */
831- CATCH(-1, PyDict_Update(self->_precedence,
832- parent->_local_precedence));
833- /* self._reserved_words.update(parent._local_reserved_words) */
834- CATCH(-1, PyDict_Update(self->_reserved_words,
835- parent->_local_reserved_words));
836- }
837- /* self._dispatch_table.update(self._local_dispatch_table) */
838- CATCH(-1, PyDict_Update(self->_dispatch_table,
839- self->_local_dispatch_table));
840- /* self._precedence.update(self._local_precedence) */
841- CATCH(-1, PyDict_Update(self->_precedence, self->_local_precedence));
842- /* self._reserved_words.update(self._local_reserved_words) */
843- CATCH(-1, PyDict_Update(self->_reserved_words,
844- self->_local_reserved_words));
845-
846- /* for child in self._children: */
847- CATCH(NULL, iter = PyObject_GetIter(self->_children));
848- while((child = PyIter_Next(iter))) {
849- PyObject *tmp;
850-
851- /* child._update_cache() */
852- CATCH(NULL, tmp = Compile__update_cache((CompileObject *)child, NULL));
853- Py_DECREF(tmp);
854- Py_DECREF(child);
855- }
856- if (PyErr_Occurred())
857- goto error;
858- Py_CLEAR(iter);
859-
860- Py_RETURN_NONE;
861-
862-error:
863- Py_XDECREF(child);
864- Py_XDECREF(iter);
865- return NULL;
866-}
867-
868-static PyObject *
869-Compile_when(CompileObject *self, PyObject *types)
870-{
871- PyObject *result = NULL;
872- PyObject *module = PyImport_ImportModule("storm.expr");
873- if (module) {
874- PyObject *_when = PyObject_GetAttrString(module, "_when");
875- if (_when) {
876- result = PyObject_CallFunctionObjArgs(_when, self, types, NULL);
877- Py_DECREF(_when);
878- }
879- Py_DECREF(module);
880- }
881- return result;
882-}
883-
884-static PyObject *
885-Compile_add_reserved_words(CompileObject *self, PyObject *words)
886-{
887- PyObject *lower_word = NULL;
888- PyObject *iter = NULL;
889- PyObject *word = NULL;
890- PyObject *tmp;
891-
892- /* self._local_reserved_words.update((word.lower(), True)
893- for word in words) */
894- CATCH(NULL, iter = PyObject_GetIter(words));
895- while ((word = PyIter_Next(iter))) {
896- CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
897- CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
898- lower_word, Py_True));
899- Py_CLEAR(lower_word);
900- Py_DECREF(word);
901- }
902- if (PyErr_Occurred())
903- goto error;
904- Py_CLEAR(iter);
905-
906- /* self._update_cache() */
907- CATCH(NULL, tmp = Compile__update_cache(self, NULL));
908- Py_DECREF(tmp);
909-
910- Py_RETURN_NONE;
911-
912-error:
913- Py_XDECREF(lower_word);
914- Py_XDECREF(word);
915- Py_XDECREF(iter);
916- return NULL;
917-}
918-
919-static PyObject *
920-Compile_remove_reserved_words(CompileObject *self, PyObject *words)
921-{
922- PyObject *lower_word = NULL;
923- PyObject *word = NULL;
924- PyObject *iter = NULL;
925- PyObject *tmp;
926-
927- /* self._local_reserved_words.update((word.lower(), None)
928- for word in words) */
929- CATCH(NULL, iter = PyObject_GetIter(words));
930- while ((word = PyIter_Next(iter))) {
931- CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
932- CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
933- lower_word, Py_None));
934- Py_CLEAR(lower_word);
935- Py_DECREF(word);
936- }
937- if (PyErr_Occurred())
938- goto error;
939- Py_CLEAR(iter);
940-
941- /* self._update_cache() */
942- CATCH(NULL, tmp = Compile__update_cache(self, NULL));
943- Py_DECREF(tmp);
944-
945- Py_RETURN_NONE;
946-
947-error:
948- Py_XDECREF(lower_word);
949- Py_XDECREF(word);
950- Py_XDECREF(iter);
951- return NULL;
952-}
953-
954-static PyObject *
955-Compile_is_reserved_word(CompileObject *self, PyObject *word)
956-{
957- PyObject *lower_word = NULL;
958- PyObject *result = Py_False;
959- PyObject *item;
960-
961- /* return self._reserved_words.get(word.lower()) is not None */
962- CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
963- item = PyDict_GetItem(self->_reserved_words, lower_word);
964- if (item == NULL && PyErr_Occurred()) {
965- goto error;
966- } else if (item != NULL && item != Py_None) {
967- result = Py_True;
968- }
969- Py_DECREF(lower_word);
970- Py_INCREF(result);
971- return result;
972-
973-error:
974- Py_XDECREF(lower_word);
975- return NULL;
976-}
977-
978-staticforward PyTypeObject Compile_Type;
979-
980-static PyObject *
981-Compile_create_child(CompileObject *self, PyObject *args)
982-{
983- /* return self.__class__(self) */
984- return PyObject_CallFunctionObjArgs((PyObject *)self->ob_type, self, NULL);
985-}
986-
987-static PyObject *
988-Compile_get_precedence(CompileObject *self, PyObject *type)
989-{
990- /* return self._precedence.get(type, MAX_PRECEDENCE) */
991- PyObject *result = PyDict_GetItem(self->_precedence, type);
992- if (result == NULL && !PyErr_Occurred()) {
993- /* That should be MAX_PRECEDENCE, defined in expr.py */
994- return PyInt_FromLong(1000);
995- }
996- Py_INCREF(result);
997- return result;
998-}
999-
1000-static PyObject *
1001-Compile_set_precedence(CompileObject *self, PyObject *args)
1002-{
1003- Py_ssize_t size = PyTuple_GET_SIZE(args);
1004- PyObject *precedence = NULL;
1005- PyObject *tmp;
1006- int i;
1007-
1008- if (size < 2) {
1009- PyErr_SetString(PyExc_TypeError,
1010- "set_precedence() takes at least 2 arguments.");
1011- return NULL;
1012- }
1013-
1014- /* for type in types: */
1015- precedence = PyTuple_GET_ITEM(args, 0);
1016- for (i = 1; i != size; i++) {
1017- PyObject *type = PyTuple_GET_ITEM(args, i);
1018- /* self._local_precedence[type] = precedence */
1019- CATCH(-1, PyDict_SetItem(self->_local_precedence, type, precedence));
1020- }
1021-
1022- /* self._update_cache() */
1023- CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1024- Py_DECREF(tmp);
1025-
1026- Py_RETURN_NONE;
1027-error:
1028- return NULL;
1029-}
1030-
1031-PyObject *
1032-Compile_single(CompileObject *self,
1033- PyObject *expr, PyObject *state, PyObject *outer_precedence)
1034-{
1035- PyObject *inner_precedence = NULL;
1036- PyObject *statement = NULL;
1037-
1038- /* cls = expr.__class__ */
1039- PyObject *cls = (PyObject *)expr->ob_type;
1040-
1041- /*
1042- dispatch_table = self._dispatch_table
1043- if cls in dispatch_table:
1044- handler = dispatch_table[cls]
1045- else:
1046- */
1047- PyObject *handler = PyDict_GetItem(self->_dispatch_table, cls);
1048- if (!handler) {
1049- PyObject *mro;
1050- Py_ssize_t size, i;
1051-
1052- if (PyErr_Occurred())
1053- goto error;
1054-
1055- /* for mro_cls in cls.__mro__: */
1056- mro = expr->ob_type->tp_mro;
1057- size = PyTuple_GET_SIZE(mro);
1058- for (i = 0; i != size; i++) {
1059- PyObject *mro_cls = PyTuple_GET_ITEM(mro, i);
1060- /*
1061- if mro_cls in dispatch_table:
1062- handler = dispatch_table[mro_cls]
1063- break
1064- */
1065- handler = PyDict_GetItem(self->_dispatch_table, mro_cls);
1066- if (handler)
1067- break;
1068-
1069- if (PyErr_Occurred())
1070- goto error;
1071- }
1072- /* else: */
1073- if (i == size) {
1074- /*
1075- raise CompileError("Don't know how to compile type %r of %r"
1076- % (expr.__class__, expr))
1077- */
1078- PyObject *repr = PyObject_Repr(expr);
1079- if (repr) {
1080- PyErr_Format(CompileError,
1081- "Don't know how to compile type %s of %s",
1082- expr->ob_type->tp_name, PyString_AS_STRING(repr));
1083- Py_DECREF(repr);
1084- }
1085- goto error;
1086- }
1087- }
1088-
1089- /*
1090- inner_precedence = state.precedence = \
1091- self._precedence.get(cls, MAX_PRECEDENCE)
1092- */
1093- CATCH(NULL, inner_precedence = Compile_get_precedence(self, cls));
1094- CATCH(-1, PyObject_SetAttrString(state, "precedence", inner_precedence));
1095-
1096- /* statement = handler(self, expr, state) */
1097- CATCH(NULL, statement = PyObject_CallFunctionObjArgs(handler, self, expr,
1098- state, NULL));
1099-
1100- /* if inner_precedence < outer_precedence: */
1101- if (PyObject_Compare(inner_precedence, outer_precedence) == -1) {
1102- PyObject *args, *tmp;
1103-
1104- if (PyErr_Occurred())
1105- goto error;
1106-
1107- /* return "(%s)" % statement */
1108- CATCH(NULL, args = PyTuple_Pack(1, statement));
1109- tmp = PyUnicode_Format(parenthesis_format, args);
1110- Py_DECREF(args);
1111- CATCH(NULL, tmp);
1112- Py_DECREF(statement);
1113- statement = tmp;
1114- }
1115-
1116- Py_DECREF(inner_precedence);
1117-
1118- return statement;
1119-
1120-error:
1121- Py_XDECREF(inner_precedence);
1122- Py_XDECREF(statement);
1123-
1124- return NULL;
1125-}
1126-
1127-PyObject *
1128-Compile_one_or_many(CompileObject *self, PyObject *expr, PyObject *state,
1129- PyObject *join, int raw, int token)
1130-{
1131- PyObject *outer_precedence = NULL;
1132- PyObject *compiled = NULL;
1133- PyObject *sequence = NULL;
1134- PyObject *statement = NULL;
1135- Py_ssize_t size, i;
1136-
1137- Py_INCREF(expr);
1138-
1139- /*
1140- expr_type = type(expr)
1141- if (expr_type is SQLRaw or
1142- raw and (expr_type is str or expr_type is unicode)):
1143- return expr
1144- */
1145- if ((PyObject *)expr->ob_type == SQLRaw ||
1146- (raw && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr)))) {
1147- /* Pass our reference on. */
1148- return expr;
1149- }
1150-
1151- /*
1152- if token and (expr_type is str or expr_type is unicode):
1153- expr = SQLToken(expr)
1154- */
1155- if (token && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr))) {
1156- PyObject *tmp;
1157- CATCH(NULL, tmp = PyObject_CallFunctionObjArgs(SQLToken, expr, NULL));
1158- Py_DECREF(expr);
1159- expr = tmp;
1160- }
1161-
1162- /*
1163- if state is None:
1164- state = State()
1165- */
1166- /* That's done in Compile__call__ just once. */
1167-
1168- /* outer_precedence = state.precedence */
1169- CATCH(NULL, outer_precedence = PyObject_GetAttrString(state, "precedence"));
1170- /* if expr_type is tuple or expr_type is list: */
1171- if (PyTuple_CheckExact(expr) || PyList_CheckExact(expr)) {
1172- /* compiled = [] */
1173- CATCH(NULL, compiled = PyList_New(0));
1174-
1175- /* for subexpr in expr: */
1176- sequence = PySequence_Fast(expr, "This can't actually fail! ;-)");
1177- size = PySequence_Fast_GET_SIZE(sequence);
1178- for (i = 0; i != size; i++) {
1179- PyObject *subexpr = PySequence_Fast_GET_ITEM(sequence, i);
1180- /*
1181- subexpr_type = type(subexpr)
1182- if subexpr_type is SQLRaw or raw and (subexpr_type is str or
1183- subexpr_type is unicode):
1184- */
1185- if ((PyObject *)subexpr->ob_type == (PyObject *)SQLRaw ||
1186- (raw && (PyString_CheckExact(subexpr) ||
1187- PyUnicode_CheckExact(subexpr)))) {
1188- /* statement = subexpr */
1189- Py_INCREF(subexpr);
1190- statement = subexpr;
1191- /* elif subexpr_type is tuple or subexpr_type is list: */
1192- } else if (PyTuple_CheckExact(subexpr) ||
1193- PyList_CheckExact(subexpr)) {
1194- /* state.precedence = outer_precedence */
1195- CATCH(-1, PyObject_SetAttrString(state, "precedence",
1196- outer_precedence));
1197- /* statement = self(subexpr, state, join, raw, token) */
1198- CATCH(NULL,
1199- statement = Compile_one_or_many(self, subexpr, state,
1200- join, raw, token));
1201- /* else: */
1202- } else {
1203- /*
1204- if token and (subexpr_type is unicode or
1205- subexpr_type is str):
1206- */
1207- if (token && (PyUnicode_CheckExact(subexpr) ||
1208- PyString_CheckExact(subexpr))) {
1209- /* subexpr = SQLToken(subexpr) */
1210- CATCH(NULL,
1211- subexpr = PyObject_CallFunctionObjArgs(SQLToken,
1212- subexpr,
1213- NULL));
1214- } else {
1215- Py_INCREF(subexpr);
1216- }
1217-
1218- /*
1219- statement = self._compile_single(subexpr, state,
1220- outer_precedence)
1221- */
1222- statement = Compile_single(self, subexpr, state,
1223- outer_precedence);
1224- Py_DECREF(subexpr);
1225- CATCH(NULL, statement);
1226- }
1227-
1228- /* compiled.append(statement) */
1229- CATCH(-1, PyList_Append(compiled, statement));
1230- Py_CLEAR(statement);
1231- }
1232- Py_CLEAR(sequence);
1233-
1234- /* statement = join.join(compiled) */
1235- CATCH(NULL, statement = PyUnicode_Join(join, compiled));
1236- Py_CLEAR(compiled);
1237- } else {
1238- /* statement = self._compile_single(expr, state, outer_precedence) */
1239- CATCH(NULL, statement = Compile_single(self, expr, state,
1240- outer_precedence));
1241- }
1242-
1243- /* state.precedence = outer_precedence */
1244- CATCH(-1, PyObject_SetAttrString(state, "precedence", outer_precedence));
1245- Py_CLEAR(outer_precedence);
1246-
1247- Py_DECREF(expr);
1248-
1249- return statement;
1250-
1251-error:
1252- Py_XDECREF(expr);
1253- Py_XDECREF(outer_precedence);
1254- Py_XDECREF(compiled);
1255- Py_XDECREF(sequence);
1256- Py_XDECREF(statement);
1257-
1258- return NULL;
1259-}
1260-
1261-static PyObject *
1262-Compile__call__(CompileObject *self, PyObject *args, PyObject *kwargs)
1263-{
1264- static char *kwlist[] = {"expr", "state", "join", "raw", "token", NULL};
1265- PyObject *expr = NULL;
1266- PyObject *state = Py_None;
1267- PyObject *join;
1268- char raw = 0;
1269- char token = 0;
1270-
1271- PyObject *result = NULL;
1272-
1273- if (!initialize_globals())
1274- return NULL;
1275-
1276- join = default_compile_join;
1277-
1278- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OSbb", kwlist,
1279- &expr, &state, &join, &raw, &token)) {
1280- return NULL;
1281- }
1282-
1283- if (state == Py_None) {
1284- state = PyObject_CallFunctionObjArgs(State, NULL);
1285- } else {
1286- Py_INCREF(state);
1287- }
1288- if (state) {
1289- result = Compile_one_or_many(self, expr, state, join, raw, token);
1290- Py_DECREF(state);
1291- }
1292- return result;
1293-}
1294-
1295-
1296-static PyMethodDef Compile_methods[] = {
1297- {"_update_cache", (PyCFunction)Compile__update_cache, METH_NOARGS, NULL},
1298- {"when", (PyCFunction)Compile_when, METH_VARARGS, NULL},
1299- {"add_reserved_words", (PyCFunction)Compile_add_reserved_words,
1300- METH_O, NULL},
1301- {"remove_reserved_words", (PyCFunction)Compile_remove_reserved_words,
1302- METH_O, NULL},
1303- {"is_reserved_word", (PyCFunction)Compile_is_reserved_word, METH_O, NULL},
1304- {"create_child", (PyCFunction)Compile_create_child, METH_NOARGS, NULL},
1305- {"get_precedence", (PyCFunction)Compile_get_precedence, METH_O, NULL},
1306- {"set_precedence", (PyCFunction)Compile_set_precedence, METH_VARARGS, NULL},
1307- {NULL, NULL}
1308-};
1309-
1310-#define OFFSETOF(x) offsetof(CompileObject, x)
1311-static PyMemberDef Compile_members[] = {
1312- {"_local_dispatch_table", T_OBJECT, OFFSETOF(_local_dispatch_table), 0, 0},
1313- {"_local_precedence", T_OBJECT, OFFSETOF(_local_precedence), 0, 0},
1314- {"_local_reserved_words", T_OBJECT, OFFSETOF(_local_reserved_words), 0, 0},
1315- {"_dispatch_table", T_OBJECT, OFFSETOF(_dispatch_table), 0, 0},
1316- {"_precedence", T_OBJECT, OFFSETOF(_precedence), 0, 0},
1317- {"_reserved_words", T_OBJECT, OFFSETOF(_reserved_words), 0, 0},
1318- {"_children", T_OBJECT, OFFSETOF(_children), 0, 0},
1319- {"_parents", T_OBJECT, OFFSETOF(_parents), 0, 0},
1320- {NULL}
1321-};
1322-#undef OFFSETOF
1323-
1324-statichere PyTypeObject Compile_Type = {
1325- PyObject_HEAD_INIT(NULL)
1326- 0, /*ob_size*/
1327- "storm.variables.Compile", /*tp_name*/
1328- sizeof(CompileObject), /*tp_basicsize*/
1329- 0, /*tp_itemsize*/
1330- (destructor)Compile_dealloc, /*tp_dealloc*/
1331- 0, /*tp_print*/
1332- 0, /*tp_getattr*/
1333- 0, /*tp_setattr*/
1334- 0, /*tp_compare*/
1335- 0, /*tp_repr*/
1336- 0, /*tp_as_number*/
1337- 0, /*tp_as_sequence*/
1338- 0, /*tp_as_mapping*/
1339- 0, /*tp_hash*/
1340- (ternaryfunc)Compile__call__, /*tp_call*/
1341- 0, /*tp_str*/
1342- PyObject_GenericGetAttr,/*tp_getattro*/
1343- PyObject_GenericSetAttr,/*tp_setattro*/
1344- 0, /*tp_as_buffer*/
1345- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
1346- 0, /*tp_doc*/
1347- (traverseproc)Compile_traverse, /*tp_traverse*/
1348- (inquiry)Compile_clear, /*tp_clear*/
1349- 0, /*tp_richcompare*/
1350- offsetof(CompileObject, __weakreflist), /*tp_weaklistoffset*/
1351- 0, /*tp_iter*/
1352- 0, /*tp_iternext*/
1353- Compile_methods, /*tp_methods*/
1354- Compile_members, /*tp_members*/
1355- 0, /*tp_getset*/
1356- 0, /*tp_base*/
1357- 0, /*tp_dict*/
1358- 0, /*tp_descr_get*/
1359- 0, /*tp_descr_set*/
1360- 0, /*tp_dictoffset*/
1361- (initproc)Compile_init, /*tp_init*/
1362- PyType_GenericAlloc, /*tp_alloc*/
1363- PyType_GenericNew, /*tp_new*/
1364- PyObject_GC_Del, /*tp_free*/
1365- 0, /*tp_is_gc*/
1366-};
1367-
1368-
1369-static PyObject *
1370+<<<<<<< TREE
1371+Compile__update_cache(CompileObject *self, PyObject *args);
1372+
1373+static int
1374+Compile_init(CompileObject *self, PyObject *args, PyObject *kwargs)
1375+{
1376+ static char *kwlist[] = {"parent", NULL};
1377+
1378+ PyObject *parent = Py_None;
1379+
1380+ PyObject *module = NULL;
1381+ PyObject *WeakKeyDictionary = NULL;
1382+
1383+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &parent))
1384+ return -1;
1385+
1386+ /*
1387+ self._local_dispatch_table = {}
1388+ self._local_precedence = {}
1389+ self._local_reserved_words = {}
1390+ self._dispatch_table = {}
1391+ self._precedence = {}
1392+ self._reserved_words = {}
1393+ */
1394+ CATCH(NULL, self->_local_dispatch_table = PyDict_New());
1395+ CATCH(NULL, self->_local_precedence = PyDict_New());
1396+ CATCH(NULL, self->_local_reserved_words = PyDict_New());
1397+ CATCH(NULL, self->_dispatch_table = PyDict_New());
1398+ CATCH(NULL, self->_precedence = PyDict_New());
1399+ CATCH(NULL, self->_reserved_words = PyDict_New());
1400+
1401+ /* self._children = WeakKeyDictionary() */
1402+ CATCH(NULL, module = PyImport_ImportModule("weakref"));
1403+ CATCH(NULL, WeakKeyDictionary = \
1404+ PyObject_GetAttrString(module, "WeakKeyDictionary"));
1405+ Py_CLEAR(module);
1406+ CATCH(NULL, self->_children = \
1407+ PyObject_CallFunctionObjArgs(WeakKeyDictionary, NULL));
1408+ Py_CLEAR(WeakKeyDictionary);
1409+
1410+ /* self._parents = [] */
1411+ CATCH(NULL, self->_parents = PyList_New(0));
1412+
1413+ /* if parent: */
1414+ if (parent != Py_None) {
1415+ PyObject *tmp;
1416+
1417+ /* self._parents.extend(parent._parents) */
1418+ CompileObject *parent_object = (CompileObject *)parent;
1419+ CATCH(-1, PyList_SetSlice(self->_parents, 0, 0,
1420+ parent_object->_parents));
1421+
1422+ /* self._parents.append(parent) */
1423+ CATCH(-1, PyList_Append(self->_parents, parent));
1424+
1425+ /* parent._children[self] = True */
1426+ CATCH(-1, PyObject_SetItem(parent_object->_children,
1427+ (PyObject *)self, Py_True));
1428+
1429+ /* self._update_cache() */
1430+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1431+ Py_DECREF(tmp);
1432+ }
1433+
1434+ return 0;
1435+
1436+error:
1437+ Py_XDECREF(module);
1438+ Py_XDECREF(WeakKeyDictionary);
1439+ return -1;
1440+}
1441+
1442+static int
1443+Compile_traverse(CompileObject *self, visitproc visit, void *arg)
1444+{
1445+ Py_VISIT(self->_local_dispatch_table);
1446+ Py_VISIT(self->_local_precedence);
1447+ Py_VISIT(self->_local_reserved_words);
1448+ Py_VISIT(self->_dispatch_table);
1449+ Py_VISIT(self->_precedence);
1450+ Py_VISIT(self->_reserved_words);
1451+ Py_VISIT(self->_children);
1452+ Py_VISIT(self->_parents);
1453+ return 0;
1454+}
1455+
1456+static int
1457+Compile_clear(CompileObject *self)
1458+{
1459+ if (self->__weakreflist)
1460+ PyObject_ClearWeakRefs((PyObject *)self);
1461+ Py_CLEAR(self->_local_dispatch_table);
1462+ Py_CLEAR(self->_local_precedence);
1463+ Py_CLEAR(self->_local_reserved_words);
1464+ Py_CLEAR(self->_dispatch_table);
1465+ Py_CLEAR(self->_precedence);
1466+ Py_CLEAR(self->_reserved_words);
1467+ Py_CLEAR(self->_children);
1468+ Py_CLEAR(self->_parents);
1469+ return 0;
1470+}
1471+
1472+static void
1473+Compile_dealloc(CompileObject *self)
1474+{
1475+ Compile_clear(self);
1476+ self->ob_type->tp_free((PyObject *)self);
1477+}
1478+
1479+static PyObject *
1480+Compile__update_cache(CompileObject *self, PyObject *args)
1481+{
1482+ PyObject *iter = NULL;
1483+ PyObject *child = NULL;
1484+ Py_ssize_t size;
1485+ int i;
1486+
1487+ /* for parent in self._parents: */
1488+ size = PyList_GET_SIZE(self->_parents);
1489+ for (i = 0; i != size; i++) {
1490+ CompileObject *parent = \
1491+ (CompileObject *)PyList_GET_ITEM(self->_parents, i);
1492+ /* self._dispatch_table.update(parent._local_dispatch_table) */
1493+ CATCH(-1, PyDict_Update(self->_dispatch_table,
1494+ parent->_local_dispatch_table));
1495+ /* self._precedence.update(parent._local_precedence) */
1496+ CATCH(-1, PyDict_Update(self->_precedence,
1497+ parent->_local_precedence));
1498+ /* self._reserved_words.update(parent._local_reserved_words) */
1499+ CATCH(-1, PyDict_Update(self->_reserved_words,
1500+ parent->_local_reserved_words));
1501+ }
1502+ /* self._dispatch_table.update(self._local_dispatch_table) */
1503+ CATCH(-1, PyDict_Update(self->_dispatch_table,
1504+ self->_local_dispatch_table));
1505+ /* self._precedence.update(self._local_precedence) */
1506+ CATCH(-1, PyDict_Update(self->_precedence, self->_local_precedence));
1507+ /* self._reserved_words.update(self._local_reserved_words) */
1508+ CATCH(-1, PyDict_Update(self->_reserved_words,
1509+ self->_local_reserved_words));
1510+
1511+ /* for child in self._children: */
1512+ CATCH(NULL, iter = PyObject_GetIter(self->_children));
1513+ while((child = PyIter_Next(iter))) {
1514+ PyObject *tmp;
1515+
1516+ /* child._update_cache() */
1517+ CATCH(NULL, tmp = Compile__update_cache((CompileObject *)child, NULL));
1518+ Py_DECREF(tmp);
1519+ Py_DECREF(child);
1520+ }
1521+ if (PyErr_Occurred())
1522+ goto error;
1523+ Py_CLEAR(iter);
1524+
1525+ Py_RETURN_NONE;
1526+
1527+error:
1528+ Py_XDECREF(child);
1529+ Py_XDECREF(iter);
1530+ return NULL;
1531+}
1532+
1533+static PyObject *
1534+Compile_when(CompileObject *self, PyObject *types)
1535+{
1536+ PyObject *result = NULL;
1537+ PyObject *module = PyImport_ImportModule("storm.expr");
1538+ if (module) {
1539+ PyObject *_when = PyObject_GetAttrString(module, "_when");
1540+ if (_when) {
1541+ result = PyObject_CallFunctionObjArgs(_when, self, types, NULL);
1542+ Py_DECREF(_when);
1543+ }
1544+ Py_DECREF(module);
1545+ }
1546+ return result;
1547+}
1548+
1549+static PyObject *
1550+Compile_add_reserved_words(CompileObject *self, PyObject *words)
1551+{
1552+ PyObject *lower_word = NULL;
1553+ PyObject *iter = NULL;
1554+ PyObject *word = NULL;
1555+ PyObject *tmp;
1556+
1557+ /* self._local_reserved_words.update((word.lower(), True)
1558+ for word in words) */
1559+ CATCH(NULL, iter = PyObject_GetIter(words));
1560+ while ((word = PyIter_Next(iter))) {
1561+ CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
1562+ CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
1563+ lower_word, Py_True));
1564+ Py_CLEAR(lower_word);
1565+ Py_DECREF(word);
1566+ }
1567+ if (PyErr_Occurred())
1568+ goto error;
1569+ Py_CLEAR(iter);
1570+
1571+ /* self._update_cache() */
1572+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1573+ Py_DECREF(tmp);
1574+
1575+ Py_RETURN_NONE;
1576+
1577+error:
1578+ Py_XDECREF(lower_word);
1579+ Py_XDECREF(word);
1580+ Py_XDECREF(iter);
1581+ return NULL;
1582+}
1583+
1584+static PyObject *
1585+Compile_remove_reserved_words(CompileObject *self, PyObject *words)
1586+{
1587+ PyObject *lower_word = NULL;
1588+ PyObject *word = NULL;
1589+ PyObject *iter = NULL;
1590+ PyObject *tmp;
1591+
1592+ /* self._local_reserved_words.update((word.lower(), None)
1593+ for word in words) */
1594+ CATCH(NULL, iter = PyObject_GetIter(words));
1595+ while ((word = PyIter_Next(iter))) {
1596+ CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
1597+ CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
1598+ lower_word, Py_None));
1599+ Py_CLEAR(lower_word);
1600+ Py_DECREF(word);
1601+ }
1602+ if (PyErr_Occurred())
1603+ goto error;
1604+ Py_CLEAR(iter);
1605+
1606+ /* self._update_cache() */
1607+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1608+ Py_DECREF(tmp);
1609+
1610+ Py_RETURN_NONE;
1611+
1612+error:
1613+ Py_XDECREF(lower_word);
1614+ Py_XDECREF(word);
1615+ Py_XDECREF(iter);
1616+ return NULL;
1617+}
1618+
1619+static PyObject *
1620+Compile_is_reserved_word(CompileObject *self, PyObject *word)
1621+{
1622+ PyObject *lower_word = NULL;
1623+ PyObject *result = Py_False;
1624+ PyObject *item;
1625+
1626+ /* return self._reserved_words.get(word.lower()) is not None */
1627+ CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
1628+ item = PyDict_GetItem(self->_reserved_words, lower_word);
1629+ if (item == NULL && PyErr_Occurred()) {
1630+ goto error;
1631+ } else if (item != NULL && item != Py_None) {
1632+ result = Py_True;
1633+ }
1634+ Py_DECREF(lower_word);
1635+ Py_INCREF(result);
1636+ return result;
1637+
1638+error:
1639+ Py_XDECREF(lower_word);
1640+ return NULL;
1641+}
1642+
1643+staticforward PyTypeObject Compile_Type;
1644+
1645+static PyObject *
1646+Compile_create_child(CompileObject *self, PyObject *args)
1647+{
1648+ /* return self.__class__(self) */
1649+ return PyObject_CallFunctionObjArgs((PyObject *)self->ob_type, self, NULL);
1650+}
1651+
1652+static PyObject *
1653+Compile_get_precedence(CompileObject *self, PyObject *type)
1654+{
1655+ /* return self._precedence.get(type, MAX_PRECEDENCE) */
1656+ PyObject *result = PyDict_GetItem(self->_precedence, type);
1657+ if (result == NULL && !PyErr_Occurred()) {
1658+ /* That should be MAX_PRECEDENCE, defined in expr.py */
1659+ return PyInt_FromLong(1000);
1660+ }
1661+ Py_INCREF(result);
1662+ return result;
1663+}
1664+
1665+static PyObject *
1666+Compile_set_precedence(CompileObject *self, PyObject *args)
1667+{
1668+ Py_ssize_t size = PyTuple_GET_SIZE(args);
1669+ PyObject *precedence = NULL;
1670+ PyObject *tmp;
1671+ int i;
1672+
1673+ if (size < 2) {
1674+ PyErr_SetString(PyExc_TypeError,
1675+ "set_precedence() takes at least 2 arguments.");
1676+ return NULL;
1677+ }
1678+
1679+ /* for type in types: */
1680+ precedence = PyTuple_GET_ITEM(args, 0);
1681+ for (i = 1; i != size; i++) {
1682+ PyObject *type = PyTuple_GET_ITEM(args, i);
1683+ /* self._local_precedence[type] = precedence */
1684+ CATCH(-1, PyDict_SetItem(self->_local_precedence, type, precedence));
1685+ }
1686+
1687+ /* self._update_cache() */
1688+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
1689+ Py_DECREF(tmp);
1690+
1691+ Py_RETURN_NONE;
1692+error:
1693+ return NULL;
1694+}
1695+
1696+PyObject *
1697+Compile_single(CompileObject *self,
1698+ PyObject *expr, PyObject *state, PyObject *outer_precedence)
1699+{
1700+ PyObject *inner_precedence = NULL;
1701+ PyObject *statement = NULL;
1702+
1703+ /* cls = expr.__class__ */
1704+ PyObject *cls = (PyObject *)expr->ob_type;
1705+
1706+ /*
1707+ dispatch_table = self._dispatch_table
1708+ if cls in dispatch_table:
1709+ handler = dispatch_table[cls]
1710+ else:
1711+ */
1712+ PyObject *handler = PyDict_GetItem(self->_dispatch_table, cls);
1713+ if (!handler) {
1714+ PyObject *mro;
1715+ Py_ssize_t size, i;
1716+
1717+ if (PyErr_Occurred())
1718+ goto error;
1719+
1720+ /* for mro_cls in cls.__mro__: */
1721+ mro = expr->ob_type->tp_mro;
1722+ size = PyTuple_GET_SIZE(mro);
1723+ for (i = 0; i != size; i++) {
1724+ PyObject *mro_cls = PyTuple_GET_ITEM(mro, i);
1725+ /*
1726+ if mro_cls in dispatch_table:
1727+ handler = dispatch_table[mro_cls]
1728+ break
1729+ */
1730+ handler = PyDict_GetItem(self->_dispatch_table, mro_cls);
1731+ if (handler)
1732+ break;
1733+
1734+ if (PyErr_Occurred())
1735+ goto error;
1736+ }
1737+ /* else: */
1738+ if (i == size) {
1739+ /*
1740+ raise CompileError("Don't know how to compile type %r of %r"
1741+ % (expr.__class__, expr))
1742+ */
1743+ PyObject *repr = PyObject_Repr(expr);
1744+ if (repr) {
1745+ PyErr_Format(CompileError,
1746+ "Don't know how to compile type %s of %s",
1747+ expr->ob_type->tp_name, PyString_AS_STRING(repr));
1748+ Py_DECREF(repr);
1749+ }
1750+ goto error;
1751+ }
1752+ }
1753+
1754+ /*
1755+ inner_precedence = state.precedence = \
1756+ self._precedence.get(cls, MAX_PRECEDENCE)
1757+ */
1758+ CATCH(NULL, inner_precedence = Compile_get_precedence(self, cls));
1759+ CATCH(-1, PyObject_SetAttrString(state, "precedence", inner_precedence));
1760+
1761+ /* statement = handler(self, expr, state) */
1762+ CATCH(NULL, statement = PyObject_CallFunctionObjArgs(handler, self, expr,
1763+ state, NULL));
1764+
1765+ /* if inner_precedence < outer_precedence: */
1766+ if (PyObject_Compare(inner_precedence, outer_precedence) == -1) {
1767+ PyObject *args, *tmp;
1768+
1769+ if (PyErr_Occurred())
1770+ goto error;
1771+
1772+ /* return "(%s)" % statement */
1773+ CATCH(NULL, args = PyTuple_Pack(1, statement));
1774+ tmp = PyUnicode_Format(parenthesis_format, args);
1775+ Py_DECREF(args);
1776+ CATCH(NULL, tmp);
1777+ Py_DECREF(statement);
1778+ statement = tmp;
1779+ }
1780+
1781+ Py_DECREF(inner_precedence);
1782+
1783+ return statement;
1784+
1785+error:
1786+ Py_XDECREF(inner_precedence);
1787+ Py_XDECREF(statement);
1788+
1789+ return NULL;
1790+}
1791+
1792+PyObject *
1793+Compile_one_or_many(CompileObject *self, PyObject *expr, PyObject *state,
1794+ PyObject *join, int raw, int token)
1795+{
1796+ PyObject *outer_precedence = NULL;
1797+ PyObject *compiled = NULL;
1798+ PyObject *sequence = NULL;
1799+ PyObject *statement = NULL;
1800+ Py_ssize_t size, i;
1801+
1802+ Py_INCREF(expr);
1803+
1804+ /*
1805+ expr_type = type(expr)
1806+ if (expr_type is SQLRaw or
1807+ raw and (expr_type is str or expr_type is unicode)):
1808+ return expr
1809+ */
1810+ if ((PyObject *)expr->ob_type == SQLRaw ||
1811+ (raw && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr)))) {
1812+ /* Pass our reference on. */
1813+ return expr;
1814+ }
1815+
1816+ /*
1817+ if token and (expr_type is str or expr_type is unicode):
1818+ expr = SQLToken(expr)
1819+ */
1820+ if (token && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr))) {
1821+ PyObject *tmp;
1822+ CATCH(NULL, tmp = PyObject_CallFunctionObjArgs(SQLToken, expr, NULL));
1823+ Py_DECREF(expr);
1824+ expr = tmp;
1825+ }
1826+
1827+ /*
1828+ if state is None:
1829+ state = State()
1830+ */
1831+ /* That's done in Compile__call__ just once. */
1832+
1833+ /* outer_precedence = state.precedence */
1834+ CATCH(NULL, outer_precedence = PyObject_GetAttrString(state, "precedence"));
1835+ /* if expr_type is tuple or expr_type is list: */
1836+ if (PyTuple_CheckExact(expr) || PyList_CheckExact(expr)) {
1837+ /* compiled = [] */
1838+ CATCH(NULL, compiled = PyList_New(0));
1839+
1840+ /* for subexpr in expr: */
1841+ sequence = PySequence_Fast(expr, "This can't actually fail! ;-)");
1842+ size = PySequence_Fast_GET_SIZE(sequence);
1843+ for (i = 0; i != size; i++) {
1844+ PyObject *subexpr = PySequence_Fast_GET_ITEM(sequence, i);
1845+ /*
1846+ subexpr_type = type(subexpr)
1847+ if subexpr_type is SQLRaw or raw and (subexpr_type is str or
1848+ subexpr_type is unicode):
1849+ */
1850+ if ((PyObject *)subexpr->ob_type == (PyObject *)SQLRaw ||
1851+ (raw && (PyString_CheckExact(subexpr) ||
1852+ PyUnicode_CheckExact(subexpr)))) {
1853+ /* statement = subexpr */
1854+ Py_INCREF(subexpr);
1855+ statement = subexpr;
1856+ /* elif subexpr_type is tuple or subexpr_type is list: */
1857+ } else if (PyTuple_CheckExact(subexpr) ||
1858+ PyList_CheckExact(subexpr)) {
1859+ /* state.precedence = outer_precedence */
1860+ CATCH(-1, PyObject_SetAttrString(state, "precedence",
1861+ outer_precedence));
1862+ /* statement = self(subexpr, state, join, raw, token) */
1863+ CATCH(NULL,
1864+ statement = Compile_one_or_many(self, subexpr, state,
1865+ join, raw, token));
1866+ /* else: */
1867+ } else {
1868+ /*
1869+ if token and (subexpr_type is unicode or
1870+ subexpr_type is str):
1871+ */
1872+ if (token && (PyUnicode_CheckExact(subexpr) ||
1873+ PyString_CheckExact(subexpr))) {
1874+ /* subexpr = SQLToken(subexpr) */
1875+ CATCH(NULL,
1876+ subexpr = PyObject_CallFunctionObjArgs(SQLToken,
1877+ subexpr,
1878+ NULL));
1879+ } else {
1880+ Py_INCREF(subexpr);
1881+ }
1882+
1883+ /*
1884+ statement = self._compile_single(subexpr, state,
1885+ outer_precedence)
1886+ */
1887+ statement = Compile_single(self, subexpr, state,
1888+ outer_precedence);
1889+ Py_DECREF(subexpr);
1890+ CATCH(NULL, statement);
1891+ }
1892+
1893+ /* compiled.append(statement) */
1894+ CATCH(-1, PyList_Append(compiled, statement));
1895+ Py_CLEAR(statement);
1896+ }
1897+ Py_CLEAR(sequence);
1898+
1899+ /* statement = join.join(compiled) */
1900+ CATCH(NULL, statement = PyUnicode_Join(join, compiled));
1901+ Py_CLEAR(compiled);
1902+ } else {
1903+ /* statement = self._compile_single(expr, state, outer_precedence) */
1904+ CATCH(NULL, statement = Compile_single(self, expr, state,
1905+ outer_precedence));
1906+ }
1907+
1908+ /* state.precedence = outer_precedence */
1909+ CATCH(-1, PyObject_SetAttrString(state, "precedence", outer_precedence));
1910+ Py_CLEAR(outer_precedence);
1911+
1912+ Py_DECREF(expr);
1913+
1914+ return statement;
1915+
1916+error:
1917+ Py_XDECREF(expr);
1918+ Py_XDECREF(outer_precedence);
1919+ Py_XDECREF(compiled);
1920+ Py_XDECREF(sequence);
1921+ Py_XDECREF(statement);
1922+
1923+ return NULL;
1924+}
1925+
1926+static PyObject *
1927+Compile__call__(CompileObject *self, PyObject *args, PyObject *kwargs)
1928+{
1929+ static char *kwlist[] = {"expr", "state", "join", "raw", "token", NULL};
1930+ PyObject *expr = NULL;
1931+ PyObject *state = Py_None;
1932+ PyObject *join;
1933+ char raw = 0;
1934+ char token = 0;
1935+
1936+ PyObject *result = NULL;
1937+
1938+ if (!initialize_globals())
1939+ return NULL;
1940+
1941+ join = default_compile_join;
1942+
1943+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OSbb", kwlist,
1944+ &expr, &state, &join, &raw, &token)) {
1945+ return NULL;
1946+ }
1947+
1948+ if (state == Py_None) {
1949+ state = PyObject_CallFunctionObjArgs(State, NULL);
1950+ } else {
1951+ Py_INCREF(state);
1952+ }
1953+ if (state) {
1954+ result = Compile_one_or_many(self, expr, state, join, raw, token);
1955+ Py_DECREF(state);
1956+ }
1957+ return result;
1958+}
1959+
1960+
1961+static PyMethodDef Compile_methods[] = {
1962+ {"_update_cache", (PyCFunction)Compile__update_cache, METH_NOARGS, NULL},
1963+ {"when", (PyCFunction)Compile_when, METH_VARARGS, NULL},
1964+ {"add_reserved_words", (PyCFunction)Compile_add_reserved_words,
1965+ METH_O, NULL},
1966+ {"remove_reserved_words", (PyCFunction)Compile_remove_reserved_words,
1967+ METH_O, NULL},
1968+ {"is_reserved_word", (PyCFunction)Compile_is_reserved_word, METH_O, NULL},
1969+ {"create_child", (PyCFunction)Compile_create_child, METH_NOARGS, NULL},
1970+ {"get_precedence", (PyCFunction)Compile_get_precedence, METH_O, NULL},
1971+ {"set_precedence", (PyCFunction)Compile_set_precedence, METH_VARARGS, NULL},
1972+ {NULL, NULL}
1973+};
1974+
1975+#define OFFSETOF(x) offsetof(CompileObject, x)
1976+static PyMemberDef Compile_members[] = {
1977+ {"_local_dispatch_table", T_OBJECT, OFFSETOF(_local_dispatch_table), 0, 0},
1978+ {"_local_precedence", T_OBJECT, OFFSETOF(_local_precedence), 0, 0},
1979+ {"_local_reserved_words", T_OBJECT, OFFSETOF(_local_reserved_words), 0, 0},
1980+ {"_dispatch_table", T_OBJECT, OFFSETOF(_dispatch_table), 0, 0},
1981+ {"_precedence", T_OBJECT, OFFSETOF(_precedence), 0, 0},
1982+ {"_reserved_words", T_OBJECT, OFFSETOF(_reserved_words), 0, 0},
1983+ {"_children", T_OBJECT, OFFSETOF(_children), 0, 0},
1984+ {"_parents", T_OBJECT, OFFSETOF(_parents), 0, 0},
1985+ {NULL}
1986+};
1987+#undef OFFSETOF
1988+
1989+statichere PyTypeObject Compile_Type = {
1990+ PyObject_HEAD_INIT(NULL)
1991+ 0, /*ob_size*/
1992+ "storm.variables.Compile", /*tp_name*/
1993+ sizeof(CompileObject), /*tp_basicsize*/
1994+ 0, /*tp_itemsize*/
1995+ (destructor)Compile_dealloc, /*tp_dealloc*/
1996+ 0, /*tp_print*/
1997+ 0, /*tp_getattr*/
1998+ 0, /*tp_setattr*/
1999+ 0, /*tp_compare*/
2000+ 0, /*tp_repr*/
2001+ 0, /*tp_as_number*/
2002+ 0, /*tp_as_sequence*/
2003+ 0, /*tp_as_mapping*/
2004+ 0, /*tp_hash*/
2005+ (ternaryfunc)Compile__call__, /*tp_call*/
2006+ 0, /*tp_str*/
2007+ PyObject_GenericGetAttr,/*tp_getattro*/
2008+ PyObject_GenericSetAttr,/*tp_setattro*/
2009+ 0, /*tp_as_buffer*/
2010+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2011+ 0, /*tp_doc*/
2012+ (traverseproc)Compile_traverse, /*tp_traverse*/
2013+ (inquiry)Compile_clear, /*tp_clear*/
2014+ 0, /*tp_richcompare*/
2015+ offsetof(CompileObject, __weakreflist), /*tp_weaklistoffset*/
2016+ 0, /*tp_iter*/
2017+ 0, /*tp_iternext*/
2018+ Compile_methods, /*tp_methods*/
2019+ Compile_members, /*tp_members*/
2020+ 0, /*tp_getset*/
2021+ 0, /*tp_base*/
2022+ 0, /*tp_dict*/
2023+ 0, /*tp_descr_get*/
2024+ 0, /*tp_descr_set*/
2025+ 0, /*tp_dictoffset*/
2026+ (initproc)Compile_init, /*tp_init*/
2027+ PyType_GenericAlloc, /*tp_alloc*/
2028+ PyType_GenericNew, /*tp_new*/
2029+ PyObject_GC_Del, /*tp_free*/
2030+ 0, /*tp_is_gc*/
2031+};
2032+
2033+
2034+static PyObject *
2035+=======
2036+Compile__update_cache(CompileObject *self, PyObject *args);
2037+
2038+static int
2039+Compile_init(CompileObject *self, PyObject *args, PyObject *kwargs)
2040+{
2041+ static char *kwlist[] = {"parent", NULL};
2042+
2043+ PyObject *parent = Py_None;
2044+
2045+ PyObject *module = NULL;
2046+ PyObject *WeakKeyDictionary = NULL;
2047+
2048+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &parent))
2049+ return -1;
2050+
2051+ /*
2052+ self._local_dispatch_table = {}
2053+ self._local_precedence = {}
2054+ self._local_reserved_words = {}
2055+ self._dispatch_table = {}
2056+ self._precedence = {}
2057+ self._reserved_words = {}
2058+ */
2059+ CATCH(NULL, self->_local_dispatch_table = PyDict_New());
2060+ CATCH(NULL, self->_local_precedence = PyDict_New());
2061+ CATCH(NULL, self->_local_reserved_words = PyDict_New());
2062+ CATCH(NULL, self->_dispatch_table = PyDict_New());
2063+ CATCH(NULL, self->_precedence = PyDict_New());
2064+ CATCH(NULL, self->_reserved_words = PyDict_New());
2065+
2066+ /* self._children = WeakKeyDictionary() */
2067+ CATCH(NULL, module = PyImport_ImportModule("weakref"));
2068+ CATCH(NULL, WeakKeyDictionary = \
2069+ PyObject_GetAttrString(module, "WeakKeyDictionary"));
2070+ Py_CLEAR(module);
2071+ CATCH(NULL, self->_children = \
2072+ PyObject_CallFunctionObjArgs(WeakKeyDictionary, NULL));
2073+ Py_CLEAR(WeakKeyDictionary);
2074+
2075+ /* self._parents = [] */
2076+ CATCH(NULL, self->_parents = PyList_New(0));
2077+
2078+ /* if parent: */
2079+ if (parent != Py_None) {
2080+ PyObject *tmp;
2081+
2082+ /* self._parents.extend(parent._parents) */
2083+ CompileObject *parent_object = (CompileObject *)parent;
2084+ CATCH(-1, PyList_SetSlice(self->_parents, 0, 0,
2085+ parent_object->_parents));
2086+
2087+ /* self._parents.append(parent) */
2088+ CATCH(-1, PyList_Append(self->_parents, parent));
2089+
2090+ /* parent._children[self] = True */
2091+ CATCH(-1, PyObject_SetItem(parent_object->_children,
2092+ (PyObject *)self, Py_True));
2093+
2094+ /* self._update_cache() */
2095+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
2096+ Py_DECREF(tmp);
2097+ }
2098+
2099+ return 0;
2100+
2101+error:
2102+ Py_XDECREF(module);
2103+ Py_XDECREF(WeakKeyDictionary);
2104+ return -1;
2105+}
2106+
2107+static int
2108+Compile_traverse(CompileObject *self, visitproc visit, void *arg)
2109+{
2110+ Py_VISIT(self->_local_dispatch_table);
2111+ Py_VISIT(self->_local_precedence);
2112+ Py_VISIT(self->_local_reserved_words);
2113+ Py_VISIT(self->_dispatch_table);
2114+ Py_VISIT(self->_precedence);
2115+ Py_VISIT(self->_reserved_words);
2116+ Py_VISIT(self->_children);
2117+ Py_VISIT(self->_parents);
2118+ return 0;
2119+}
2120+
2121+static int
2122+Compile_clear(CompileObject *self)
2123+{
2124+ if (self->__weakreflist)
2125+ PyObject_ClearWeakRefs((PyObject *)self);
2126+ Py_CLEAR(self->_local_dispatch_table);
2127+ Py_CLEAR(self->_local_precedence);
2128+ Py_CLEAR(self->_local_reserved_words);
2129+ Py_CLEAR(self->_dispatch_table);
2130+ Py_CLEAR(self->_precedence);
2131+ Py_CLEAR(self->_reserved_words);
2132+ Py_CLEAR(self->_children);
2133+ Py_CLEAR(self->_parents);
2134+ return 0;
2135+}
2136+
2137+static void
2138+Compile_dealloc(CompileObject *self)
2139+{
2140+ Compile_clear(self);
2141+ self->ob_type->tp_free((PyObject *)self);
2142+}
2143+
2144+static PyObject *
2145+Compile__update_cache(CompileObject *self, PyObject *args)
2146+{
2147+ PyObject *iter = NULL;
2148+ PyObject *child = NULL;
2149+ Py_ssize_t size;
2150+ int i;
2151+
2152+ /* for parent in self._parents: */
2153+ size = PyList_GET_SIZE(self->_parents);
2154+ for (i = 0; i != size; i++) {
2155+ CompileObject *parent = \
2156+ (CompileObject *)PyList_GET_ITEM(self->_parents, i);
2157+ /* self._dispatch_table.update(parent._local_dispatch_table) */
2158+ CATCH(-1, PyDict_Update(self->_dispatch_table,
2159+ parent->_local_dispatch_table));
2160+ /* self._precedence.update(parent._local_precedence) */
2161+ CATCH(-1, PyDict_Update(self->_precedence,
2162+ parent->_local_precedence));
2163+ /* self._reserved_words.update(parent._local_reserved_words) */
2164+ CATCH(-1, PyDict_Update(self->_reserved_words,
2165+ parent->_local_reserved_words));
2166+ }
2167+ /* self._dispatch_table.update(self._local_dispatch_table) */
2168+ CATCH(-1, PyDict_Update(self->_dispatch_table,
2169+ self->_local_dispatch_table));
2170+ /* self._precedence.update(self._local_precedence) */
2171+ CATCH(-1, PyDict_Update(self->_precedence, self->_local_precedence));
2172+ /* self._reserved_words.update(self._local_reserved_words) */
2173+ CATCH(-1, PyDict_Update(self->_reserved_words,
2174+ self->_local_reserved_words));
2175+
2176+ /* for child in self._children: */
2177+ CATCH(NULL, iter = PyObject_GetIter(self->_children));
2178+ while((child = PyIter_Next(iter))) {
2179+ PyObject *tmp;
2180+
2181+ /* child._update_cache() */
2182+ CATCH(NULL, tmp = Compile__update_cache((CompileObject *)child, NULL));
2183+ Py_DECREF(tmp);
2184+ Py_DECREF(child);
2185+ }
2186+ if (PyErr_Occurred())
2187+ goto error;
2188+ Py_CLEAR(iter);
2189+
2190+ Py_RETURN_NONE;
2191+
2192+error:
2193+ Py_XDECREF(child);
2194+ Py_XDECREF(iter);
2195+ return NULL;
2196+}
2197+
2198+static PyObject *
2199+Compile_when(CompileObject *self, PyObject *types)
2200+{
2201+ PyObject *result = NULL;
2202+ PyObject *module = PyImport_ImportModule("storm.expr");
2203+ if (module) {
2204+ PyObject *_when = PyObject_GetAttrString(module, "_when");
2205+ if (_when) {
2206+ result = PyObject_CallFunctionObjArgs(_when, self, types, NULL);
2207+ Py_DECREF(_when);
2208+ }
2209+ Py_DECREF(module);
2210+ }
2211+ return result;
2212+}
2213+
2214+static PyObject *
2215+Compile_add_reserved_words(CompileObject *self, PyObject *words)
2216+{
2217+ PyObject *lower_word = NULL;
2218+ PyObject *iter = NULL;
2219+ PyObject *word = NULL;
2220+ PyObject *tmp;
2221+
2222+ /* self._local_reserved_words.update((word.lower(), True)
2223+ for word in words) */
2224+ CATCH(NULL, iter = PyObject_GetIter(words));
2225+ while ((word = PyIter_Next(iter))) {
2226+ CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
2227+ CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
2228+ lower_word, Py_True));
2229+ Py_CLEAR(lower_word);
2230+ Py_DECREF(word);
2231+ }
2232+ if (PyErr_Occurred())
2233+ goto error;
2234+ Py_CLEAR(iter);
2235+
2236+ /* self._update_cache() */
2237+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
2238+ Py_DECREF(tmp);
2239+
2240+ Py_RETURN_NONE;
2241+
2242+error:
2243+ Py_XDECREF(lower_word);
2244+ Py_XDECREF(word);
2245+ Py_XDECREF(iter);
2246+ return NULL;
2247+}
2248+
2249+static PyObject *
2250+Compile_remove_reserved_words(CompileObject *self, PyObject *words)
2251+{
2252+ PyObject *lower_word = NULL;
2253+ PyObject *word = NULL;
2254+ PyObject *iter = NULL;
2255+ PyObject *tmp;
2256+
2257+ /* self._local_reserved_words.update((word.lower(), None)
2258+ for word in words) */
2259+ CATCH(NULL, iter = PyObject_GetIter(words));
2260+ while ((word = PyIter_Next(iter))) {
2261+ CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
2262+ CATCH(-1, PyDict_SetItem(self->_local_reserved_words,
2263+ lower_word, Py_None));
2264+ Py_CLEAR(lower_word);
2265+ Py_DECREF(word);
2266+ }
2267+ if (PyErr_Occurred())
2268+ goto error;
2269+ Py_CLEAR(iter);
2270+
2271+ /* self._update_cache() */
2272+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
2273+ Py_DECREF(tmp);
2274+
2275+ Py_RETURN_NONE;
2276+
2277+error:
2278+ Py_XDECREF(lower_word);
2279+ Py_XDECREF(word);
2280+ Py_XDECREF(iter);
2281+ return NULL;
2282+}
2283+
2284+static PyObject *
2285+Compile_is_reserved_word(CompileObject *self, PyObject *word)
2286+{
2287+ PyObject *lower_word = NULL;
2288+ PyObject *result = Py_False;
2289+ PyObject *item;
2290+
2291+ /* return self._reserved_words.get(word.lower()) is not None */
2292+ CATCH(NULL, lower_word = PyObject_CallMethod(word, "lower", NULL));
2293+ item = PyDict_GetItem(self->_reserved_words, lower_word);
2294+ if (item == NULL && PyErr_Occurred()) {
2295+ goto error;
2296+ } else if (item != NULL && item != Py_None) {
2297+ result = Py_True;
2298+ }
2299+ Py_DECREF(lower_word);
2300+ Py_INCREF(result);
2301+ return result;
2302+
2303+error:
2304+ Py_XDECREF(lower_word);
2305+ return NULL;
2306+}
2307+
2308+staticforward PyTypeObject Compile_Type;
2309+
2310+static PyObject *
2311+Compile_create_child(CompileObject *self, PyObject *args)
2312+{
2313+ /* return self.__class__(self) */
2314+ return PyObject_CallFunctionObjArgs((PyObject *)self->ob_type, self, NULL);
2315+}
2316+
2317+static PyObject *
2318+Compile_get_precedence(CompileObject *self, PyObject *type)
2319+{
2320+ /* return self._precedence.get(type, MAX_PRECEDENCE) */
2321+ PyObject *result = PyDict_GetItem(self->_precedence, type);
2322+ if (result == NULL && !PyErr_Occurred()) {
2323+ /* That should be MAX_PRECEDENCE, defined in expr.py */
2324+ return PyInt_FromLong(1000);
2325+ }
2326+ Py_INCREF(result);
2327+ return result;
2328+}
2329+
2330+static PyObject *
2331+Compile_set_precedence(CompileObject *self, PyObject *args)
2332+{
2333+ Py_ssize_t size = PyTuple_GET_SIZE(args);
2334+ PyObject *precedence = NULL;
2335+ PyObject *tmp;
2336+ int i;
2337+
2338+ if (size < 2) {
2339+ PyErr_SetString(PyExc_TypeError,
2340+ "set_precedence() takes at least 2 arguments.");
2341+ return NULL;
2342+ }
2343+
2344+ /* for type in types: */
2345+ precedence = PyTuple_GET_ITEM(args, 0);
2346+ for (i = 1; i != size; i++) {
2347+ PyObject *type = PyTuple_GET_ITEM(args, i);
2348+ /* self._local_precedence[type] = precedence */
2349+ CATCH(-1, PyDict_SetItem(self->_local_precedence, type, precedence));
2350+ }
2351+
2352+ /* self._update_cache() */
2353+ CATCH(NULL, tmp = Compile__update_cache(self, NULL));
2354+ Py_DECREF(tmp);
2355+
2356+ Py_RETURN_NONE;
2357+error:
2358+ return NULL;
2359+}
2360+
2361+PyObject *
2362+Compile_single(CompileObject *self,
2363+ PyObject *expr, PyObject *state, PyObject *outer_precedence)
2364+{
2365+ PyObject *inner_precedence = NULL;
2366+ PyObject *statement = NULL;
2367+
2368+ /* cls = expr.__class__ */
2369+ PyObject *cls = (PyObject *)expr->ob_type;
2370+
2371+ /*
2372+ dispatch_table = self._dispatch_table
2373+ if cls in dispatch_table:
2374+ handler = dispatch_table[cls]
2375+ else:
2376+ */
2377+ PyObject *handler = PyDict_GetItem(self->_dispatch_table, cls);
2378+ if (!handler) {
2379+ PyObject *mro;
2380+ Py_ssize_t size, i;
2381+
2382+ if (PyErr_Occurred())
2383+ goto error;
2384+
2385+ /* for mro_cls in cls.__mro__: */
2386+ mro = expr->ob_type->tp_mro;
2387+ size = PyTuple_GET_SIZE(mro);
2388+ for (i = 0; i != size; i++) {
2389+ PyObject *mro_cls = PyTuple_GET_ITEM(mro, i);
2390+ /*
2391+ if mro_cls in dispatch_table:
2392+ handler = dispatch_table[mro_cls]
2393+ break
2394+ */
2395+ handler = PyDict_GetItem(self->_dispatch_table, mro_cls);
2396+ if (handler)
2397+ break;
2398+
2399+ if (PyErr_Occurred())
2400+ goto error;
2401+ }
2402+ /* else: */
2403+ if (i == size) {
2404+ /*
2405+ raise CompileError("Don't know how to compile type %r of %r"
2406+ % (expr.__class__, expr))
2407+ */
2408+ PyObject *repr = PyObject_Repr(expr);
2409+ if (repr) {
2410+ PyErr_Format(CompileError,
2411+ "Don't know how to compile type %s of %s",
2412+ expr->ob_type->tp_name, PyString_AS_STRING(repr));
2413+ Py_DECREF(repr);
2414+ }
2415+ goto error;
2416+ }
2417+ }
2418+
2419+ /*
2420+ inner_precedence = state.precedence = \
2421+ self._precedence.get(cls, MAX_PRECEDENCE)
2422+ */
2423+ CATCH(NULL, inner_precedence = Compile_get_precedence(self, cls));
2424+ CATCH(-1, PyObject_SetAttrString(state, "precedence", inner_precedence));
2425+
2426+ /* statement = handler(self, expr, state) */
2427+ CATCH(NULL, statement = PyObject_CallFunctionObjArgs(handler, self, expr,
2428+ state, NULL));
2429+
2430+ /* if inner_precedence < outer_precedence: */
2431+ if (PyObject_Compare(inner_precedence, outer_precedence) == -1) {
2432+ PyObject *args, *tmp;
2433+
2434+ if (PyErr_Occurred())
2435+ goto error;
2436+
2437+ /* return "(%s)" % statement */
2438+ CATCH(NULL, args = PyTuple_Pack(1, statement));
2439+ tmp = PyUnicode_Format(parenthesis_format, args);
2440+ Py_DECREF(args);
2441+ CATCH(NULL, tmp);
2442+ Py_DECREF(statement);
2443+ statement = tmp;
2444+ }
2445+
2446+ Py_DECREF(inner_precedence);
2447+
2448+ return statement;
2449+
2450+error:
2451+ Py_XDECREF(inner_precedence);
2452+ Py_XDECREF(statement);
2453+
2454+ return NULL;
2455+}
2456+
2457+PyObject *
2458+Compile_one_or_many(CompileObject *self, PyObject *expr, PyObject *state,
2459+ PyObject *join, int raw, int token)
2460+{
2461+ PyObject *outer_precedence = NULL;
2462+ PyObject *compiled = NULL;
2463+ PyObject *sequence = NULL;
2464+ PyObject *statement = NULL;
2465+ Py_ssize_t size, i;
2466+
2467+ Py_INCREF(expr);
2468+
2469+ /*
2470+ expr_type = type(expr)
2471+ if (expr_type is SQLRaw or
2472+ raw and (expr_type is str or expr_type is unicode)):
2473+ return expr
2474+ */
2475+ if ((PyObject *)expr->ob_type == SQLRaw ||
2476+ (raw && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr)))) {
2477+ /* Pass our reference on. */
2478+ return expr;
2479+ }
2480+
2481+ /*
2482+ if token and (expr_type is str or expr_type is unicode):
2483+ expr = SQLToken(expr)
2484+ */
2485+ if (token && (PyString_CheckExact(expr) || PyUnicode_CheckExact(expr))) {
2486+ PyObject *tmp;
2487+ CATCH(NULL, tmp = PyObject_CallFunctionObjArgs(SQLToken, expr, NULL));
2488+ Py_DECREF(expr);
2489+ expr = tmp;
2490+ }
2491+
2492+ /*
2493+ if state is None:
2494+ state = State()
2495+ */
2496+ /* That's done in Compile__call__ just once. */
2497+
2498+ /* outer_precedence = state.precedence */
2499+ CATCH(NULL, outer_precedence = PyObject_GetAttrString(state, "precedence"));
2500+ /* if expr_type is tuple or expr_type is list: */
2501+ if (PyTuple_CheckExact(expr) || PyList_CheckExact(expr)) {
2502+ /* compiled = [] */
2503+ CATCH(NULL, compiled = PyList_New(0));
2504+
2505+ /* for subexpr in expr: */
2506+ sequence = PySequence_Fast(expr, "This can't actually fail! ;-)");
2507+ size = PySequence_Fast_GET_SIZE(sequence);
2508+ for (i = 0; i != size; i++) {
2509+ PyObject *subexpr = PySequence_Fast_GET_ITEM(sequence, i);
2510+ /*
2511+ subexpr_type = type(subexpr)
2512+ if subexpr_type is SQLRaw or raw and (subexpr_type is str or
2513+ subexpr_type is unicode):
2514+ */
2515+ if ((PyObject *)subexpr->ob_type == (PyObject *)SQLRaw ||
2516+ (raw && (PyString_CheckExact(subexpr) ||
2517+ PyUnicode_CheckExact(subexpr)))) {
2518+ /* statement = subexpr */
2519+ Py_INCREF(subexpr);
2520+ statement = subexpr;
2521+ /* elif subexpr_type is tuple or subexpr_type is list: */
2522+ } else if (PyTuple_CheckExact(subexpr) ||
2523+ PyList_CheckExact(subexpr)) {
2524+ /* state.precedence = outer_precedence */
2525+ CATCH(-1, PyObject_SetAttrString(state, "precedence",
2526+ outer_precedence));
2527+ /* statement = self(subexpr, state, join, raw, token) */
2528+ CATCH(NULL,
2529+ statement = Compile_one_or_many(self, subexpr, state,
2530+ join, raw, token));
2531+ /* else: */
2532+ } else {
2533+ /*
2534+ if token and (subexpr_type is unicode or
2535+ subexpr_type is str):
2536+ */
2537+ if (token && (PyUnicode_CheckExact(subexpr) ||
2538+ PyString_CheckExact(subexpr))) {
2539+ /* subexpr = SQLToken(subexpr) */
2540+ CATCH(NULL,
2541+ subexpr = PyObject_CallFunctionObjArgs(SQLToken,
2542+ subexpr,
2543+ NULL));
2544+ } else {
2545+ Py_INCREF(subexpr);
2546+ }
2547+
2548+ /*
2549+ statement = self._compile_single(subexpr, state,
2550+ outer_precedence)
2551+ */
2552+ statement = Compile_single(self, subexpr, state,
2553+ outer_precedence);
2554+ Py_DECREF(subexpr);
2555+ CATCH(NULL, statement);
2556+ }
2557+
2558+ /* compiled.append(statement) */
2559+ CATCH(-1, PyList_Append(compiled, statement));
2560+ Py_CLEAR(statement);
2561+ }
2562+ Py_CLEAR(sequence);
2563+
2564+ /* statement = join.join(compiled) */
2565+ CATCH(NULL, statement = PyUnicode_Join(join, compiled));
2566+ Py_CLEAR(compiled);
2567+ } else {
2568+ /* statement = self._compile_single(expr, state, outer_precedence) */
2569+ CATCH(NULL, statement = Compile_single(self, expr, state,
2570+ outer_precedence));
2571+ }
2572+
2573+ /* state.precedence = outer_precedence */
2574+ CATCH(-1, PyObject_SetAttrString(state, "precedence", outer_precedence));
2575+ Py_CLEAR(outer_precedence);
2576+
2577+ Py_DECREF(expr);
2578+
2579+ return statement;
2580+
2581+error:
2582+ Py_XDECREF(expr);
2583+ Py_XDECREF(outer_precedence);
2584+ Py_XDECREF(compiled);
2585+ Py_XDECREF(sequence);
2586+ Py_XDECREF(statement);
2587+
2588+ return NULL;
2589+}
2590+
2591+static PyObject *
2592+Compile__call__(CompileObject *self, PyObject *args, PyObject *kwargs)
2593+{
2594+ static char *kwlist[] = {"expr", "state", "join", "raw", "token", NULL};
2595+ PyObject *expr = NULL;
2596+ PyObject *state = Py_None;
2597+ PyObject *join;
2598+ char raw = 0;
2599+ char token = 0;
2600+
2601+ PyObject *result = NULL;
2602+
2603+ if (!initialize_globals())
2604+ return NULL;
2605+
2606+ join = default_compile_join;
2607+
2608+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OSbb", kwlist,
2609+ &expr, &state, &join, &raw, &token)) {
2610+ return NULL;
2611+ }
2612+
2613+ if (state == Py_None) {
2614+ state = PyObject_CallFunctionObjArgs(State, NULL);
2615+ } else {
2616+ Py_INCREF(state);
2617+ }
2618+ if (state) {
2619+ result = Compile_one_or_many(self, expr, state, join, raw, token);
2620+ Py_DECREF(state);
2621+ }
2622+ return result;
2623+}
2624+
2625+
2626+static PyMethodDef Compile_methods[] = {
2627+ {"_update_cache", (PyCFunction)Compile__update_cache, METH_NOARGS, NULL},
2628+ {"when", (PyCFunction)Compile_when, METH_VARARGS, NULL},
2629+ {"add_reserved_words", (PyCFunction)Compile_add_reserved_words,
2630+ METH_O, NULL},
2631+ {"remove_reserved_words", (PyCFunction)Compile_remove_reserved_words,
2632+ METH_O, NULL},
2633+ {"is_reserved_word", (PyCFunction)Compile_is_reserved_word, METH_O, NULL},
2634+ {"create_child", (PyCFunction)Compile_create_child, METH_NOARGS, NULL},
2635+ {"get_precedence", (PyCFunction)Compile_get_precedence, METH_O, NULL},
2636+ {"set_precedence", (PyCFunction)Compile_set_precedence, METH_VARARGS, NULL},
2637+ {NULL, NULL}
2638+};
2639+
2640+#define OFFSETOF(x) offsetof(CompileObject, x)
2641+static PyMemberDef Compile_members[] = {
2642+ {"_local_dispatch_table", T_OBJECT, OFFSETOF(_local_dispatch_table), 0, 0},
2643+ {"_local_precedence", T_OBJECT, OFFSETOF(_local_precedence), 0, 0},
2644+ {"_local_reserved_words", T_OBJECT, OFFSETOF(_local_reserved_words), 0, 0},
2645+ {"_dispatch_table", T_OBJECT, OFFSETOF(_dispatch_table), 0, 0},
2646+ {"_precedence", T_OBJECT, OFFSETOF(_precedence), 0, 0},
2647+ {"_reserved_words", T_OBJECT, OFFSETOF(_reserved_words), 0, 0},
2648+ {"_children", T_OBJECT, OFFSETOF(_children), 0, 0},
2649+ {"_parents", T_OBJECT, OFFSETOF(_parents), 0, 0},
2650+ {NULL}
2651+};
2652+#undef OFFSETOF
2653+
2654+statichere PyTypeObject Compile_Type = {
2655+ PyObject_HEAD_INIT(NULL)
2656+ 0, /*ob_size*/
2657+ "storm.variables.Compile", /*tp_name*/
2658+ sizeof(CompileObject), /*tp_basicsize*/
2659+ 0, /*tp_itemsize*/
2660+ (destructor)Compile_dealloc, /*tp_dealloc*/
2661+ 0, /*tp_print*/
2662+ 0, /*tp_getattr*/
2663+ 0, /*tp_setattr*/
2664+ 0, /*tp_compare*/
2665+ 0, /*tp_repr*/
2666+ 0, /*tp_as_number*/
2667+ 0, /*tp_as_sequence*/
2668+ 0, /*tp_as_mapping*/
2669+ 0, /*tp_hash*/
2670+ (ternaryfunc)Compile__call__, /*tp_call*/
2671+ 0, /*tp_str*/
2672+ PyObject_GenericGetAttr,/*tp_getattro*/
2673+ PyObject_GenericSetAttr,/*tp_setattro*/
2674+ 0, /*tp_as_buffer*/
2675+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
2676+ 0, /*tp_doc*/
2677+ (traverseproc)Compile_traverse, /*tp_traverse*/
2678+ (inquiry)Compile_clear, /*tp_clear*/
2679+ 0, /*tp_richcompare*/
2680+ offsetof(CompileObject, __weakreflist), /*tp_weaklistoffset*/
2681+ 0, /*tp_iter*/
2682+ 0, /*tp_iternext*/
2683+ Compile_methods, /*tp_methods*/
2684+ Compile_members, /*tp_members*/
2685+ 0, /*tp_getset*/
2686+ 0, /*tp_base*/
2687+ 0, /*tp_dict*/
2688+ 0, /*tp_descr_get*/
2689+ 0, /*tp_descr_set*/
2690+ 0, /*tp_dictoffset*/
2691+ (initproc)Compile_init, /*tp_init*/
2692+ PyType_GenericAlloc, /*tp_alloc*/
2693+ PyType_GenericNew, /*tp_new*/
2694+ PyObject_GC_Del, /*tp_free*/
2695+ 0, /*tp_is_gc*/
2696+};
2697+
2698+
2699+static PyObject *
2700+>>>>>>> MERGE-SOURCE
2701 ObjectInfo__emit_object_deleted(ObjectInfoObject *self, PyObject *args)
2702 {
2703 /* self.event.emit("object-deleted") */
2704
2705=== modified file 'storm/database.py'
2706=== modified file 'storm/databases/postgres.py'
2707--- storm/databases/postgres.py 2008-08-18 19:44:51 +0000
2708+++ storm/databases/postgres.py 2009-05-06 21:20:16 +0000
2709@@ -36,7 +36,7 @@
2710 from storm.variables import Variable, ListVariable, RawStrVariable
2711 from storm.database import Database, Connection, Result
2712 from storm.exceptions import (
2713- install_exceptions, DatabaseError, DatabaseModuleError,
2714+ install_exceptions, DatabaseError, DatabaseModuleError, InterfaceError,
2715 OperationalError, ProgrammingError, TimeoutError)
2716 from storm.tracer import TimeoutTracer
2717
2718@@ -285,18 +285,28 @@
2719 yield param
2720
2721 def is_disconnection_error(self, exc):
2722- if not isinstance(exc, (OperationalError, ProgrammingError)):
2723+ if not isinstance(
2724+ exc, (InterfaceError, OperationalError, ProgrammingError)):
2725 return False
2726
2727 # XXX: 2007-09-17 jamesh
2728 # I have no idea why I am seeing the last exception message
2729 # after upgrading to Gutsy.
2730 msg = str(exc)
2731- return ("server closed the connection unexpectedly" in msg or
2732- "could not connect to server" in msg or
2733- "no connection to the server" in msg or
2734- "connection not open" in msg or
2735- "losed the connection unexpectedly" in msg)
2736+<<<<<<< TREE
2737+ return ("server closed the connection unexpectedly" in msg or
2738+ "could not connect to server" in msg or
2739+ "no connection to the server" in msg or
2740+ "connection not open" in msg or
2741+ "losed the connection unexpectedly" in msg)
2742+=======
2743+ return ("server closed the connection unexpectedly" in msg or
2744+ "could not connect to server" in msg or
2745+ "no connection to the server" in msg or
2746+ "connection not open" in msg or
2747+ "connection already closed" in msg or
2748+ "losed the connection unexpectedly" in msg)
2749+>>>>>>> MERGE-SOURCE
2750
2751
2752 class Postgres(Database):
2753
2754=== modified file 'storm/properties.py'
2755=== modified file 'storm/references.py'
2756=== modified file 'storm/sqlobject.py'
2757--- storm/sqlobject.py 2008-11-05 18:37:41 +0000
2758+++ storm/sqlobject.py 2009-05-06 21:20:16 +0000
2759@@ -552,8 +552,13 @@
2760 return item in result_set
2761
2762 def __nonzero__(self):
2763+<<<<<<< TREE
2764 result_set = self._without_prejoins()._result_set
2765 return not result_set.is_empty()
2766+=======
2767+ result_set = self._without_prejoins()._result_set
2768+ return result_set.any() is not None
2769+>>>>>>> MERGE-SOURCE
2770
2771 def count(self):
2772 result_set = self._without_prejoins()._result_set
2773
2774=== modified file 'storm/store.py'
2775--- storm/store.py 2009-02-16 10:44:31 +0000
2776+++ storm/store.py 2009-05-06 21:20:16 +0000
2777@@ -36,7 +36,8 @@
2778 Union, Except, Intersect, Alias, SetExpr)
2779 from storm.exceptions import (
2780 WrongStoreError, NotFlushedError, OrderLoopError, UnorderedError,
2781- NotOneError, FeatureError, CompileError, LostObjectError, ClassInfoError)
2782+ NotOneError, FeatureError, CompileError, LostObjectError, ClassInfoError,
2783+ ExprError)
2784 from storm import Undef
2785 from storm.cache import Cache
2786 from storm.event import EventSystem
2787@@ -439,7 +440,18 @@
2788 normal flushing times are insufficient, such as when you want to
2789 make sure a database trigger gets run at a particular time.
2790 """
2791+<<<<<<< TREE
2792 self._event.emit("flush")
2793+=======
2794+ # XXX 2008-06-19 jamesh bug=241267:
2795+ # This loop takes up 75% of flush()'s runtime in our tests,
2796+ # and probably more in cases with more live objects. As we
2797+ # don't use any property types that require the event, I've
2798+ # temporarily disabled it.
2799+
2800+ ##for obj_info in self._iter_alive():
2801+ ## obj_info.event.emit("flush")
2802+>>>>>>> MERGE-SOURCE
2803
2804 # The _dirty list may change under us while we're running
2805 # the flush hooks, so we cannot just simply loop over it
2806@@ -1016,6 +1028,7 @@
2807
2808 return self.copy().config(offset=offset, limit=limit)
2809
2810+<<<<<<< TREE
2811 def __contains__(self, item):
2812 """Check if an item is contained within the result set."""
2813 columns, values = self._find_spec.get_columns_and_values_for_item(item)
2814@@ -1047,6 +1060,31 @@
2815 result = self._store._connection.execute(select)
2816 return (not result.get_one())
2817
2818+=======
2819+ def __contains__(self, item):
2820+ """Check if an item is contained within the result set."""
2821+ columns, values = self._find_spec.get_columns_and_values_for_item(item)
2822+
2823+ if self._select is Undef and self._group_by is Undef:
2824+ # No predefined select: adjust the where clause.
2825+ dummy, default_tables = self._find_spec.get_columns_and_tables()
2826+ where = [Eq(*pair) for pair in zip(columns, values)]
2827+ if self._where is not Undef:
2828+ where.append(self._where)
2829+ select = Select(1, And(*where), self._tables,
2830+ default_tables)
2831+ else:
2832+ # Rewrite the predefined query and use it as a subquery.
2833+ aliased_columns = [Alias(column, "_key%d" % index)
2834+ for (index, column) in enumerate(columns)]
2835+ subquery = replace_columns(self._get_select(), aliased_columns)
2836+ where = [Eq(*pair) for pair in zip(aliased_columns, values)]
2837+ select = Select(1, And(*where), Alias(subquery, "_tmp"))
2838+
2839+ result = self._store._connection.execute(select)
2840+ return result.get_one() is not None
2841+
2842+>>>>>>> MERGE-SOURCE
2843 def any(self):
2844 """Return a single item from the result set.
2845
2846@@ -1438,12 +1476,18 @@
2847 def __getitem__(self, index):
2848 return self.copy()
2849
2850+<<<<<<< TREE
2851 def __contains__(self, item):
2852 return False
2853
2854 def is_empty(self):
2855 return True
2856
2857+=======
2858+ def __contains__(self, item):
2859+ return False
2860+
2861+>>>>>>> MERGE-SOURCE
2862 def any(self):
2863 return None
2864
2865
2866=== modified file 'storm/tracer.py'
2867--- storm/tracer.py 2009-02-04 01:53:02 +0000
2868+++ storm/tracer.py 2009-05-06 21:20:16 +0000
2869@@ -14,6 +14,7 @@
2870
2871 def connection_raw_execute(self, connection, raw_cursor, statement, params):
2872 time = datetime.now().isoformat()[11:]
2873+<<<<<<< TREE
2874 raw_params = []
2875 for param in params:
2876 if isinstance(param, Variable):
2877@@ -23,6 +24,10 @@
2878 raw_params = tuple(raw_params)
2879 self._stream.write(
2880 "[%s] EXECUTE: %r, %r\n" % (time, statement, raw_params))
2881+=======
2882+ params = tuple(param.get() for param in params)
2883+ self._stream.write("[%s] EXECUTE: %r, %r\n" % (time, statement, params))
2884+>>>>>>> MERGE-SOURCE
2885 self._stream.flush()
2886
2887 def connection_raw_execute_error(self, connection, raw_cursor,
2888
2889=== modified file 'storm/variables.py'
2890--- storm/variables.py 2009-03-04 16:56:58 +0000
2891+++ storm/variables.py 2009-05-06 21:20:16 +0000
2892@@ -536,6 +536,7 @@
2893 raise ValueError("Invalid enum value: %s" % repr(value))
2894
2895
2896+<<<<<<< TREE
2897 class MutableValueVariable(Variable):
2898 """
2899 A variable which contains a reference to mutable content. For this kind
2900@@ -544,6 +545,10 @@
2901 flushing current objects, to check if the state has changed.
2902 """
2903 __slots__ = ("_event_system")
2904+=======
2905+class PickleVariable(Variable):
2906+ __slots__ = ()
2907+>>>>>>> MERGE-SOURCE
2908
2909 def __init__(self, *args, **kwargs):
2910 self._event_system = None
2911@@ -603,9 +608,21 @@
2912 self._lazy_value = state[0]
2913 self._value = pickle.loads(state[1])
2914
2915+<<<<<<< TREE
2916
2917 class ListVariable(MutableValueVariable):
2918 __slots__ = ("_item_factory",)
2919+=======
2920+ def __hash__(self):
2921+ try:
2922+ return hash(self._value)
2923+ except TypeError:
2924+ return hash(pickle.dumps(self._value, -1))
2925+
2926+
2927+class ListVariable(Variable):
2928+ __slots__ = ("_item_factory",)
2929+>>>>>>> MERGE-SOURCE
2930
2931 def __init__(self, item_factory, *args, **kwargs):
2932 self._item_factory = item_factory
2933
2934=== modified file 'storm/zope/__init__.py'
2935--- storm/zope/__init__.py 2008-07-30 06:07:40 +0000
2936+++ storm/zope/__init__.py 2009-05-06 21:20:16 +0000
2937@@ -27,6 +27,7 @@
2938
2939
2940 classImplements(storm_sqlobject.SQLObjectResultSet, ISQLObjectResultSet)
2941+<<<<<<< TREE
2942 classImplements(ResultSet, IResultSet)
2943 classImplements(EmptyResultSet, IResultSet)
2944
2945@@ -43,3 +44,7 @@
2946 # Store.
2947 _available_by_default.append("__storm_object_info__")
2948 BasicTypes[ObjectInfo] = NoProxy
2949+=======
2950+classImplements(ResultSet, IResultSet)
2951+classImplements(EmptyResultSet, IResultSet)
2952+>>>>>>> MERGE-SOURCE
2953
2954=== modified file 'storm/zope/interfaces.py'
2955=== modified file 'storm/zope/zstorm.py'
2956=== modified file 'test'
2957=== modified file 'tests/__init__.py'
2958--- tests/__init__.py 2008-06-20 14:08:30 +0000
2959+++ tests/__init__.py 2009-05-06 21:20:16 +0000
2960@@ -0,0 +1,1 @@
2961+#import storm.psycer as p; p.enable()
2962
2963=== modified file 'tests/databases/base.py'
2964=== modified file 'tests/databases/postgres.py'
2965=== modified file 'tests/expr.py'
2966--- tests/expr.py 2008-10-02 15:47:18 +0000
2967+++ tests/expr.py 2009-05-06 21:20:16 +0000
2968@@ -662,16 +662,30 @@
2969 'ORDER BY column1')
2970 self.assertEquals(state.parameters, [])
2971
2972- def test_select_having(self):
2973- expr = Select(column1, tables=table1, order_by=u"column1",
2974- group_by=[u"column2"], having=u"1 = 2")
2975- state = State()
2976- statement = compile(expr, state)
2977- self.assertEquals(statement, 'SELECT column1 FROM "table 1" '
2978- 'GROUP BY column2 HAVING 1 = 2 '
2979- 'ORDER BY column1')
2980- self.assertEquals(state.parameters, [])
2981-
2982+<<<<<<< TREE
2983+ def test_select_having(self):
2984+ expr = Select(column1, tables=table1, order_by=u"column1",
2985+ group_by=[u"column2"], having=u"1 = 2")
2986+ state = State()
2987+ statement = compile(expr, state)
2988+ self.assertEquals(statement, 'SELECT column1 FROM "table 1" '
2989+ 'GROUP BY column2 HAVING 1 = 2 '
2990+ 'ORDER BY column1')
2991+ self.assertEquals(state.parameters, [])
2992+
2993+=======
2994+ def test_select_having(self):
2995+ expr = Select(column1, tables=table1, order_by=u"column1",
2996+ group_by=[u"column2"], having=u"1 = 2")
2997+ state = State()
2998+ statement = compile(expr, state)
2999+ self.assertEquals(statement, 'SELECT column1 FROM "table 1" '
3000+ 'GROUP BY column2 HAVING 1 = 2 '
3001+ 'ORDER BY column1')
3002+ self.assertEquals(state.parameters, [])
3003+
3004+
3005+>>>>>>> MERGE-SOURCE
3006 def test_select_contexts(self):
3007 column, where, table, order_by, group_by = track_contexts(5)
3008 expr = Select(column, where, table,
3009@@ -932,8 +946,13 @@
3010 expr = Func1().is_in([])
3011 state = State()
3012 statement = compile(expr, state)
3013+<<<<<<< TREE
3014 self.assertEquals(statement, "?")
3015 self.assertVariablesEqual(state.parameters, [BoolVariable(False)])
3016+=======
3017+ self.assertEquals(statement, "?")
3018+ self.assertEquals(state.parameters, [BoolVariable(False)])
3019+>>>>>>> MERGE-SOURCE
3020
3021 def test_is_in_expr(self):
3022 expr = Func1().is_in(Select(column1))
3023
3024=== modified file 'tests/store/base.py'
3025--- tests/store/base.py 2009-02-19 16:44:33 +0000
3026+++ tests/store/base.py 2009-05-06 21:20:16 +0000
3027@@ -21,17 +21,26 @@
3028 #
3029 import decimal
3030 import gc
3031+<<<<<<< TREE
3032 import operator
3033 import weakref
3034+=======
3035+import operator
3036+>>>>>>> MERGE-SOURCE
3037
3038 from storm.references import Reference, ReferenceSet, Proxy
3039 from storm.database import Result
3040 from storm.properties import Int, Float, RawStr, Unicode, Property, Pickle
3041 from storm.properties import PropertyPublisherMeta, Decimal
3042+<<<<<<< TREE
3043 from storm.variables import PickleVariable
3044 from storm.expr import (
3045 Asc, Desc, Select, Func, LeftJoin, SQL, Count, Sum, Avg, And, Or, Eq,
3046 Lower)
3047+=======
3048+from storm.expr import (
3049+ Asc, Desc, Select, Func, LeftJoin, SQL, Count, Sum, Avg, And, Or, Eq)
3050+>>>>>>> MERGE-SOURCE
3051 from storm.variables import Variable, UnicodeVariable, IntVariable
3052 from storm.info import get_obj_info, ClassAlias
3053 from storm.exceptions import *
3054@@ -1306,131 +1315,259 @@
3055 foo = self.store.find(Foo, Foo.id == 10).one()
3056 self.assertEqual(foo.title, "Title 30")
3057
3058- def test_find_group_by(self):
3059- result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3060- result.group_by(FooValue.value2)
3061- result.order_by(Count(FooValue.id), Sum(FooValue.value1))
3062- result = list(result)
3063- self.assertEquals(result, [(2L, 2L), (2L, 2L), (2L, 3L), (3L, 6L)])
3064-
3065- def test_find_group_by_table(self):
3066- result = self.store.find(
3067- (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3068- result.group_by(Foo)
3069- foo1 = self.store.get(Foo, 10)
3070- foo2 = self.store.get(Foo, 20)
3071- self.assertEquals(list(result), [(5, foo1), (16, foo2)])
3072-
3073- def test_find_group_by_table_contains(self):
3074- result = self.store.find(
3075- (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3076- result.group_by(Foo)
3077- foo1 = self.store.get(Foo, 10)
3078- self.assertEquals((5, foo1) in result, True)
3079-
3080- def test_find_group_by_multiple_tables(self):
3081- result = self.store.find(
3082- Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3083- result.group_by(Foo.id)
3084- result.order_by(Sum(FooValue.value2))
3085- result = list(result)
3086- self.assertEquals(result, [5, 16])
3087-
3088- result = self.store.find(
3089- (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3090- result.group_by(Foo)
3091- result.order_by(Sum(FooValue.value2))
3092- result = list(result)
3093- foo1 = self.store.get(Foo, 10)
3094- foo2 = self.store.get(Foo, 20)
3095- self.assertEquals(result, [(5, foo1), (16, foo2)])
3096-
3097- result = self.store.find(
3098- (Foo.id, Sum(FooValue.value2), Avg(FooValue.value1)),
3099- Foo.id == FooValue.foo_id)
3100- result.group_by(Foo.id)
3101- result.order_by(Foo.id)
3102- result = list(result)
3103- self.assertEquals(result, [(10, 5, 2),
3104- (20, 16, 1)])
3105-
3106- def test_find_group_by_having(self):
3107- result = self.store.find(
3108- Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3109- result.group_by(Foo.id)
3110- result.having(Sum(FooValue.value2) == 5)
3111- self.assertEquals(list(result), [5])
3112- result = self.store.find(
3113- Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3114- result.group_by(Foo.id)
3115- result.having(Count() == 5)
3116- self.assertEquals(list(result), [16])
3117-
3118- def test_find_having_without_group_by(self):
3119- result = self.store.find(FooValue)
3120- self.assertRaises(FeatureError, result.having, FooValue.value1 == 1)
3121-
3122- def test_find_group_by_multiple_having(self):
3123- result = self.store.find((Count(), FooValue.value2))
3124- result.group_by(FooValue.value2)
3125- result.having(Count() == 2, FooValue.value2 >= 3)
3126- result.order_by(Count(), FooValue.value2)
3127- list_result = list(result)
3128- self.assertEquals(list_result, [(2, 3), (2, 4)])
3129-
3130- def test_find_successive_group_by(self):
3131- result = self.store.find(Count())
3132- result.group_by(FooValue.value2)
3133- result.order_by(Count())
3134- list_result = list(result)
3135- self.assertEquals(list_result, [2, 2, 2, 3])
3136- result.group_by(FooValue.value1)
3137- list_result = list(result)
3138- self.assertEquals(list_result, [4, 5])
3139-
3140- def test_find_multiple_group_by(self):
3141- result = self.store.find(Count())
3142- result.group_by(FooValue.value2, FooValue.value1)
3143- result.order_by(Count())
3144- list_result = list(result)
3145- self.assertEquals(list_result, [1, 1, 2, 2, 3])
3146-
3147- def test_find_multiple_group_by_with_having(self):
3148- result = self.store.find((Count(), FooValue.value2))
3149- result.group_by(FooValue.value2, FooValue.value1).having(Count() == 2)
3150- result.order_by(Count(), FooValue.value2)
3151- list_result = list(result)
3152- self.assertEquals(list_result, [(2, 3), (2, 4)])
3153-
3154- def test_find_group_by_avg(self):
3155- result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3156- result.group_by(FooValue.value2)
3157- self.assertRaises(FeatureError, result.avg, FooValue.value2)
3158-
3159- def test_find_group_by_values(self):
3160- result = self.store.find(
3161- (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3162- result.group_by(Foo)
3163- result.order_by(Foo.title)
3164- result = list(result.values(Foo.title))
3165- self.assertEquals(result, [u'Title 20', u'Title 30'])
3166-
3167- def test_find_group_by_union(self):
3168- result1 = self.store.find(Foo, id=30)
3169- result2 = self.store.find(Foo, id=10)
3170- result3 = result1.union(result2)
3171- self.assertRaises(FeatureError, result3.group_by, Foo.title)
3172-
3173- def test_find_group_by_remove(self):
3174- result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3175- result.group_by(FooValue.value2)
3176- self.assertRaises(FeatureError, result.remove)
3177-
3178- def test_find_group_by_set(self):
3179- result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3180- result.group_by(FooValue.value2)
3181- self.assertRaises(FeatureError, result.set, FooValue.value1 == 1)
3182-
3183+<<<<<<< TREE
3184+ def test_find_group_by(self):
3185+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3186+ result.group_by(FooValue.value2)
3187+ result.order_by(Count(FooValue.id), Sum(FooValue.value1))
3188+ result = list(result)
3189+ self.assertEquals(result, [(2L, 2L), (2L, 2L), (2L, 3L), (3L, 6L)])
3190+
3191+ def test_find_group_by_table(self):
3192+ result = self.store.find(
3193+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3194+ result.group_by(Foo)
3195+ foo1 = self.store.get(Foo, 10)
3196+ foo2 = self.store.get(Foo, 20)
3197+ self.assertEquals(list(result), [(5, foo1), (16, foo2)])
3198+
3199+ def test_find_group_by_table_contains(self):
3200+ result = self.store.find(
3201+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3202+ result.group_by(Foo)
3203+ foo1 = self.store.get(Foo, 10)
3204+ self.assertEquals((5, foo1) in result, True)
3205+
3206+ def test_find_group_by_multiple_tables(self):
3207+ result = self.store.find(
3208+ Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3209+ result.group_by(Foo.id)
3210+ result.order_by(Sum(FooValue.value2))
3211+ result = list(result)
3212+ self.assertEquals(result, [5, 16])
3213+
3214+ result = self.store.find(
3215+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3216+ result.group_by(Foo)
3217+ result.order_by(Sum(FooValue.value2))
3218+ result = list(result)
3219+ foo1 = self.store.get(Foo, 10)
3220+ foo2 = self.store.get(Foo, 20)
3221+ self.assertEquals(result, [(5, foo1), (16, foo2)])
3222+
3223+ result = self.store.find(
3224+ (Foo.id, Sum(FooValue.value2), Avg(FooValue.value1)),
3225+ Foo.id == FooValue.foo_id)
3226+ result.group_by(Foo.id)
3227+ result.order_by(Foo.id)
3228+ result = list(result)
3229+ self.assertEquals(result, [(10, 5, 2),
3230+ (20, 16, 1)])
3231+
3232+ def test_find_group_by_having(self):
3233+ result = self.store.find(
3234+ Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3235+ result.group_by(Foo.id)
3236+ result.having(Sum(FooValue.value2) == 5)
3237+ self.assertEquals(list(result), [5])
3238+ result = self.store.find(
3239+ Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3240+ result.group_by(Foo.id)
3241+ result.having(Count() == 5)
3242+ self.assertEquals(list(result), [16])
3243+
3244+ def test_find_having_without_group_by(self):
3245+ result = self.store.find(FooValue)
3246+ self.assertRaises(FeatureError, result.having, FooValue.value1 == 1)
3247+
3248+ def test_find_group_by_multiple_having(self):
3249+ result = self.store.find((Count(), FooValue.value2))
3250+ result.group_by(FooValue.value2)
3251+ result.having(Count() == 2, FooValue.value2 >= 3)
3252+ result.order_by(Count(), FooValue.value2)
3253+ list_result = list(result)
3254+ self.assertEquals(list_result, [(2, 3), (2, 4)])
3255+
3256+ def test_find_successive_group_by(self):
3257+ result = self.store.find(Count())
3258+ result.group_by(FooValue.value2)
3259+ result.order_by(Count())
3260+ list_result = list(result)
3261+ self.assertEquals(list_result, [2, 2, 2, 3])
3262+ result.group_by(FooValue.value1)
3263+ list_result = list(result)
3264+ self.assertEquals(list_result, [4, 5])
3265+
3266+ def test_find_multiple_group_by(self):
3267+ result = self.store.find(Count())
3268+ result.group_by(FooValue.value2, FooValue.value1)
3269+ result.order_by(Count())
3270+ list_result = list(result)
3271+ self.assertEquals(list_result, [1, 1, 2, 2, 3])
3272+
3273+ def test_find_multiple_group_by_with_having(self):
3274+ result = self.store.find((Count(), FooValue.value2))
3275+ result.group_by(FooValue.value2, FooValue.value1).having(Count() == 2)
3276+ result.order_by(Count(), FooValue.value2)
3277+ list_result = list(result)
3278+ self.assertEquals(list_result, [(2, 3), (2, 4)])
3279+
3280+ def test_find_group_by_avg(self):
3281+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3282+ result.group_by(FooValue.value2)
3283+ self.assertRaises(FeatureError, result.avg, FooValue.value2)
3284+
3285+ def test_find_group_by_values(self):
3286+ result = self.store.find(
3287+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3288+ result.group_by(Foo)
3289+ result.order_by(Foo.title)
3290+ result = list(result.values(Foo.title))
3291+ self.assertEquals(result, [u'Title 20', u'Title 30'])
3292+
3293+ def test_find_group_by_union(self):
3294+ result1 = self.store.find(Foo, id=30)
3295+ result2 = self.store.find(Foo, id=10)
3296+ result3 = result1.union(result2)
3297+ self.assertRaises(FeatureError, result3.group_by, Foo.title)
3298+
3299+ def test_find_group_by_remove(self):
3300+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3301+ result.group_by(FooValue.value2)
3302+ self.assertRaises(FeatureError, result.remove)
3303+
3304+ def test_find_group_by_set(self):
3305+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3306+ result.group_by(FooValue.value2)
3307+ self.assertRaises(FeatureError, result.set, FooValue.value1 == 1)
3308+
3309+=======
3310+ def test_find_group_by(self):
3311+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3312+ result.group_by(FooValue.value2)
3313+ result.order_by(Count(FooValue.id), Sum(FooValue.value1))
3314+ result = list(result)
3315+ self.assertEquals(result, [(2L, 2L), (2L, 2L), (2L, 3L), (3L, 6L)])
3316+
3317+ def test_find_group_by_table(self):
3318+ result = self.store.find(
3319+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3320+ result.group_by(Foo)
3321+ foo1 = self.store.get(Foo, 10)
3322+ foo2 = self.store.get(Foo, 20)
3323+ self.assertEquals(list(result), [(5, foo1), (16, foo2)])
3324+
3325+ def test_find_group_by_table_contains(self):
3326+ result = self.store.find(
3327+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3328+ result.group_by(Foo)
3329+ foo1 = self.store.get(Foo, 10)
3330+ self.assertEquals((5, foo1) in result, True)
3331+
3332+ def test_find_group_by_multiple_tables(self):
3333+ result = self.store.find(
3334+ Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3335+ result.group_by(Foo.id)
3336+ result.order_by(Sum(FooValue.value2))
3337+ result = list(result)
3338+ self.assertEquals(result, [5, 16])
3339+
3340+ result = self.store.find(
3341+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3342+ result.group_by(Foo)
3343+ result.order_by(Sum(FooValue.value2))
3344+ result = list(result)
3345+ foo1 = self.store.get(Foo, 10)
3346+ foo2 = self.store.get(Foo, 20)
3347+ self.assertEquals(result, [(5, foo1), (16, foo2)])
3348+
3349+ result = self.store.find(
3350+ (Foo.id, Sum(FooValue.value2), Avg(FooValue.value1)),
3351+ Foo.id == FooValue.foo_id)
3352+ result.group_by(Foo.id)
3353+ result.order_by(Foo.id)
3354+ result = list(result)
3355+ self.assertEquals(result, [(10, 5, 2),
3356+ (20, 16, 1)])
3357+
3358+ def test_find_group_by_having(self):
3359+ result = self.store.find(
3360+ Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3361+ result.group_by(Foo.id)
3362+ result.having(Sum(FooValue.value2) == 5)
3363+ self.assertEquals(list(result), [5])
3364+ result = self.store.find(
3365+ Sum(FooValue.value2), Foo.id == FooValue.foo_id)
3366+ result.group_by(Foo.id)
3367+ result.having(Count() == 5)
3368+ self.assertEquals(list(result), [16])
3369+
3370+ def test_find_having_without_group_by(self):
3371+ result = self.store.find(FooValue)
3372+ self.assertRaises(FeatureError, result.having, FooValue.value1 == 1)
3373+
3374+ def test_find_group_by_multiple_having(self):
3375+ result = self.store.find((Count(), FooValue.value2))
3376+ result.group_by(FooValue.value2)
3377+ result.having(Count() == 2, FooValue.value2 >= 3)
3378+ result.order_by(Count(), FooValue.value2)
3379+ list_result = list(result)
3380+ self.assertEquals(list_result, [(2, 3), (2, 4)])
3381+
3382+ def test_find_successive_group_by(self):
3383+ result = self.store.find(Count())
3384+ result.group_by(FooValue.value2)
3385+ result.order_by(Count())
3386+ list_result = list(result)
3387+ self.assertEquals(list_result, [2, 2, 2, 3])
3388+ result.group_by(FooValue.value1)
3389+ list_result = list(result)
3390+ self.assertEquals(list_result, [4, 5])
3391+
3392+ def test_find_multiple_group_by(self):
3393+ result = self.store.find(Count())
3394+ result.group_by(FooValue.value2, FooValue.value1)
3395+ result.order_by(Count())
3396+ list_result = list(result)
3397+ self.assertEquals(list_result, [1, 1, 2, 2, 3])
3398+
3399+ def test_find_multiple_group_by_with_having(self):
3400+ result = self.store.find((Count(), FooValue.value2))
3401+ result.group_by(FooValue.value2, FooValue.value1).having(Count() == 2)
3402+ result.order_by(Count(), FooValue.value2)
3403+ list_result = list(result)
3404+ self.assertEquals(list_result, [(2, 3), (2, 4)])
3405+
3406+ def test_find_group_by_avg(self):
3407+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3408+ result.group_by(FooValue.value2)
3409+ self.assertRaises(FeatureError, result.avg, FooValue.value2)
3410+
3411+ def test_find_group_by_values(self):
3412+ result = self.store.find(
3413+ (Sum(FooValue.value2), Foo), Foo.id == FooValue.foo_id)
3414+ result.group_by(Foo)
3415+ result.order_by(Foo.title)
3416+ result = list(result.values(Foo.title))
3417+ self.assertEquals(result, [u'Title 20', u'Title 30'])
3418+
3419+ def test_find_group_by_union(self):
3420+ result1 = self.store.find(Foo, id=30)
3421+ result2 = self.store.find(Foo, id=10)
3422+ result3 = result1.union(result2)
3423+ self.assertRaises(FeatureError, result3.group_by, Foo.title)
3424+
3425+ def test_find_group_by_remove(self):
3426+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3427+ result.group_by(FooValue.value2)
3428+ self.assertRaises(FeatureError, result.remove)
3429+
3430+ def test_find_group_by_set(self):
3431+ result = self.store.find((Count(FooValue.id), Sum(FooValue.value1)))
3432+ result.group_by(FooValue.value2)
3433+ self.assertRaises(FeatureError, result.set, FooValue.value1 == 1)
3434+
3435+>>>>>>> MERGE-SOURCE
3436 def test_add_commit(self):
3437 foo = Foo()
3438 foo.id = 40
3439@@ -4316,6 +4453,10 @@
3440 self.assertEquals(foo.title, "Some default value")
3441
3442 def test_pickle_variable(self):
3443+ # XXX 2008-06-19 jamesh bug=241267:
3444+ # Disabled, as Pickle() properties depend on the flush event.
3445+ return
3446+
3447 class PickleBlob(Blob):
3448 bin = Pickle()
3449
3450@@ -4503,6 +4644,10 @@
3451 self.assertTrue(value is blob.pickle)
3452
3453 def test_pickle_variable_with_deleted_object(self):
3454+ # XXX 2008-06-19 jamesh bug=241267:
3455+ # Disabled, as Pickle() properties depend on the flush event.
3456+ return
3457+
3458 class PickleBlob(Blob):
3459 bin = Pickle()
3460
3461@@ -5387,6 +5532,7 @@
3462 " (ensure your database was created with CREATE DATABASE"
3463 " ... CHARACTER SET utf8)")
3464
3465+<<<<<<< TREE
3466 def test_creation_order_is_preserved_when_possible(self):
3467 foos = [self.store.add(Foo()) for i in range(10)]
3468 self.store.flush()
3469@@ -5499,6 +5645,50 @@
3470 foo.title = u"New title"
3471 self.assertEqual(len(calls), 1)
3472 self.assertEqual(calls[0], self.store)
3473+=======
3474+ def test_creation_order_is_preserved_when_possible(self):
3475+ foos = [self.store.add(Foo()) for i in range(10)]
3476+ self.store.flush()
3477+ for i in range(len(foos)-1):
3478+ self.assertTrue(foos[i].id < foos[i+1].id)
3479+
3480+ def test_update_order_is_preserved_when_possible(self):
3481+ class MyFoo(Foo):
3482+ sequence = 0
3483+ def __storm_flushed__(self):
3484+ self.flush_order = MyFoo.sequence
3485+ MyFoo.sequence += 1
3486+
3487+ foos = [self.store.add(MyFoo()) for i in range(10)]
3488+ self.store.flush()
3489+
3490+ MyFoo.sequence = 0
3491+ for foo in foos:
3492+ foo.title = u"Changed Title"
3493+ self.store.flush()
3494+
3495+ for i, foo in enumerate(foos):
3496+ self.assertEquals(foo.flush_order, i)
3497+
3498+ def test_removal_order_is_preserved_when_possible(self):
3499+ class MyFoo(Foo):
3500+ sequence = 0
3501+ def __storm_flushed__(self):
3502+ self.flush_order = MyFoo.sequence
3503+ MyFoo.sequence += 1
3504+
3505+ foos = [self.store.add(MyFoo()) for i in range(10)]
3506+ self.store.flush()
3507+
3508+ MyFoo.sequence = 0
3509+ for foo in foos:
3510+ self.store.remove(foo)
3511+ self.store.flush()
3512+
3513+ for i, foo in enumerate(foos):
3514+ self.assertEquals(foo.flush_order, i)
3515+
3516+>>>>>>> MERGE-SOURCE
3517
3518 class EmptyResultSetTest(object):
3519
3520@@ -5560,6 +5750,7 @@
3521 self.assertEquals(list(self.result[:]), [])
3522 self.assertEquals(list(self.empty[:]), [])
3523
3524+<<<<<<< TREE
3525 def test_contains(self):
3526 self.assertEquals(Foo() in self.empty, False)
3527
3528@@ -5567,6 +5758,11 @@
3529 self.assertEquals(self.result.is_empty(), True)
3530 self.assertEquals(self.empty.is_empty(), True)
3531
3532+=======
3533+ def test_contains(self):
3534+ self.assertEquals(Foo() in self.empty, False)
3535+
3536+>>>>>>> MERGE-SOURCE
3537 def test_any(self):
3538 self.assertEquals(self.result.any(), None)
3539 self.assertEquals(self.empty.any(), None)
3540
3541=== modified file 'tests/store/mysql.py'
3542=== modified file 'tests/store/postgres.py'
3543--- tests/store/postgres.py 2009-03-04 16:56:58 +0000
3544+++ tests/store/postgres.py 2009-05-06 21:20:16 +0000
3545@@ -103,6 +103,9 @@
3546 self.connection.rollback()
3547
3548 def test_list_variable(self):
3549+ # XXX 2008-06-19 jamesh bug=241267:
3550+ # Disabled, as List() properties depend on the flush event.
3551+ return
3552
3553 lst = Lst1()
3554 lst.id = 1
3555@@ -146,6 +149,9 @@
3556 self.assertEquals(result.get_one(), ([1,2,3],))
3557
3558 def test_list_variable_nested(self):
3559+ # XXX 2008-06-19 jamesh bug=241267:
3560+ # Disabled, as List() properties depend on the flush event.
3561+ return
3562
3563 lst = Lst2()
3564 lst.id = 1
3565
3566=== modified file 'tests/store/sqlite.py'
3567=== modified file 'tests/tracer.py'
3568--- tests/tracer.py 2009-02-04 01:53:02 +0000
3569+++ tests/tracer.py 2009-05-06 21:20:16 +0000
3570@@ -74,6 +74,7 @@
3571 self.assertEquals(stash, ["m1", (1, 2), {"c": 3}, "m2", (), {}])
3572
3573
3574+<<<<<<< TREE
3575
3576 class MockVariable(Variable):
3577
3578@@ -84,6 +85,18 @@
3579 return self._value
3580
3581
3582+=======
3583+
3584+class MockVariable(object):
3585+
3586+ def __init__(self, value):
3587+ self._value = value
3588+
3589+ def get(self):
3590+ return self._value
3591+
3592+
3593+>>>>>>> MERGE-SOURCE
3594 class DebugTracerTest(TestHelper):
3595
3596 def setUp(self):
3597@@ -116,6 +129,7 @@
3598 self.assertEqual(tracer._stream, marker)
3599
3600 def test_connection_raw_execute(self):
3601+<<<<<<< TREE
3602 self.stream.write(
3603 "[04:05:06.000007] EXECUTE: 'STATEMENT', ('PARAM',)\n")
3604 self.stream.flush()
3605@@ -139,6 +153,17 @@
3606 raw_cursor = "RAW_CURSOR"
3607 statement = "STATEMENT"
3608 params = [self.variable, 1]
3609+=======
3610+ stderr = self.mocker.replace("sys.stderr")
3611+ stderr.write("[04:05:06.000007] EXECUTE: 'STATEMENT', ('PARAM',)\n")
3612+ stderr.flush()
3613+ self.mocker.replay()
3614+
3615+ connection = "CONNECTION"
3616+ raw_cursor = "RAW_CURSOR"
3617+ statement = "STATEMENT"
3618+ params = [self.variable]
3619+>>>>>>> MERGE-SOURCE
3620
3621 self.tracer.connection_raw_execute(connection, raw_cursor,
3622 statement, params)
3623@@ -170,6 +195,25 @@
3624 self.tracer.connection_raw_execute_success(connection, raw_cursor,
3625 statement, params)
3626
3627+<<<<<<< TREE
3628+=======
3629+ def test_custom_stream(self):
3630+ self.tracer = DebugTracer(sys.stdout)
3631+
3632+ stdout = self.mocker.replace("sys.stdout")
3633+ stdout.write("[04:05:06.000007] EXECUTE: 'STATEMENT', ('PARAM',)\n")
3634+ stdout.flush()
3635+ self.mocker.replay()
3636+
3637+ connection = "CONNECTION"
3638+ raw_cursor = "RAW_CURSOR"
3639+ statement = "STATEMENT"
3640+ params = [self.variable]
3641+
3642+ self.tracer.connection_raw_execute(connection, raw_cursor,
3643+ statement, params)
3644+
3645+>>>>>>> MERGE-SOURCE
3646
3647 class TimeoutTracerTestBase(TestHelper):
3648
3649
3650=== modified file 'tests/tutorial.txt'
3651=== modified file 'tests/zope/zstorm.py'
3652--- tests/zope/zstorm.py 2009-03-05 21:53:12 +0000
3653+++ tests/zope/zstorm.py 2009-05-06 21:20:16 +0000
3654@@ -21,7 +21,11 @@
3655 import thread, weakref, gc
3656
3657 from tests.helper import TestHelper
3658+<<<<<<< TREE
3659 from tests.zope import has_transaction, has_zope_component
3660+=======
3661+from tests.zope import has_transaction, has_zope, has_zope_component
3662+>>>>>>> MERGE-SOURCE
3663
3664 if has_transaction:
3665 import transaction
3666@@ -31,6 +35,9 @@
3667 if has_zope_component:
3668 from zope.component import provideUtility, getUtility
3669
3670+if has_zope_component:
3671+ from zope.component import provideUtility, getUtility
3672+
3673 from storm.exceptions import OperationalError
3674 from storm.locals import Store
3675
3676@@ -233,6 +240,7 @@
3677 store = self.zstorm.get("name", "sqlite:")
3678 store_ref = weakref.ref(store)
3679 transaction.abort()
3680+<<<<<<< TREE
3681 del store
3682 gc.collect()
3683 self.assertNotIdentical(store_ref(), None)
3684@@ -249,3 +257,24 @@
3685 provideUtility(ZStorm())
3686 self.assertTrue(isinstance(getUtility(IZStorm), ZStorm))
3687
3688+=======
3689+ self.assertEquals(
3690+ len(transaction.manager._synchs.values()[0].data.values()), 1)
3691+ self.zstorm._reset()
3692+ self.assertEquals(
3693+ len(transaction.manager._synchs.values()[0].data.values()), 0)
3694+
3695+ def test_store_strong_reference(self):
3696+ """
3697+ The zstorm utility should be a strong reference to named stores so that
3698+ it doesn't recreate stores uselessly.
3699+ """
3700+ store = self.zstorm.get("name", "sqlite:")
3701+ store_ref = weakref.ref(store)
3702+ transaction.abort()
3703+ del store
3704+ gc.collect()
3705+ self.assertNotIdentical(store_ref(), None)
3706+ store = self.zstorm.get("name")
3707+ self.assertIdentical(store_ref(), store)
3708+>>>>>>> MERGE-SOURCE

Subscribers

People subscribed via source and target branches

to status/vote changes: