Merge lp:~ack/storm/drop-mysql-support into lp:storm

Proposed by Alberto Donato
Status: Merged
Approved by: Adam Collard
Approved revision: 482
Merged at revision: 486
Proposed branch: lp:~ack/storm/drop-mysql-support
Merge into: lp:storm
Diff against target: 784 lines (+15/-566)
10 files modified
Makefile (+0/-4)
README (+13/-42)
dev/db-setup (+0/-6)
dev/ubuntu-deps (+0/-2)
storm/databases/mysql.py (+0/-227)
tests/databases/base.py (+0/-2)
tests/databases/mysql.py (+0/-145)
tests/store/base.py (+0/-30)
tests/store/mysql.py (+0/-106)
tests/tutorial.txt (+2/-2)
To merge this branch: bzr merge lp:~ack/storm/drop-mysql-support
Reviewer Review Type Date Requested Status
Simon Poirier (community) Approve
Chad Smith (community) Approve
Review via email: mp+288652@code.launchpad.net

Description of the change

Drop support for MySQL.

To post a comment you must log in.
Revision history for this message
Chad Smith (chad.smith) wrote :

Thank you for the amazing branch. Since we are the only consumers of this project, makes sense to drop mysql and eventually sqlite support.

This merge proposal inspired me to reflect on life for about six months.

review: Approve
Revision history for this message
Simon Poirier (simpoir) wrote :

+1 with inline nitpick

review: Approve
lp:~ack/storm/drop-mysql-support updated
482. By Alberto Donato

Drop extra space.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2012-02-01 17:02:31 +0000
3+++ Makefile 2017-02-08 11:47:07 +0000
4@@ -6,13 +6,9 @@
5
6 STORM_POSTGRES_URI = postgres:storm_test
7 STORM_POSTGRES_HOST_URI = postgres://localhost:$(PGPORT)/storm_test
8-STORM_MYSQL_URI = mysql:storm_test
9-STORM_MYSQL_HOST_URI = mysql://localhost/storm_test
10
11 export STORM_POSTGRES_URI
12 export STORM_POSTGRES_HOST_URI
13-export STORM_MYSQL_URI
14-export STORM_MYSQL_HOST_URI
15
16 all: build
17
18
19=== modified file 'README'
20--- README 2016-03-01 13:09:28 +0000
21+++ README 2017-02-08 11:47:07 +0000
22@@ -22,8 +22,7 @@
23 * Storm is well designed (different classes have very clear
24 boundaries, with small and clean public APIs).
25 * Designed from day one to work both with thin relational
26- databases, such as SQLite, and big iron systems like PostgreSQL
27- and MySQL.
28+ databases, such as SQLite, and big iron systems like PostgreSQL.
29 * Storm is easy to debug, since its code is written with a KISS
30 principle, and thus is easy to understand.
31 * Designed from day one to work both at the low end, with trivial
32@@ -102,26 +101,18 @@
33 Installing dependencies
34 -----------------------
35
36-The following instructions assume that you're using Ubuntu. The
37-same procedure will probably work without changes on a Debian system
38-and with minimal changes on a non-Debian-based linux distribution.
39-In order to run the test suite, and exercise all supported backends,
40-you will need to install MySQL and PostgreSQL, along with the
41-related Python database drivers:
42+The following instructions assume that you're using Ubuntu. The same procedure
43+will probably work without changes on a Debian system and with minimal changes
44+on a non-Debian-based linux distribution. In order to run the test suite, and
45+exercise all supported backends, you will need to install PostgreSQL, along
46+with the related Python database drivers:
47
48 $ sudo apt-get install \
49- python-mysqldb mysql-server \
50 postgresql pgbouncer \
51 build-essential
52
53 These will take a few minutes to download (its a bit under 200MB all
54-together). Once the download is complete, a screen called
55-"configuring mysql-server-5.0" will be shown. When asked for a
56-password for the root user leave the field blank and hit enter to
57-continue. This is not a recommended setting for a production
58-server, but makes life easier on a development machine. You may be
59-asked to enter a password multiple times. Leave it blank in each
60-case.
61+together).
62
63 The Python dependencies for running tests can mostly be installed with
64 apt-get:
65@@ -167,38 +158,18 @@
66
67 $ sudo /etc/init.d/postgresql-8.4 restart
68
69-Next, you probably noticed that, while MySQL asked us about a root
70-user several times, PostgreSQL didn't ask us at all. Lets create
71-our PostgreSQL user now. As noted in the Ubuntu PostgreSQL
72-documentation, the easiest thing is to create a user with the same
73-name as your username. Run the following command to create a user
74-for yourself (if prompted for a password, leave it blank):
75+Lets create our PostgreSQL user now. As noted in the Ubuntu PostgreSQL
76+documentation, the easiest thing is to create a user with the same name as your
77+username. Run the following command to create a user for yourself (if prompted
78+for a password, leave it blank):
79
80 $ sudo -u postgres createuser --superuser $USER
81
82-Despite having created our root user already, MySQL requires an
83-extra step. First we start mysql as the root user (which, you may
84-recall, has no password) with:
85-
86- $ mysql -u root
87-
88-Then we create a new user. Be sure to replace YOUR_USERNAME with
89-your actual user name (leaving the quotes in place).
90-
91-mysql> GRANT ALL PRIVILEGES ON *.* TO 'YOUR_USERNAME'@'localhost'
92-IDENTIFIED BY '' WITH GRANT OPTION;
93-
94 Creating test databases
95 -----------------------
96
97-The test suite needs some local databases in place to exercise MySQL
98-and PostgreSQL functionality. While still at the MySQL command
99-prompt run:
100-
101-mysql> CREATE DATABASE storm_test CHARACTER SET utf8;
102-
103-Use Ctrl+D to exit, then, once back on the standard terminal, run
104-the command for PostgreSQL:
105+The test suite needs some local databases in place to exercise PostgreSQL
106+functionality. Run:
107
108 $ createdb storm_test
109
110
111=== modified file 'dev/db-setup'
112--- dev/db-setup 2013-02-26 21:39:56 +0000
113+++ dev/db-setup 2017-02-08 11:47:07 +0000
114@@ -3,7 +3,6 @@
115 PGHBA=/etc/postgresql/*/main/pg_hba.conf
116 PGCONF=/etc/postgresql/*/main/postgresql.conf
117 PGINIT=/etc/init.d/postgresql*
118-MYSQL_PRIVS="GRANT ALL PRIVILEGES ON *.* TO '$USER'@'localhost' IDENTIFIED BY '' WITH GRANT OPTION;"
119
120 is_number() {
121 test "$1" && printf '%f' "$1" >/dev/null;
122@@ -37,15 +36,10 @@
123 # If this fails, we will get errors later, so don't fail.
124 sudo -u postgres createuser --superuser $USER || /bin/true
125
126-echo " * Granting all mysql privs to $USER"
127-mysql -u root -e "$MYSQL_PRIVS"
128-
129 echo " * Create DB Test Fixtures (will fail if existing)"
130 createdb storm_test || /bin/true
131-mysql -u $USER -e "CREATE DATABASE storm_test CHARACTER SET utf8;" || /bin/true
132
133 echo " * Testing DB Access for user:$USER"
134 pg_dump storm_test > /dev/null
135-mysqldump -u $USER storm_test > /dev/null
136
137 echo " * All Done."
138
139=== modified file 'dev/ubuntu-deps'
140--- dev/ubuntu-deps 2016-03-01 13:15:05 +0000
141+++ dev/ubuntu-deps 2017-02-08 11:47:07 +0000
142@@ -6,8 +6,6 @@
143 }
144
145 apt_get install --no-install-recommends \
146- python-mysqldb \
147- mysql-server \
148 postgresql \
149 pgbouncer \
150 build-essential \
151
152=== removed file 'storm/databases/mysql.py'
153--- storm/databases/mysql.py 2015-06-15 12:02:12 +0000
154+++ storm/databases/mysql.py 1970-01-01 00:00:00 +0000
155@@ -1,227 +0,0 @@
156-#
157-# Copyright (c) 2006, 2007 Canonical
158-#
159-# Written by Gustavo Niemeyer <gustavo@niemeyer.net>
160-#
161-# This file is part of Storm Object Relational Mapper.
162-#
163-# Storm is free software; you can redistribute it and/or modify
164-# it under the terms of the GNU Lesser General Public License as
165-# published by the Free Software Foundation; either version 2.1 of
166-# the License, or (at your option) any later version.
167-#
168-# Storm is distributed in the hope that it will be useful,
169-# but WITHOUT ANY WARRANTY; without even the implied warranty of
170-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
171-# GNU Lesser General Public License for more details.
172-#
173-# You should have received a copy of the GNU Lesser General Public License
174-# along with this program. If not, see <http://www.gnu.org/licenses/>.
175-#
176-from datetime import time, timedelta
177-from array import array
178-import sys
179-
180-from storm.databases import dummy
181-
182-try:
183- import MySQLdb
184- import MySQLdb.converters
185-except ImportError:
186- MySQLdb = dummy
187-
188-from storm.expr import (
189- compile, Insert, Select, compile_select, Undef, And, Eq,
190- SQLRaw, SQLToken, is_safe_token)
191-from storm.variables import Variable
192-from storm.database import Database, Connection, Result
193-from storm.exceptions import (
194- install_exceptions, DatabaseModuleError, OperationalError)
195-from storm.variables import IntVariable
196-
197-
198-install_exceptions(MySQLdb)
199-
200-
201-compile = compile.create_child()
202-
203-@compile.when(Select)
204-def compile_select_mysql(compile, select, state):
205- if select.offset is not Undef and select.limit is Undef:
206- select.limit = sys.maxint
207- return compile_select(compile, select, state)
208-
209-@compile.when(SQLToken)
210-def compile_sql_token_mysql(compile, expr, state):
211- """MySQL uses ` as the escape character by default."""
212- if is_safe_token(expr) and not compile.is_reserved_word(expr):
213- return expr
214- return '`%s`' % expr.replace('`', '``')
215-
216-
217-class MySQLResult(Result):
218-
219- @staticmethod
220- def from_database(row):
221- """Convert MySQL-specific datatypes to "normal" Python types.
222-
223- If there are any C{array} instances in the row, convert them
224- to strings.
225- """
226- for value in row:
227- if isinstance(value, array):
228- yield value.tostring()
229- else:
230- yield value
231-
232-
233-class MySQLConnection(Connection):
234-
235- result_factory = MySQLResult
236- param_mark = "%s"
237- compile = compile
238-
239- def execute(self, statement, params=None, noresult=False):
240- if (isinstance(statement, Insert) and
241- statement.primary_variables is not Undef):
242-
243- result = Connection.execute(self, statement, params)
244-
245- # The lastrowid value will be set if:
246- # - the table had an AUTO INCREMENT column, and
247- # - the column was not set during the insert or set to 0
248- #
249- # If these conditions are met, then lastrowid will be the
250- # value of the first such column set. We assume that it
251- # is the first undefined primary key variable.
252- if result._raw_cursor.lastrowid:
253- for variable in statement.primary_variables:
254- if not variable.is_defined():
255- variable.set(result._raw_cursor.lastrowid,
256- from_db=True)
257- break
258- if noresult:
259- result = None
260- return result
261- return Connection.execute(self, statement, params, noresult)
262-
263- def to_database(self, params):
264- for param in params:
265- if isinstance(param, Variable):
266- param = param.get(to_db=True)
267- if isinstance(param, timedelta):
268- yield str(param)
269- else:
270- yield param
271-
272- def is_disconnection_error(self, exc, extra_disconnection_errors=()):
273- # http://dev.mysql.com/doc/refman/5.0/en/gone-away.html
274- return (isinstance(exc, (OperationalError,
275- extra_disconnection_errors)) and
276- exc.args[0] in (2006, 2013)) # (SERVER_GONE_ERROR, SERVER_LOST)
277-
278-
279-class MySQL(Database):
280-
281- connection_factory = MySQLConnection
282- _converters = None
283-
284- def __init__(self, uri):
285- super(MySQL, self).__init__(uri)
286- if MySQLdb is dummy:
287- raise DatabaseModuleError("'MySQLdb' module not found")
288- self._connect_kwargs = {}
289- if uri.database is not None:
290- self._connect_kwargs["db"] = uri.database
291- if uri.host is not None:
292- self._connect_kwargs["host"] = uri.host
293- if uri.port is not None:
294- self._connect_kwargs["port"] = uri.port
295- if uri.username is not None:
296- self._connect_kwargs["user"] = uri.username
297- if uri.password is not None:
298- self._connect_kwargs["passwd"] = uri.password
299- for option in ["unix_socket"]:
300- if option in uri.options:
301- self._connect_kwargs[option] = uri.options.get(option)
302-
303- if self._converters is None:
304- # MySQLdb returns a timedelta by default on TIME fields.
305- converters = MySQLdb.converters.conversions.copy()
306- converters[MySQLdb.converters.FIELD_TYPE.TIME] = _convert_time
307- self.__class__._converters = converters
308-
309- self._connect_kwargs["conv"] = self._converters
310- self._connect_kwargs["use_unicode"] = True
311- self._connect_kwargs["charset"] = uri.options.get("charset", "utf8")
312-
313- def raw_connect(self):
314- raw_connection = MySQLdb.connect(**self._connect_kwargs)
315-
316- # Here is another sad story about bad transactional behavior. MySQL
317- # offers a feature to automatically reconnect dropped connections.
318- # What sounds like a dream, is actually a nightmare for anyone who
319- # is dealing with transactions. When a reconnection happens, the
320- # currently running transaction is transparently rolled back, and
321- # everything that was being done is lost, without notice. Not only
322- # that, but the connection may be put back in AUTOCOMMIT mode, even
323- # when that's not the default MySQLdb behavior. The MySQL developers
324- # quickly understood that this is a terrible idea, and removed the
325- # behavior in MySQL 5.0.3. Unfortunately, Debian and Ubuntu still
326- # have a patch for the MySQLdb module which *reenables* that
327- # behavior by default even past version 5.0.3 of MySQL.
328- #
329- # Some links:
330- # http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html
331- # http://dev.mysql.com/doc/refman/5.0/en/mysql-reconnect.html
332- # http://dev.mysql.com/doc/refman/5.0/en/gone-away.html
333- #
334- # What we do here is to explore something that is a very weird
335- # side-effect, discovered by reading the code. When we call the
336- # ping() with a False argument, the automatic reconnection is
337- # disabled in a *permanent* way for this connection. The argument
338- # to ping() is new in 1.2.2, though.
339- if MySQLdb.version_info >= (1, 2, 2):
340- raw_connection.ping(False)
341-
342- return raw_connection
343-
344-
345-create_from_uri = MySQL
346-
347-
348-def _convert_time(time_str):
349- h, m, s = time_str.split(":")
350- if "." in s:
351- f = float(s)
352- s = int(f)
353- return time(int(h), int(m), s, (f-s)*1000000)
354- return time(int(h), int(m), int(s), 0)
355-
356-
357-# --------------------------------------------------------------------
358-# Reserved words, MySQL specific
359-
360-# The list of reserved words here are MySQL specific. SQL92 reserved words
361-# are registered in storm.expr, near the "Reserved words, from SQL1992"
362-# comment. The reserved words here were taken from:
363-#
364-# http://dev.mysql.com/doc/refman/5.4/en/reserved-words.html
365-compile.add_reserved_words("""
366- accessible analyze asensitive before bigint binary blob call change
367- condition current_user database databases day_hour day_microsecond
368- day_minute day_second delayed deterministic distinctrow div dual each
369- elseif enclosed escaped exit explain float4 float8 force fulltext
370- high_priority hour_microsecond hour_minute hour_second if ignore index
371- infile inout int1 int2 int3 int4 int8 iterate keys kill leave limit linear
372- lines load localtime localtimestamp lock long longblob longtext loop
373- low_priority master_ssl_verify_server_cert mediumblob mediumint mediumtext
374- middleint minute_microsecond minute_second mod modifies no_write_to_binlog
375- optimize optionally out outfile purge range read_write reads regexp
376- release rename repeat replace require return rlike schemas
377- second_microsecond sensitive separator show spatial specific
378- sql_big_result sql_calc_found_rows sql_small_result sqlexception
379- sqlwarning ssl starting straight_join terminated tinyblob tinyint tinytext
380- trigger undo unlock unsigned use utc_date utc_time utc_timestamp varbinary
381- varcharacter while xor year_month zerofill
382- """.split())
383
384=== modified file 'tests/databases/base.py'
385--- tests/databases/base.py 2015-06-15 12:06:44 +0000
386+++ tests/databases/base.py 2017-02-08 11:47:07 +0000
387@@ -330,8 +330,6 @@
388 that works with data in memory, in fact) becomes a dangerous thing.
389
390 For PostgreSQL, isolation level must be SERIALIZABLE.
391- For MySQL, isolation level must be REPEATABLE READ (the default),
392- and the InnoDB engine must be in use.
393 For SQLite, the isolation level already is SERIALIZABLE when not
394 in autocommit mode. OTOH, PySQLite is nuts regarding transactional
395 behavior, and will easily offer READ COMMITTED behavior inside a
396
397=== removed file 'tests/databases/mysql.py'
398--- tests/databases/mysql.py 2009-09-21 17:03:08 +0000
399+++ tests/databases/mysql.py 1970-01-01 00:00:00 +0000
400@@ -1,145 +0,0 @@
401-#
402-# Copyright (c) 2006, 2007 Canonical
403-#
404-# Written by Gustavo Niemeyer <gustavo@niemeyer.net>
405-#
406-# This file is part of Storm Object Relational Mapper.
407-#
408-# Storm is free software; you can redistribute it and/or modify
409-# it under the terms of the GNU Lesser General Public License as
410-# published by the Free Software Foundation; either version 2.1 of
411-# the License, or (at your option) any later version.
412-#
413-# Storm is distributed in the hope that it will be useful,
414-# but WITHOUT ANY WARRANTY; without even the implied warranty of
415-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
416-# GNU Lesser General Public License for more details.
417-#
418-# You should have received a copy of the GNU Lesser General Public License
419-# along with this program. If not, see <http://www.gnu.org/licenses/>.
420-#
421-import os
422-
423-from storm.databases.mysql import MySQL
424-from storm.database import create_database
425-from storm.expr import Column, Insert
426-from storm.uri import URI
427-from storm.variables import IntVariable, UnicodeVariable
428-
429-from tests.databases.base import (
430- DatabaseTest, DatabaseDisconnectionTest, UnsupportedDatabaseTest)
431-from tests.helper import TestHelper
432-
433-
434-class MySQLTest(DatabaseTest, TestHelper):
435-
436- supports_microseconds = False
437-
438- def is_supported(self):
439- return bool(os.environ.get("STORM_MYSQL_URI"))
440-
441- def create_database(self):
442- self.database = create_database(os.environ["STORM_MYSQL_URI"])
443-
444- def create_tables(self):
445- self.connection.execute("CREATE TABLE number "
446- "(one INTEGER, two INTEGER, three INTEGER)")
447- self.connection.execute("CREATE TABLE test "
448- "(id INT AUTO_INCREMENT PRIMARY KEY,"
449- " title VARCHAR(50)) ENGINE=InnoDB")
450- self.connection.execute("CREATE TABLE datetime_test "
451- "(id INT AUTO_INCREMENT PRIMARY KEY,"
452- " dt TIMESTAMP, d DATE, t TIME, td TEXT) "
453- "ENGINE=InnoDB")
454- self.connection.execute("CREATE TABLE bin_test "
455- "(id INT AUTO_INCREMENT PRIMARY KEY,"
456- " b BLOB) ENGINE=InnoDB")
457-
458- def test_wb_create_database(self):
459- database = create_database("mysql://un:pw@ht:12/db?unix_socket=us")
460- self.assertTrue(isinstance(database, MySQL))
461- for key, value in [("db", "db"), ("host", "ht"), ("port", 12),
462- ("user", "un"), ("passwd", "pw"),
463- ("unix_socket", "us")]:
464- self.assertEquals(database._connect_kwargs.get(key), value)
465-
466- def test_charset_defaults_to_utf8(self):
467- result = self.connection.execute("SELECT @@character_set_client")
468- self.assertEquals(result.get_one(), ("utf8",))
469-
470- def test_charset_option(self):
471- uri = URI(os.environ["STORM_MYSQL_URI"])
472- uri.options["charset"] = "ascii"
473- database = create_database(uri)
474- connection = database.connect()
475- result = connection.execute("SELECT @@character_set_client")
476- self.assertEquals(result.get_one(), ("ascii",))
477-
478- def test_get_insert_identity(self):
479- # Primary keys are filled in during execute() for MySQL
480- pass
481-
482- def test_get_insert_identity_composed(self):
483- # Primary keys are filled in during execute() for MySQL
484- pass
485-
486- def test_execute_insert_auto_increment_primary_key(self):
487- id_column = Column("id", "test")
488- id_variable = IntVariable()
489- title_column = Column("title", "test")
490- title_variable = UnicodeVariable(u"testing")
491-
492- # This is not part of the table. It is just used to show that
493- # only one primary key variable is set from the insert ID.
494- dummy_column = Column("dummy", "test")
495- dummy_variable = IntVariable()
496-
497- insert = Insert({title_column: title_variable},
498- primary_columns=(id_column, dummy_column),
499- primary_variables=(id_variable, dummy_variable))
500- self.connection.execute(insert)
501- self.assertTrue(id_variable.is_defined())
502- self.assertFalse(dummy_variable.is_defined())
503-
504- # The newly inserted row should have the maximum id value for
505- # the table.
506- result = self.connection.execute("SELECT MAX(id) FROM test")
507- self.assertEqual(result.get_one()[0], id_variable.get())
508-
509- def test_mysql_specific_reserved_words(self):
510- reserved_words = """
511- accessible analyze asensitive before bigint binary blob call
512- change condition current_user database databases day_hour
513- day_microsecond day_minute day_second delayed deterministic
514- distinctrow div dual each elseif enclosed escaped exit explain
515- float4 float8 force fulltext high_priority hour_microsecond
516- hour_minute hour_second if ignore index infile inout int1 int2
517- int3 int4 int8 iterate keys kill leave limit linear lines load
518- localtime localtimestamp lock long longblob longtext loop
519- low_priority master_ssl_verify_server_cert mediumblob mediumint
520- mediumtext middleint minute_microsecond minute_second mod modifies
521- no_write_to_binlog optimize optionally out outfile purge range
522- read_write reads regexp release rename repeat replace require
523- return rlike schemas second_microsecond sensitive separator show
524- spatial specific sql_big_result sql_calc_found_rows
525- sql_small_result sqlexception sqlwarning ssl starting
526- straight_join terminated tinyblob tinyint tinytext trigger undo
527- unlock unsigned use utc_date utc_time utc_timestamp varbinary
528- varcharacter while xor year_month zerofill
529- """.split()
530- for word in reserved_words:
531- self.assertTrue(self.connection.compile.is_reserved_word(word),
532- "Word missing: %s" % (word,))
533-
534-
535-class MySQLUnsupportedTest(UnsupportedDatabaseTest, TestHelper):
536-
537- dbapi_module_names = ["MySQLdb"]
538- db_module_name = "mysql"
539-
540-
541-class MySQLDisconnectionTest(DatabaseDisconnectionTest, TestHelper):
542-
543- environment_variable = "STORM_MYSQL_URI"
544- host_environment_variable = "STORM_MYSQL_HOST_URI"
545- default_port = 3306
546
547=== modified file 'tests/store/base.py'
548--- tests/store/base.py 2016-05-13 18:55:24 +0000
549+++ tests/store/base.py 2017-02-08 11:47:07 +0000
550@@ -869,8 +869,6 @@
551 result2 = self.store.find(Foo, Foo.id != 10)
552 self.assertEquals(foo in result1.union(result2), True)
553
554- if self.__class__.__name__.startswith("MySQL"):
555- return
556 self.assertEquals(foo in result1.intersection(result2), False)
557 self.assertEquals(foo in result1.intersection(result1), True)
558 self.assertEquals(foo in result1.difference(result2), True)
559@@ -1322,8 +1320,6 @@
560 result2 = self.store.find((Foo, Bar), Bar.foo_id == Foo.id)
561 self.assertEquals((foo, bar) in result1.union(result2), True)
562
563- if self.__class__.__name__.startswith("MySQL"):
564- return
565 self.assertEquals((foo, bar) in result1.intersection(result2), True)
566 self.assertEquals((foo, bar) in result1.difference(result2), False)
567
568@@ -1440,8 +1436,6 @@
569 result2 = self.store.find(Foo.title)
570 self.assertEquals(u"Title 10" in result1.union(result2), True)
571
572- if self.__class__.__name__.startswith("MySQL"):
573- return
574 self.assertEquals(u"Title 10" in result1.intersection(result2), True)
575 self.assertEquals(u"Title 10" in result1.difference(result2), False)
576
577@@ -5633,9 +5627,6 @@
578 self.assertEquals(result3.avg(Foo.id), 10)
579
580 def test_result_difference(self):
581- if self.__class__.__name__.startswith("MySQL"):
582- return
583-
584 result1 = self.store.find(Foo)
585 result2 = self.store.find(Foo, id=20)
586 result3 = result1.difference(result2)
587@@ -5653,9 +5644,6 @@
588 ])
589
590 def test_result_difference_with_empty(self):
591- if self.__class__.__name__.startswith("MySQL"):
592- return
593-
594 result1 = self.store.find(Foo, id=30)
595 result2 = EmptyResultSet()
596
597@@ -5666,17 +5654,11 @@
598 ])
599
600 def test_result_difference_incompatible(self):
601- if self.__class__.__name__.startswith("MySQL"):
602- return
603-
604 result1 = self.store.find(Foo, id=10)
605 result2 = self.store.find(Bar, id=100)
606 self.assertRaises(FeatureError, result1.difference, result2)
607
608 def test_result_difference_count(self):
609- if self.__class__.__name__.startswith("MySQL"):
610- return
611-
612 result1 = self.store.find(Foo)
613 result2 = self.store.find(Foo, id=20)
614
615@@ -5694,9 +5676,6 @@
616 self.assertEquals(result2.count(), 3)
617
618 def test_result_intersection(self):
619- if self.__class__.__name__.startswith("MySQL"):
620- return
621-
622 result1 = self.store.find(Foo)
623 result2 = self.store.find(Foo, Foo.id.is_in((10, 30)))
624 result3 = result1.intersection(result2)
625@@ -5714,9 +5693,6 @@
626 ])
627
628 def test_result_intersection_with_empty(self):
629- if self.__class__.__name__.startswith("MySQL"):
630- return
631-
632 result1 = self.store.find(Foo, id=30)
633 result2 = EmptyResultSet()
634 result3 = result1.intersection(result2)
635@@ -5724,17 +5700,11 @@
636 self.assertEquals(len(list(result3)), 0)
637
638 def test_result_intersection_incompatible(self):
639- if self.__class__.__name__.startswith("MySQL"):
640- return
641-
642 result1 = self.store.find(Foo, id=10)
643 result2 = self.store.find(Bar, id=100)
644 self.assertRaises(FeatureError, result1.intersection, result2)
645
646 def test_result_intersection_count(self):
647- if self.__class__.__name__.startswith("MySQL"):
648- return
649-
650 result1 = self.store.find(Foo, Foo.id.is_in((10, 20)))
651 result2 = self.store.find(Foo, Foo.id.is_in((10, 30)))
652 result3 = result1.intersection(result2)
653
654=== removed file 'tests/store/mysql.py'
655--- tests/store/mysql.py 2011-02-14 12:17:54 +0000
656+++ tests/store/mysql.py 1970-01-01 00:00:00 +0000
657@@ -1,106 +0,0 @@
658-#
659-# Copyright (c) 2006, 2007 Canonical
660-#
661-# Written by Gustavo Niemeyer <gustavo@niemeyer.net>
662-#
663-# This file is part of Storm Object Relational Mapper.
664-#
665-# Storm is free software; you can redistribute it and/or modify
666-# it under the terms of the GNU Lesser General Public License as
667-# published by the Free Software Foundation; either version 2.1 of
668-# the License, or (at your option) any later version.
669-#
670-# Storm is distributed in the hope that it will be useful,
671-# but WITHOUT ANY WARRANTY; without even the implied warranty of
672-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
673-# GNU Lesser General Public License for more details.
674-#
675-# You should have received a copy of the GNU Lesser General Public License
676-# along with this program. If not, see <http://www.gnu.org/licenses/>.
677-#
678-import os
679-
680-from storm.database import create_database
681-
682-from tests.store.base import StoreTest, EmptyResultSetTest
683-from tests.helper import TestHelper
684-
685-
686-class MySQLStoreTest(TestHelper, StoreTest):
687-
688- def setUp(self):
689- TestHelper.setUp(self)
690- StoreTest.setUp(self)
691-
692- def tearDown(self):
693- TestHelper.tearDown(self)
694- StoreTest.tearDown(self)
695-
696- def is_supported(self):
697- return bool(os.environ.get("STORM_MYSQL_URI"))
698-
699- def create_database(self):
700- self.database = create_database(os.environ["STORM_MYSQL_URI"])
701-
702- def create_tables(self):
703- connection = self.connection
704- connection.execute("CREATE TABLE foo "
705- "(id INT PRIMARY KEY AUTO_INCREMENT,"
706- " title VARCHAR(50) DEFAULT 'Default Title') "
707- "ENGINE=InnoDB")
708- connection.execute("CREATE TABLE bar "
709- "(id INT PRIMARY KEY AUTO_INCREMENT,"
710- " foo_id INTEGER, title VARCHAR(50)) "
711- "ENGINE=InnoDB")
712- connection.execute("CREATE TABLE bin "
713- "(id INT PRIMARY KEY AUTO_INCREMENT,"
714- " bin BLOB, foo_id INTEGER) "
715- "ENGINE=InnoDB")
716- connection.execute("CREATE TABLE link "
717- "(foo_id INTEGER, bar_id INTEGER,"
718- " PRIMARY KEY (foo_id, bar_id)) "
719- "ENGINE=InnoDB")
720- connection.execute("CREATE TABLE money "
721- "(id INT PRIMARY KEY AUTO_INCREMENT,"
722- " value NUMERIC(6,4)) "
723- "ENGINE=InnoDB")
724- connection.execute("CREATE TABLE selfref "
725- "(id INT PRIMARY KEY AUTO_INCREMENT,"
726- " title VARCHAR(50),"
727- " selfref_id INTEGER,"
728- " INDEX (selfref_id),"
729- " FOREIGN KEY (selfref_id) REFERENCES selfref(id)) "
730- "ENGINE=InnoDB")
731- connection.execute("CREATE TABLE foovalue "
732- "(id INT PRIMARY KEY AUTO_INCREMENT,"
733- " foo_id INTEGER,"
734- " value1 INTEGER, value2 INTEGER) "
735- "ENGINE=InnoDB")
736- connection.execute("CREATE TABLE unique_id "
737- "(id VARCHAR(36) PRIMARY KEY) "
738- "ENGINE=InnoDB")
739- connection.commit()
740-
741-
742-class MySQLEmptyResultSetTest(TestHelper, EmptyResultSetTest):
743-
744- def setUp(self):
745- TestHelper.setUp(self)
746- EmptyResultSetTest.setUp(self)
747-
748- def tearDown(self):
749- TestHelper.tearDown(self)
750- EmptyResultSetTest.tearDown(self)
751-
752- def is_supported(self):
753- return bool(os.environ.get("STORM_MYSQL_URI"))
754-
755- def create_database(self):
756- self.database = create_database(os.environ["STORM_MYSQL_URI"])
757-
758- def create_tables(self):
759- self.connection.execute("CREATE TABLE foo "
760- "(id INT PRIMARY KEY AUTO_INCREMENT,"
761- " title VARCHAR(50) DEFAULT 'Default Title') "
762- "ENGINE=InnoDB")
763- self.connection.commit()
764
765=== modified file 'tests/tutorial.txt'
766--- tests/tutorial.txt 2010-08-02 17:42:54 +0000
767+++ tests/tutorial.txt 2017-02-08 11:47:07 +0000
768@@ -43,14 +43,14 @@
769 >>>
770 }}}
771
772-Three databases are supported at the moment: SQLite, MySQL and PostgreSQL.
773+Two databases are supported at the moment: SQLite and PostgreSQL.
774 The parameter passed to `create_database()` is an URI, as follows:
775
776 {{{
777 database = create_database("scheme://username:password@hostname:port/database_name")
778 }}}
779
780-The scheme may be "sqlite", "postgres", or "mysql".
781+The scheme may be "sqlite" or "postgres".
782
783 Now we have to create the table that will actually hold the data
784 for our class.

Subscribers

People subscribed via source and target branches

to status/vote changes: