Merge lp:~adam-collard/storm/kill-django-storm into lp:storm

Proposed by Adam Collard
Status: Merged
Approved by: Benji York
Approved revision: 482
Merged at revision: 480
Proposed branch: lp:~adam-collard/storm/kill-django-storm
Merge into: lp:storm
Prerequisite: lp:~adam-collard/storm/sqlobject2-compatibility
Diff against target: 1048 lines (+12/-958)
11 files modified
NEWS (+11/-0)
README (+1/-1)
dev/ubuntu-deps (+0/-1)
setup.py (+0/-1)
storm/django/__init__.py (+0/-20)
storm/django/backend/base.py (+0/-136)
storm/django/middleware.py (+0/-86)
storm/django/stores.py (+0/-61)
tests/django/backend.py (+0/-323)
tests/django/middleware.py (+0/-220)
tests/django/stores.py (+0/-109)
To merge this branch: bzr merge lp:~adam-collard/storm/kill-django-storm
Reviewer Review Type Date Requested Status
Adam Collard (community) Abstain
Benji York (community) Approve
Review via email: mp+287630@code.launchpad.net

Description of the change

Remove Django support in Storm.

The Django support has long since bit-rotted in Storm, and searching on http://searchcode.com/ shows it isn't being used. Rather than try to keep it alive this branch does the honourable thing and shoots it in the head.

With this branch merged, tests should pass on Xenial.

To post a comment you must log in.
Revision history for this message
Benji York (benji) wrote :

This branch looks good and the tests do in fact pass on Xenial for me.

review: Approve
Revision history for this message
Adam Collard (adam-collard) :
review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2014-12-28 11:51:53 +0000
3+++ NEWS 2016-03-01 13:17:28 +0000
4@@ -8,6 +8,17 @@
5 package, which can apply patches "in parallel" against a set of stores. See
6 the module docstring for more information.
7
8+Bug fixes
9+---------
10+
11+- Fixed SQLObject tests to work with SQLObject 2.x by using Unicode strings for
12+ LIKE operations.
13+
14+API changes
15+-----------
16+
17+- Removed Django support, storm.django is no more.
18+
19 0.20 (2013-06-28)
20 =================
21
22
23=== modified file 'README'
24--- README 2012-03-06 10:28:06 +0000
25+++ README 2016-03-01 13:17:28 +0000
26@@ -127,7 +127,7 @@
27 apt-get:
28
29 $ apt-get install \
30- python-django python-fixtures python-psycopg2 \
31+ python-fixtures python-psycopg2 \
32 python-testresources python-transaction python-twisted \
33 python-zope.component python-zope.security
34
35
36=== modified file 'dev/ubuntu-deps'
37--- dev/ubuntu-deps 2014-05-22 16:45:50 +0000
38+++ dev/ubuntu-deps 2016-03-01 13:17:28 +0000
39@@ -11,7 +11,6 @@
40 postgresql \
41 pgbouncer \
42 build-essential \
43- python-django \
44 python-fixtures \
45 python-psycopg2 \
46 python-testresources \
47
48=== modified file 'setup.py'
49--- setup.py 2011-10-28 14:44:04 +0000
50+++ setup.py 2016-03-01 13:17:28 +0000
51@@ -53,7 +53,6 @@
52 test_suite = "tests.find_tests",
53 tests_require=[
54 # Versions based on Lucid, where packaged.
55- "django >= 1.1.1",
56 "fixtures >= 0.3.5",
57 # pgbouncer (the Python module) is not yet packaged in Ubuntu.
58 "pgbouncer >= 0.0.7",
59
60=== removed file 'storm/django/__init__.py'
61--- storm/django/__init__.py 2008-07-30 08:45:40 +0000
62+++ storm/django/__init__.py 1970-01-01 00:00:00 +0000
63@@ -1,20 +0,0 @@
64-#
65-# Copyright (c) 2008 Canonical
66-#
67-# Written by James Henstridge <jamesh@canonical.com>
68-#
69-# This file is part of Storm Object Relational Mapper.
70-#
71-# Storm is free software; you can redistribute it and/or modify
72-# it under the terms of the GNU Lesser General Public License as
73-# published by the Free Software Foundation; either version 2.1 of
74-# the License, or (at your option) any later version.
75-#
76-# Storm is distributed in the hope that it will be useful,
77-# but WITHOUT ANY WARRANTY; without even the implied warranty of
78-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79-# GNU Lesser General Public License for more details.
80-#
81-# You should have received a copy of the GNU Lesser General Public License
82-# along with this program. If not, see <http://www.gnu.org/licenses/>.
83-#
84
85=== removed file 'storm/django/backend/base.py'
86--- storm/django/backend/base.py 2012-03-05 20:04:10 +0000
87+++ storm/django/backend/base.py 1970-01-01 00:00:00 +0000
88@@ -1,136 +0,0 @@
89-__metaclass__ = type
90-
91-__all__ = [
92- 'DatabaseWrapper', 'DatabaseError', 'IntegrityError',
93- ]
94-
95-from django.conf import settings
96-import transaction
97-
98-from storm.django.stores import get_store, get_store_uri
99-from storm.exceptions import DatabaseError, IntegrityError
100-
101-
102-class StormDatabaseWrapperMixin(object):
103-
104- _store = None
105-
106- def _get_connection(self):
107- if self._store is None:
108- self._store = get_store(settings.DATABASE_NAME)
109- # Make sure that the store is registered with the transaction
110- # manager: we don't know what the connection will be used for.
111- self._store._event.emit("register-transaction")
112- self._store._connection._ensure_connected()
113- return self._store._connection._raw_connection
114-
115- def _set_connection(self, connection):
116- # Ignore attempts to set the connection.
117- pass
118-
119- connection = property(_get_connection, _set_connection)
120-
121- def _valid_connection(self):
122- # Storm handles the connection liveness checks.
123- return True
124-
125- def _cursor(self, *args):
126- cursor = super(StormDatabaseWrapperMixin, self)._cursor(*args)
127- return StormCursorWrapper(self._store, cursor)
128-
129- def _commit(self):
130- #print "commit"
131- try:
132- transaction.commit()
133- except Exception:
134- transaction.abort()
135- raise
136-
137- def _rollback(self):
138- #print "rollback"
139- transaction.abort()
140-
141- def close(self):
142- # As we are borrowing Storm's connection, we shouldn't close
143- # it behind Storm's back.
144- self._store = None
145-
146-
147-class StormCursorWrapper(object):
148- """A cursor wrapper that checks for disconnection errors."""
149-
150- def __init__(self, store, cursor):
151- self._connection = store._connection
152- self._cursor = cursor
153-
154- def _check_disconnect(self, *args, **kwargs):
155- from django.db import DatabaseError as DjangoDatabaseError
156- kwargs['extra_disconnection_errors'] = DjangoDatabaseError
157- return self._connection._check_disconnect(*args, **kwargs)
158-
159- def execute(self, statement, *args):
160- """Execute an SQL statement."""
161- return self._check_disconnect(self._cursor.execute, statement, *args)
162-
163- def fetchone(self):
164- """Fetch one row from the result."""
165- return self._check_disconnect(self._cursor.fetchone)
166-
167- def fetchall(self):
168- """Fetch all rows from the result."""
169- return self._check_disconnect(self._cursor.fetchall)
170-
171- def fetchmany(self, *args):
172- """Fetch multiple rows from the result."""
173- return self._check_disconnect(self._cursor.fetchmany, *args)
174-
175- @property
176- def description(self):
177- """Fetch the description of the result."""
178- return self._check_disconnect(getattr, self._cursor, "description")
179-
180- @property
181- def rowcount(self):
182- """Fetch the number of rows in the result."""
183- return self._check_disconnect(getattr, self._cursor, "rowcount")
184-
185- @property
186- def query(self):
187- """Fetch the last executed query."""
188- return self._check_disconnect(getattr, self._cursor, "query")
189-
190-
191-PostgresStormDatabaseWrapper = None
192-MySQLStormDatabaseWrapper = None
193-
194-
195-def DatabaseWrapper(*args, **kwargs):
196- store_uri = get_store_uri(settings.DATABASE_NAME)
197-
198- # Create a DatabaseWrapper class that uses an underlying Storm
199- # connection. We don't support sqlite here because Django expects
200- # a bunch of special setup on the connection that Storm doesn't
201- # do.
202- if store_uri.startswith('postgres:'):
203- global PostgresStormDatabaseWrapper
204- if PostgresStormDatabaseWrapper is None:
205- from django.db.backends.postgresql_psycopg2.base import (
206- DatabaseWrapper as PostgresDatabaseWrapper)
207- class PostgresStormDatabaseWrapper(StormDatabaseWrapperMixin,
208- PostgresDatabaseWrapper):
209- pass
210- DatabaseWrapper = PostgresStormDatabaseWrapper
211- elif store_uri.startswith('mysql:'):
212- global MySQLStormDatabaseWrapper
213- if MySQLStormDatabaseWrapper is None:
214- from django.db.backends.mysql.base import (
215- DatabaseWrapper as MySQLDatabaseWrapper)
216- class MySQLStormDatabaseWrapper(StormDatabaseWrapperMixin,
217- MySQLDatabaseWrapper):
218- pass
219- DatabaseWrapper = MySQLStormDatabaseWrapper
220- else:
221- assert False, (
222- "Unsupported database backend: %s" % store_uri)
223-
224- return DatabaseWrapper(*args, **kwargs)
225
226=== removed file 'storm/django/middleware.py'
227--- storm/django/middleware.py 2011-11-14 21:50:14 +0000
228+++ storm/django/middleware.py 1970-01-01 00:00:00 +0000
229@@ -1,86 +0,0 @@
230-#
231-# Copyright (c) 2008 Canonical
232-#
233-# Written by James Henstridge <jamesh@canonical.com>
234-#
235-# This file is part of Storm Object Relational Mapper.
236-#
237-# Storm is free software; you can redistribute it and/or modify
238-# it under the terms of the GNU Lesser General Public License as
239-# published by the Free Software Foundation; either version 2.1 of
240-# the License, or (at your option) any later version.
241-#
242-# Storm is distributed in the hope that it will be useful,
243-# but WITHOUT ANY WARRANTY; without even the implied warranty of
244-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
245-# GNU Lesser General Public License for more details.
246-#
247-# You should have received a copy of the GNU Lesser General Public License
248-# along with this program. If not, see <http://www.gnu.org/licenses/>.
249-#
250-
251-"""Django middleware support for the Zope transaction manager.
252-
253-Adding storm.django.middleware.ZopeTransactionMiddleware to
254-L{MIDDLEWARE_CLASSES} in the application's settings module will cause a
255-Zope transaction to be run for each request.
256-"""
257-
258-__all__ = ['ZopeTransactionMiddleware']
259-
260-
261-from django.conf import settings
262-
263-import transaction
264-
265-
266-class ZopeTransactionMiddleware(object):
267- """Zope Transaction middleware for Django.
268-
269- If this is enabled, a Zope transaction will be run to cover each
270- request.
271- """
272- def __init__(self):
273- self.commit_safe_methods = getattr(
274- settings, 'STORM_COMMIT_SAFE_METHODS', True)
275-
276- def process_request(self, request):
277- """Begin a transaction on request start.."""
278- from django.db import transaction as django_transaction
279- django_transaction.enter_transaction_management()
280- django_transaction.managed(True)
281- transaction.begin()
282-
283- def process_exception(self, request, exception):
284- """Abort the transaction on errors."""
285- from django.db import transaction as django_transaction
286- transaction.abort()
287- django_transaction.set_clean()
288- django_transaction.leave_transaction_management()
289-
290- def process_response(self, request, response):
291- """Commit or abort the transaction after processing the response.
292-
293- On successful completion of the request, the transaction will
294- be committed.
295-
296- As an exception to this, if the L{STORM_COMMIT_SAFE_METHODS}
297- setting is False, and the request used either of the GET and
298- HEAD methods, the transaction will be aborted.
299- """
300- from django.db import transaction as django_transaction
301- # If process_exception() has been called, then we'll no longer
302- # be in managed transaction mode.
303- if django_transaction.is_managed():
304- if self.commit_safe_methods or (
305- request.method not in ['HEAD', 'GET']):
306- try:
307- transaction.commit()
308- except Exception:
309- transaction.abort()
310- raise
311- else:
312- transaction.abort()
313- django_transaction.set_clean()
314- django_transaction.leave_transaction_management()
315- return response
316
317=== removed file 'storm/django/stores.py'
318--- storm/django/stores.py 2009-08-05 06:23:43 +0000
319+++ storm/django/stores.py 1970-01-01 00:00:00 +0000
320@@ -1,61 +0,0 @@
321-#
322-# Copyright (c) 2008 Canonical
323-#
324-# Written by James Henstridge <jamesh@canonical.com>
325-#
326-# This file is part of Storm Object Relational Mapper.
327-#
328-# Storm is free software; you can redistribute it and/or modify
329-# it under the terms of the GNU Lesser General Public License as
330-# published by the Free Software Foundation; either version 2.1 of
331-# the License, or (at your option) any later version.
332-#
333-# Storm is distributed in the hope that it will be useful,
334-# but WITHOUT ANY WARRANTY; without even the implied warranty of
335-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
336-# GNU Lesser General Public License for more details.
337-#
338-# You should have received a copy of the GNU Lesser General Public License
339-# along with this program. If not, see <http://www.gnu.org/licenses/>.
340-#
341-
342-"""Support for configuration and management of Storm stores in a Django app."""
343-
344-__all__ = ["ensure_stores_configured", "get_store", "get_store_uri"]
345-
346-
347-from storm.zope.zstorm import global_zstorm
348-
349-from django.conf import settings
350-from django.core.exceptions import ImproperlyConfigured
351-
352-
353-def configure_stores(settings):
354- if not hasattr(settings, "STORM_STORES"):
355- raise ImproperlyConfigured(
356- "You need to specify STORM_STORES in your Django settings file.")
357-
358- for name, uri in settings.STORM_STORES.iteritems():
359- global_zstorm.set_default_uri(name, uri)
360-
361-
362-have_configured_stores = False
363-
364-
365-def ensure_stores_configured():
366- global have_configured_stores
367- if not have_configured_stores:
368- configure_stores(settings)
369- have_configured_stores = True
370-
371-
372-def get_store(name):
373- # Make sure that stores have been configured.
374- ensure_stores_configured()
375-
376- return global_zstorm.get(name)
377-
378-
379-def get_store_uri(name):
380- ensure_stores_configured()
381- return global_zstorm.get_default_uris()[name]
382
383=== removed file 'tests/django/backend.py'
384--- tests/django/backend.py 2015-01-25 09:29:29 +0000
385+++ tests/django/backend.py 1970-01-01 00:00:00 +0000
386@@ -1,323 +0,0 @@
387-
388-# Copyright (c) 2008 Canonical
389-#
390-# Written by James Henstridge <jamesh@canonical.com>
391-#
392-# This file is part of Storm Object Relational Mapper.
393-#
394-# Storm is free software; you can redistribute it and/or modify
395-# it under the terms of the GNU Lesser General Public License as
396-# published by the Free Software Foundation; either version 2.1 of
397-# the License, or (at your option) any later version.
398-#
399-# Storm is distributed in the hope that it will be useful,
400-# but WITHOUT ANY WARRANTY; without even the implied warranty of
401-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
402-# GNU Lesser General Public License for more details.
403-#
404-# You should have received a copy of the GNU Lesser General Public License
405-# along with this program. If not, see <http://www.gnu.org/licenses/>.
406-#
407-
408-import os
409-
410-try:
411- import django
412- import transaction
413-except ImportError:
414- have_django_and_transaction = False
415-else:
416- have_django_and_transaction = True
417- from django.conf import settings
418- from storm.django import stores
419- from storm.zope.zstorm import global_zstorm, StoreDataManager
420-
421-import storm.database
422-from storm.exceptions import DisconnectionError
423-
424-from tests.helper import TestHelper
425-from tests.databases.base import DatabaseDisconnectionMixin
426-
427-
428-def make_wrapper():
429- from storm.django.backend import base
430- if django.VERSION >= (1, 1):
431- wrapper = base.DatabaseWrapper({
432- 'DATABASE_NAME': settings.DATABASE_NAME,
433- 'TIME_ZONE': settings.TIME_ZONE,
434- 'OPTIONS': {},
435- })
436- else:
437- wrapper = base.DatabaseWrapper(**settings.DATABASE_OPTIONS)
438- return wrapper
439-
440-
441-class DjangoBackendTests(object):
442-
443- def is_supported(self):
444- return have_django_and_transaction and self.get_store_uri() is not None
445-
446- def setUp(self):
447- super(DjangoBackendTests, self).setUp()
448- settings.configure(STORM_STORES={})
449- settings.MIDDLEWARE_CLASSES += (
450- "storm.django.middleware.ZopeTransactionMiddleware",)
451- settings.DATABASE_ENGINE = "storm.django.backend"
452- settings.DATABASE_NAME = "django"
453- settings.STORM_STORES["django"] = self.get_store_uri()
454- stores.have_configured_stores = False
455- self.create_tables()
456-
457- def tearDown(self):
458- transaction.abort()
459- self.drop_tables()
460- if django.VERSION >= (1, 1):
461- if django.VERSION >= (1, 6):
462- from django.utils.functional import empty
463- else:
464- empty = None
465- settings._wrapped = empty
466- else:
467- settings._target = None
468- global_zstorm._reset()
469- stores.have_configured_stores = False
470- transaction.manager.free(transaction.get())
471- super(DjangoBackendTests, self).tearDown()
472-
473- def get_store_uri(self):
474- raise NotImplementedError
475-
476- def get_wrapper_class(self):
477- raise NotImplementedError
478-
479- def create_tables(self):
480- raise NotImplementedError
481-
482- def drop_tables(self):
483- raise NotImplementedError
484-
485- def test_create_wrapper(self):
486- wrapper = make_wrapper()
487- self.assertTrue(isinstance(wrapper, self.get_wrapper_class()))
488-
489- # The wrapper uses the same database connection as the store.
490- store = stores.get_store("django")
491- self.assertEqual(store._connection._raw_connection, wrapper.connection)
492-
493- def _isInTransaction(self, store):
494- """Check if a Store is part of the current transaction."""
495- for dm in transaction.get()._resources:
496- if isinstance(dm, StoreDataManager) and dm._store is store:
497- return True
498- return False
499-
500- def assertInTransaction(self, store):
501- """Check that the given store is joined to the transaction."""
502- self.assertTrue(self._isInTransaction(store),
503- "%r should be joined to the transaction" % store)
504-
505- def test_using_wrapper_joins_transaction(self):
506- wrapper = make_wrapper()
507- cursor = wrapper.cursor()
508- cursor.execute("SELECT 1")
509- self.assertInTransaction(stores.get_store("django"))
510-
511- def test_commit(self):
512- wrapper = make_wrapper()
513- cursor = wrapper.cursor()
514- cursor.execute("INSERT INTO django_test (title) VALUES ('foo')")
515- wrapper._commit()
516-
517- cursor = wrapper.cursor()
518- cursor.execute("SELECT title FROM django_test")
519- result = cursor.fetchall()
520- self.assertEqual(len(result), 1)
521- self.assertEqual(result[0][0], "foo")
522-
523- def test_rollback(self):
524- wrapper = make_wrapper()
525- cursor = wrapper.cursor()
526- cursor.execute("INSERT INTO django_test (title) VALUES ('foo')")
527- wrapper._rollback()
528-
529- cursor = wrapper.cursor()
530- cursor.execute("SELECT title FROM django_test")
531- result = cursor.fetchall()
532- self.assertEqual(len(result), 0)
533-
534- def test_register_transaction(self):
535- wrapper = make_wrapper()
536- store = global_zstorm.get("django")
537- # Watch for register-transaction calls.
538- calls = []
539- def register_transaction(owner):
540- calls.append(owner)
541- store._event.hook("register-transaction", register_transaction)
542-
543- cursor = wrapper.cursor()
544- cursor.execute("SELECT 1")
545- self.assertNotEqual(calls, [])
546-
547- def test_abort_transaction_on_failed_commit(self):
548- _transaction = transaction.get()
549- resource1 = self.mocker.mock()
550- self.expect(resource1.prepare).throw(AttributeError).count(0)
551- self.expect(resource1.tpc_begin(_transaction)).throw(DisconnectionError)
552- self.expect(resource1.abort(_transaction)).count(2)
553- self.expect(resource1.sortKey())
554- self.mocker.replay()
555-
556- _transaction.join(resource1)
557- wrapper = make_wrapper()
558- cursor = wrapper.cursor()
559- cursor.execute("INSERT INTO django_test (title) VALUES ('foo')")
560- self.assertRaises(DisconnectionError, wrapper._commit)
561-
562- # Calling _get_connection on the wrapper after a failed commit should
563- # work fine. Before the fix this would raise a
564- # 'TransactionFailedError'.
565- wrapper._get_connection()
566-
567-
568-class DjangoBackendDisconnectionTests(DatabaseDisconnectionMixin):
569-
570- def is_supported(self):
571- if not have_django_and_transaction:
572- return False
573- return DatabaseDisconnectionMixin.is_supported(self)
574-
575- def setUp(self):
576- super(DjangoBackendDisconnectionTests, self).setUp()
577- settings.configure(STORM_STORES={})
578-
579- settings.DATABASE_ENGINE = "storm.django.backend"
580- settings.DATABASE_NAME = "django"
581- settings.STORM_STORES["django"] = str(self.proxy_uri)
582- stores.have_configured_stores = False
583-
584- def tearDown(self):
585- transaction.abort()
586- if django.VERSION >= (1, 1):
587- if django.VERSION >= (1, 6):
588- from django.utils.functional import empty
589- else:
590- empty = None
591- settings._wrapped = empty
592- else:
593- settings._target = None
594- global_zstorm._reset()
595- stores.have_configured_stores = False
596- transaction.manager.free(transaction.get())
597- super(DjangoBackendDisconnectionTests, self).tearDown()
598-
599- def test_wb_disconnect(self):
600- wrapper = make_wrapper()
601- store = global_zstorm.get("django")
602- cursor = wrapper.cursor()
603- cursor.execute("SELECT 'about to reset connection'")
604- wrapper._rollback()
605- cursor = wrapper.cursor()
606- self.proxy.restart()
607- self.assertRaises(DisconnectionError, cursor.execute, "SELECT 1")
608- self.assertEqual(
609- store._connection._state, storm.database.STATE_DISCONNECTED)
610- wrapper._rollback()
611-
612- self.assertEqual(
613- store._connection._state, storm.database.STATE_RECONNECT)
614- cursor = wrapper.cursor()
615- cursor.execute("SELECT 1")
616-
617- def test_wb_transaction_registration(self):
618- wrapper = make_wrapper()
619- store = global_zstorm.get("django")
620- # Watch for register-transaction calls.
621- calls = []
622- def register_transaction(owner):
623- calls.append(owner)
624- store._event.hook("register-transaction", register_transaction)
625-
626- # Simulate a disconnection, and put the connection into a
627- # state where it would attempt to reconnect.
628- store._connection._raw_connection = None
629- store._connection._state = storm.database.STATE_RECONNECT
630- self.proxy.stop()
631-
632- self.assertRaises(DisconnectionError, wrapper.cursor)
633- # The connection is in the disconnected state, and has been
634- # registered with any listening transaction manager.
635- self.assertNotEqual(calls, [])
636- self.assertEqual(
637- store._connection._state, storm.database.STATE_DISCONNECTED)
638-
639- wrapper._rollback()
640- del calls[:]
641-
642- # Now reconnect:
643- self.proxy.start()
644- cursor = wrapper.cursor()
645- cursor.execute("SELECT 1")
646- # The connection is up, and has been registered with any
647- # listening transaction manager.
648- self.assertNotEqual(calls, [])
649- self.assertEqual(
650- store._connection._state, storm.database.STATE_CONNECTED)
651-
652-
653-class PostgresDjangoBackendTests(DjangoBackendTests, TestHelper):
654-
655- def get_store_uri(self):
656- return os.environ.get("STORM_POSTGRES_URI")
657-
658- def get_wrapper_class(self):
659- from storm.django.backend import base
660- return base.PostgresStormDatabaseWrapper
661-
662- def create_tables(self):
663- store = stores.get_store("django")
664- store.execute("CREATE TABLE django_test ("
665- " id SERIAL PRIMARY KEY,"
666- " title TEXT)")
667- transaction.commit()
668-
669- def drop_tables(self):
670- store = stores.get_store("django")
671- store.execute("DROP TABLE django_test")
672- transaction.commit()
673-
674-
675-class MySQLDjangoBackendTests(DjangoBackendTests, TestHelper):
676-
677- def get_store_uri(self):
678- return os.environ.get("STORM_MYSQL_URI")
679-
680- def get_wrapper_class(self):
681- from storm.django.backend import base
682- return base.MySQLStormDatabaseWrapper
683-
684- def create_tables(self):
685- store = stores.get_store("django")
686- store.execute("CREATE TABLE django_test ("
687- " id INT AUTO_INCREMENT PRIMARY KEY,"
688- " title TEXT) ENGINE=InnoDB")
689- transaction.commit()
690-
691- def drop_tables(self):
692- store = stores.get_store("django")
693- store.execute("DROP TABLE django_test")
694- transaction.commit()
695-
696-class PostgresDjangoBackendDisconnectionTests(
697- DjangoBackendDisconnectionTests, TestHelper):
698-
699- environment_variable = "STORM_POSTGRES_URI"
700- host_environment_variable = "STORM_POSTGRES_HOST_URI"
701- default_port = 5432
702-
703-
704-class MySQLDjangoBackendDisconnectionTests(
705- DjangoBackendDisconnectionTests, TestHelper):
706-
707- environment_variable = "STORM_MYSQL_URI"
708- host_environment_variable = "STORM_MYSQL_HOST_URI"
709- default_port = 3306
710
711=== removed file 'tests/django/middleware.py'
712--- tests/django/middleware.py 2015-01-25 09:29:29 +0000
713+++ tests/django/middleware.py 1970-01-01 00:00:00 +0000
714@@ -1,220 +0,0 @@
715-#
716-# Copyright (c) 2008 Canonical
717-#
718-# Written by James Henstridge <jamesh@canonical.com>
719-#
720-# This file is part of Storm Object Relational Mapper.
721-#
722-# Storm is free software; you can redistribute it and/or modify
723-# it under the terms of the GNU Lesser General Public License as
724-# published by the Free Software Foundation; either version 2.1 of
725-# the License, or (at your option) any later version.
726-#
727-# Storm is distributed in the hope that it will be useful,
728-# but WITHOUT ANY WARRANTY; without even the implied warranty of
729-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
730-# GNU Lesser General Public License for more details.
731-#
732-# You should have received a copy of the GNU Lesser General Public License
733-# along with this program. If not, see <http://www.gnu.org/licenses/>.
734-#
735-
736-from storm.exceptions import DisconnectionError
737-
738-try:
739- import django
740- import transaction
741-except ImportError:
742- have_django_and_transaction = False
743-else:
744- have_django_and_transaction = True
745- from django import conf
746- from django.http import HttpRequest, HttpResponse
747- from storm.django.middleware import ZopeTransactionMiddleware
748-
749-from tests.helper import TestHelper
750-
751-
752-class TransactionMiddlewareTests(TestHelper):
753-
754- def is_supported(self):
755- return have_django_and_transaction
756-
757- def setUp(self):
758- super(TransactionMiddlewareTests, self).setUp()
759- conf.settings.configure(STORM_COMMIT_SAFE_METHODS=False)
760- from django.db import transaction as django_transaction
761- self.django_transaction = django_transaction
762-
763- def tearDown(self):
764- if django.VERSION >= (1, 1):
765- if django.VERSION >= (1, 6):
766- from django.utils.functional import empty
767- else:
768- empty = None
769- conf.settings._wrapped = empty
770- else:
771- conf.settings._target = None
772- super(TransactionMiddlewareTests, self).tearDown()
773-
774- def test_process_request_begins_transaction(self):
775- begin = self.mocker.replace("transaction.begin")
776- enter_transaction_management = self.mocker.replace(
777- "django.db.transaction.enter_transaction_management")
778- managed = self.mocker.replace(
779- "django.db.transaction.managed")
780- enter_transaction_management()
781- managed(True)
782- begin()
783- self.mocker.replay()
784-
785- zope_middleware = ZopeTransactionMiddleware()
786- request = HttpRequest()
787- request.method = "GET"
788- zope_middleware.process_request(request)
789-
790- def test_process_exception_aborts_transaction(self):
791- abort = self.mocker.replace("transaction.abort")
792- leave_transaction_management = self.mocker.replace(
793- "django.db.transaction.leave_transaction_management")
794- set_clean = self.mocker.replace(
795- "django.db.transaction.set_clean")
796- abort()
797- set_clean()
798- leave_transaction_management()
799- self.mocker.replay()
800-
801- zope_middleware = ZopeTransactionMiddleware()
802- request = HttpRequest()
803- request.method = "GET"
804- exception = RuntimeError("some error")
805- zope_middleware.process_exception(request, exception)
806-
807- def test_process_response_commits_transaction_if_managed(self):
808- commit = self.mocker.replace("transaction.commit")
809- leave_transaction_management = self.mocker.replace(
810- "django.db.transaction.leave_transaction_management")
811- is_managed = self.mocker.replace(
812- "django.db.transaction.is_managed")
813- set_clean = self.mocker.replace(
814- "django.db.transaction.set_clean")
815- # We test three request methods
816- self.expect(is_managed()).result(True).count(3)
817- self.expect(commit()).count(3)
818- self.expect(set_clean()).count(3)
819- self.expect(leave_transaction_management()).count(3)
820- self.mocker.replay()
821-
822- # Commit on all methods
823- conf.settings.STORM_COMMIT_SAFE_METHODS = True
824-
825- zope_middleware = ZopeTransactionMiddleware()
826- request = HttpRequest()
827- response = HttpResponse()
828-
829- request.method = "GET"
830- zope_middleware.process_response(request, response)
831- request.method = "HEAD"
832- zope_middleware.process_response(request, response)
833- request.method = "POST"
834- zope_middleware.process_response(request, response)
835-
836- def test_process_response_aborts_transaction_for_safe_methods(self):
837- abort = self.mocker.replace("transaction.abort")
838- commit = self.mocker.replace("transaction.commit")
839- leave_transaction_management = self.mocker.replace(
840- "django.db.transaction.leave_transaction_management")
841- is_managed = self.mocker.replace(
842- "django.db.transaction.is_managed")
843- set_clean = self.mocker.replace(
844- "django.db.transaction.set_clean")
845- # We test three request methods
846- self.expect(is_managed()).result(True).count(3)
847- self.expect(abort()).count(2)
848- commit()
849- self.expect(set_clean()).count(3)
850- self.expect(leave_transaction_management()).count(3)
851- self.mocker.replay()
852-
853- # Don't commit on safe methods
854- conf.settings.STORM_COMMIT_SAFE_METHODS = False
855-
856- zope_middleware = ZopeTransactionMiddleware()
857- request = HttpRequest()
858- response = HttpResponse()
859-
860- request.method = "GET"
861- zope_middleware.process_response(request, response)
862- request.method = "HEAD"
863- zope_middleware.process_response(request, response)
864- request.method = "POST"
865- zope_middleware.process_response(request, response)
866-
867- def test_process_response_aborts_transaction_not_managed(self):
868- abort = self.mocker.replace("transaction.abort")
869- commit = self.mocker.replace("transaction.commit")
870- leave_transaction_management = self.mocker.replace(
871- "django.db.transaction.leave_transaction_management")
872- is_managed = self.mocker.replace(
873- "django.db.transaction.is_managed")
874- set_clean = self.mocker.replace(
875- "django.db.transaction.set_clean")
876-
877- self.expect(is_managed()).result(False).count(2)
878- # None of these methods should be called
879- self.expect(commit()).count(0)
880- self.expect(abort()).count(0)
881- self.expect(set_clean()).count(0)
882- self.expect(leave_transaction_management()).count(0)
883- self.mocker.replay()
884-
885- zope_middleware = ZopeTransactionMiddleware()
886- request = HttpRequest()
887- response = HttpResponse()
888-
889- request.method = "GET"
890- zope_middleware.process_response(request, response)
891-
892- # Try the same with a safe method.
893- conf.settings.STORM_COMMIT_SAFE_METHODS = False
894- zope_middleware = ZopeTransactionMiddleware()
895- zope_middleware.process_response(request, response)
896-
897- def test_process_response_aborts_transaction_on_failed_commit(self):
898- _transaction = transaction.get()
899- resource1 = self.mocker.mock()
900- self.expect(resource1.prepare).throw(AttributeError).count(0)
901- resource2 = self.mocker.mock()
902- self.expect(resource2.prepare).throw(AttributeError).count(0)
903- leave_transaction_management = self.mocker.replace(
904- "django.db.transaction.leave_transaction_management")
905- is_managed = self.mocker.replace(
906- "django.db.transaction.is_managed")
907- set_clean = self.mocker.replace(
908- "django.db.transaction.set_clean")
909-
910- self.expect(is_managed()).result(True).count(1)
911- self.expect(resource1.tpc_begin(_transaction)).throw(DisconnectionError)
912- self.expect(resource1.abort(_transaction)).count(2)
913- # None of these methods should be called
914- self.expect(set_clean()).count(0)
915- self.expect(leave_transaction_management()).count(0)
916- self.mocker.replay()
917-
918- _transaction.join(resource1)
919- zope_middleware = ZopeTransactionMiddleware()
920- request = HttpRequest()
921- response = HttpResponse()
922-
923- # Processing this response should fail on "commit()" with a
924- # DisconnectionError. The error is saved by
925- # "_saveAndRaiseCommitishError()", and re-raised, so we need to catch
926- # it and abort the transaction.
927- request.method = "POST"
928- self.assertRaises(DisconnectionError, zope_middleware.process_response,
929- request, response)
930-
931- # Now the transaction should have been cleared by "abort()". A resource
932- # joining the transaction manager should not fail with a
933- # "TransactionFailedError".
934- transaction.get().join(resource2)
935
936=== removed file 'tests/django/stores.py'
937--- tests/django/stores.py 2015-01-25 09:29:29 +0000
938+++ tests/django/stores.py 1970-01-01 00:00:00 +0000
939@@ -1,109 +0,0 @@
940-#
941-# Copyright (c) 2008 Canonical
942-#
943-# Written by James Henstridge <jamesh@canonical.com>
944-#
945-# This file is part of Storm Object Relational Mapper.
946-#
947-# Storm is free software; you can redistribute it and/or modify
948-# it under the terms of the GNU Lesser General Public License as
949-# published by the Free Software Foundation; either version 2.1 of
950-# the License, or (at your option) any later version.
951-#
952-# Storm is distributed in the hope that it will be useful,
953-# but WITHOUT ANY WARRANTY; without even the implied warranty of
954-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
955-# GNU Lesser General Public License for more details.
956-#
957-# You should have received a copy of the GNU Lesser General Public License
958-# along with this program. If not, see <http://www.gnu.org/licenses/>.
959-#
960-
961-import threading
962-
963-try:
964- import django
965- import transaction
966-except ImportError:
967- have_django_and_transaction = False
968-else:
969- have_django_and_transaction = True
970- from django import conf
971- from storm.django import stores
972- from storm.zope.zstorm import global_zstorm
973-
974-from storm.store import Store
975-from tests.helper import TestHelper
976-
977-
978-class DjangoStoreTests(TestHelper):
979-
980- def is_supported(self):
981- return have_django_and_transaction
982-
983- def setUp(self):
984- super(DjangoStoreTests, self).setUp()
985- conf.settings.configure(STORM_STORES={})
986-
987- def tearDown(self):
988- if django.VERSION >= (1, 1):
989- if django.VERSION >= (1, 6):
990- from django.utils.functional import empty
991- else:
992- empty = None
993- conf.settings._wrapped = empty
994- else:
995- conf.settings._target = None
996- # Reset the utility to cleanup the StoreSynchronizer's from the
997- # transaction.
998- global_zstorm._reset()
999- stores.have_configured_stores = False
1000- # Free the transaction to avoid having errors that cross
1001- # test cases.
1002- transaction.manager.free(transaction.get())
1003- super(DjangoStoreTests, self).tearDown()
1004-
1005- def test_configure_stores_configures_store_uris(self):
1006- conf.settings.MIDDLEWARE_CLASSES += (
1007- "storm.django.middleware.ZopeTransactionMiddleware",)
1008- conf.settings.STORM_STORES = {"name1": "sqlite:1",
1009- "name2": "sqlite:2",
1010- "name3": "sqlite:3"}
1011- stores.configure_stores(conf.settings)
1012- default_uris = global_zstorm.get_default_uris()
1013- self.assertEquals(default_uris, {"name1": "sqlite:1",
1014- "name2": "sqlite:2",
1015- "name3": "sqlite:3"})
1016-
1017- def test_get_store(self):
1018- conf.settings.MIDDLEWARE_CLASSES += (
1019- "storm.django.middleware.ZopeTransactionMiddleware",)
1020- conf.settings.STORM_STORES = {"name": "sqlite:"}
1021- store = stores.get_store("name")
1022- self.assertTrue(isinstance(store, Store))
1023- # Calling get_store() twice returns the same store.
1024- store2 = stores.get_store("name")
1025- self.assertTrue(store is store2)
1026-
1027- def test_get_store_returns_per_thread_stores(self):
1028- conf.settings.MIDDLEWARE_CLASSES += (
1029- "storm.django.middleware.ZopeTransactionMiddleware",)
1030- conf.settings.STORM_STORES = {"name": "sqlite:"}
1031-
1032- store = stores.get_store("name")
1033- other_stores = []
1034- def f():
1035- other_stores.append(stores.get_store("name"))
1036-
1037- thread = threading.Thread(target=f)
1038- thread.start()
1039- thread.join()
1040- self.assertEqual(len(other_stores), 1)
1041- self.assertNotEqual(other_stores[0], store)
1042-
1043- def test_get_store_uri(self):
1044- conf.settings.MIDDLEWARE_CLASSES += (
1045- "storm.django.middleware.ZopeTransactionMiddleware",)
1046- conf.settings.STORM_STORES = {"name": "sqlite:"}
1047-
1048- self.assertEqual(stores.get_store_uri("name"), "sqlite:")

Subscribers

People subscribed via source and target branches

to status/vote changes: