From 1025488f3684415002f331fa2e557be7cdb447bb Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 3 Dec 2011 13:29:05 -0500 Subject: [PATCH] - Clean up file write operations so that file handles are closed. - PyPy is supported. --- CHANGES | 7 +++ alembic/__init__.py | 2 +- alembic/autogenerate.py | 2 +- alembic/script.py | 3 +- alembic/util.py | 9 ++- setup.py | 2 + tests/__init__.py | 20 +++--- tests/test_autogenerate.py | 101 ++++++++++++++---------------- tests/test_mssql.py | 4 +- tests/test_offline_environment.py | 4 +- tests/test_postgresql.py | 11 ++-- tests/test_sql_script.py | 4 +- 12 files changed, 86 insertions(+), 83 deletions(-) diff --git a/CHANGES b/CHANGES index 38b20499..a60f041e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +0.1.1 +===== +- Clean up file write operations so that + file handles are closed. + +- PyPy is supported. + 0.1.0 ===== - Initial release. Status of features: diff --git a/alembic/__init__.py b/alembic/__init__.py index f7507f86..1ed8a203 100644 --- a/alembic/__init__.py +++ b/alembic/__init__.py @@ -1,6 +1,6 @@ from os import path -__version__ = '0.1.0' +__version__ = '0.1.1' package_dir = path.abspath(path.dirname(__file__)) diff --git a/alembic/autogenerate.py b/alembic/autogenerate.py index acb61d8e..31eafee8 100644 --- a/alembic/autogenerate.py +++ b/alembic/autogenerate.py @@ -78,7 +78,7 @@ def _produce_net_changes(connection, metadata, diffs, autogen_context): for tname in existing_tables ) - for tname in existing_tables: + for tname in sorted(existing_tables): _compare_columns(tname, conn_column_info[tname], metadata.tables[tname], diff --git a/alembic/script.py b/alembic/script.py index f5d3212d..770c6506 100644 --- a/alembic/script.py +++ b/alembic/script.py @@ -148,7 +148,8 @@ class ScriptDirectory(object): def write(self, rev_id, content): path = self._rev_path(rev_id) - open(path, 'w').write(content) + with open(path, 'w') as fp: + fp.write(content) pyc_path = util.pyc_file_from_path(path) if os.access(pyc_path, os.F_OK): os.unlink(pyc_path) diff --git a/alembic/util.py b/alembic/util.py index aa5d0e25..c61040f9 100644 --- a/alembic/util.py +++ b/alembic/util.py @@ -35,11 +35,10 @@ except (KeyError, ValueError): width = 80 def template_to_file(template_file, dest, **kw): - f = open(dest, 'w') - f.write( - Template(filename=template_file).render(**kw) - ) - f.close() + with open(dest, 'w') as f: + f.write( + Template(filename=template_file).render(**kw) + ) def status(_statmsg, fn, *arg, **kw): diff --git a/setup.py b/setup.py index 571e7e9e..298b2fbb 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,8 @@ setup(name='alembic', 'Intended Audience :: Developers', 'Programming Language :: Python', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Database :: Front-Ends', ], keywords='SQLAlchemy migrations', diff --git a/tests/__init__.py b/tests/__init__.py index 10ce3ae4..e94079d6 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -117,12 +117,6 @@ def assert_raises_message(except_cls, msg, callable_, *args, **kwargs): assert re.search(msg, str(e)), "%r !~ %s" % (msg, e) print str(e) -def _testing_config(): - from alembic.config import Config - if not os.access(staging_directory, os.F_OK): - os.mkdir(staging_directory) - return Config(os.path.join(staging_directory, 'test_alembic.ini')) - def op_fixture(dialect='default', as_sql=False): impl = _impls[dialect] class Impl(impl): @@ -181,7 +175,8 @@ config = context.config if os.access(pyc_path, os.F_OK): os.unlink(pyc_path) - open(path, 'w').write(txt) + with open(path, 'w') as f: + f.write(txt) def _sqlite_testing_config(): dir_ = os.path.join(staging_directory, 'scripts') @@ -216,7 +211,7 @@ datefmt = %%H:%%M:%%S """ % (dir_, dir_)) -def no_sql_testing_config(dialect="postgresql"): +def _no_sql_testing_config(dialect="postgresql"): """use a postgresql url with no host so that connections guaranteed to fail""" dir_ = os.path.join(staging_directory, 'scripts') return _write_config_file(""" @@ -252,9 +247,16 @@ datefmt = %%H:%%M:%%S def _write_config_file(text): cfg = _testing_config() - open(cfg.config_file_name, 'w').write(text) + with open(cfg.config_file_name, 'w') as f: + f.write(text) return cfg +def _testing_config(): + from alembic.config import Config + if not os.access(staging_directory, os.F_OK): + os.mkdir(staging_directory) + return Config(os.path.join(staging_directory, 'test_alembic.ini')) + def staging_env(create=True, template="generic"): from alembic import command, script diff --git a/tests/test_autogenerate.py b/tests/test_autogenerate.py index 1f64db83..721f86fd 100644 --- a/tests/test_autogenerate.py +++ b/tests/test_autogenerate.py @@ -5,7 +5,7 @@ from alembic import autogenerate, context from unittest import TestCase from tests import staging_env, sqlite_db, clear_staging_env, eq_, \ eq_ignore_whitespace, requires_07 - +import re import sys py3k = sys.version_info >= (3, ) @@ -109,47 +109,43 @@ class AutogenerateDiffTest(TestCase): eq_(diffs[1][0], 'remove_table') eq_(diffs[1][1].name, "extra") - eq_(diffs[2][0], 'remove_column') - eq_(diffs[2][2].name, 'pw') + eq_(diffs[2][0], "add_column") + eq_(diffs[2][1], "address") + eq_(diffs[2][2], metadata.tables['address'].c.street) + + eq_(diffs[3][0], "add_column") + eq_(diffs[3][1], "order") + eq_(diffs[3][2], metadata.tables['order'].c.user_id) - eq_(diffs[3][0][0], "modify_default") - eq_(diffs[3][0][1], "user") - eq_(diffs[3][0][2], "a1") - eq_(diffs[3][0][5].arg, "x") + eq_(diffs[4][0][0], "modify_type") + eq_(diffs[4][0][1], "order") + eq_(diffs[4][0][2], "amount") + eq_(repr(diffs[4][0][4]), "NUMERIC(precision=8, scale=2)") + eq_(repr(diffs[4][0][5]), "Numeric(precision=10, scale=2)") - eq_(diffs[4][0][0], 'modify_nullable') - eq_(diffs[4][0][4], True) - eq_(diffs[4][0][5], False) - eq_(diffs[5][0], "add_column") - eq_(diffs[5][1], "order") - eq_(diffs[5][2], metadata.tables['order'].c.user_id) + eq_(diffs[5][0], 'remove_column') + eq_(diffs[5][2].name, 'pw') - eq_(diffs[6][0][0], "modify_type") - eq_(diffs[6][0][1], "order") - eq_(diffs[6][0][2], "amount") - eq_(repr(diffs[6][0][4]), "NUMERIC(precision=8, scale=2)") - eq_(repr(diffs[6][0][5]), "Numeric(precision=10, scale=2)") + eq_(diffs[6][0][0], "modify_default") + eq_(diffs[6][0][1], "user") + eq_(diffs[6][0][2], "a1") + eq_(diffs[6][0][5].arg, "x") + + eq_(diffs[7][0][0], 'modify_nullable') + eq_(diffs[7][0][4], True) + eq_(diffs[7][0][5], False) - eq_(diffs[6][1][0], 'modify_nullable') - eq_(diffs[6][1][4], False) - eq_(diffs[6][1][5], True) - eq_(diffs[7][0], "add_column") - eq_(diffs[7][1], "address") - eq_(diffs[7][2], metadata.tables['address'].c.street) def test_render_diffs(self): """test a full render including indentation""" - # TODO: this test isn't going - # to be so spectacular on Py3K... - metadata = self.m2 template_args = {} autogenerate.produce_migration_diffs(template_args, self.autogen_context) - eq_(template_args['upgrades'], + eq_(re.sub(r"u'", "'", template_args['upgrades']), """### commands auto generated by Alembic - please adjust! ### create_table('item', sa.Column('id', sa.Integer(), nullable=False), @@ -158,8 +154,15 @@ class AutogenerateDiffTest(TestCase): sa.ForeignKeyConstraint([order_id], ['order.order_id'], ), sa.PrimaryKeyConstraint('id') ) - drop_table(%(u)s'extra') - drop_column('user', %(u)s'pw') + drop_table('extra') + add_column('address', sa.Column('street', sa.String(length=50), nullable=True)) + add_column('order', sa.Column('user_id', sa.Integer(), nullable=True)) + alter_column('order', 'amount', + existing_type=sa.NUMERIC(precision=8, scale=2), + type_=sa.Numeric(precision=10, scale=2), + nullable=True, + existing_server_default='0') + drop_column('user', 'pw') alter_column('user', 'a1', existing_type=sa.TEXT(), server_default='x', @@ -167,25 +170,22 @@ class AutogenerateDiffTest(TestCase): alter_column('user', 'name', existing_type=sa.VARCHAR(length=50), nullable=False) - add_column('order', sa.Column('user_id', sa.Integer(), nullable=True)) - alter_column('order', %(u)s'amount', - existing_type=sa.NUMERIC(precision=8, scale=2), - type_=sa.Numeric(precision=10, scale=2), - nullable=True, - existing_server_default='0') - add_column('address', sa.Column('street', sa.String(length=50), nullable=True)) - ### end Alembic commands ###""" % { - 'u':"" if py3k else 'u' - }) - - eq_(template_args['downgrades'], + ### end Alembic commands ###""") + eq_(re.sub(r"u'", "'", template_args['downgrades']), """### commands auto generated by Alembic - please adjust! ### drop_table('item') - create_table(%(u)s'extra', - sa.Column(%(u)s'x', sa.CHAR(), nullable=True), + create_table('extra', + sa.Column('x', sa.CHAR(), nullable=True), sa.PrimaryKeyConstraint() ) - add_column('user', sa.Column(%(u)s'pw', sa.VARCHAR(length=50), nullable=True)) + drop_column('address', 'street') + drop_column('order', 'user_id') + alter_column('order', 'amount', + existing_type=sa.Numeric(precision=10, scale=2), + type_=sa.NUMERIC(precision=8, scale=2), + nullable=False, + existing_server_default='0') + add_column('user', sa.Column('pw', sa.VARCHAR(length=50), nullable=True)) alter_column('user', 'a1', existing_type=sa.TEXT(), server_default=None, @@ -193,16 +193,7 @@ class AutogenerateDiffTest(TestCase): alter_column('user', 'name', existing_type=sa.VARCHAR(length=50), nullable=True) - drop_column('order', 'user_id') - alter_column('order', %(u)s'amount', - existing_type=sa.Numeric(precision=10, scale=2), - type_=sa.NUMERIC(precision=8, scale=2), - nullable=False, - existing_server_default='0') - drop_column('address', 'street') - ### end Alembic commands ###""" % { - 'u':"" if py3k else 'u' - }) + ### end Alembic commands ###""") def test_skip_null_type_comparison_reflected(self): diff = [] diff --git a/tests/test_mssql.py b/tests/test_mssql.py index dbdb0bac..f86f01d2 100644 --- a/tests/test_mssql.py +++ b/tests/test_mssql.py @@ -1,7 +1,7 @@ """Test op functions against MSSQL.""" from tests import op_fixture, capture_context_buffer, \ - no_sql_testing_config, assert_raises_message, staging_env, \ + _no_sql_testing_config, assert_raises_message, staging_env, \ three_rev_fixture, clear_staging_env from alembic import op, command, util from sqlalchemy import Integer, Column, ForeignKey, \ @@ -14,7 +14,7 @@ class FullEnvironmentTests(TestCase): @classmethod def setup_class(cls): env = staging_env() - cls.cfg = cfg = no_sql_testing_config("mssql") + cls.cfg = cfg = _no_sql_testing_config("mssql") cls.a, cls.b, cls.c = \ three_rev_fixture(cfg) diff --git a/tests/test_offline_environment.py b/tests/test_offline_environment.py index 1bd0c891..e8f13f88 100644 --- a/tests/test_offline_environment.py +++ b/tests/test_offline_environment.py @@ -1,5 +1,5 @@ from tests import clear_staging_env, staging_env, \ - no_sql_testing_config, sqlite_db, eq_, ne_, \ + _no_sql_testing_config, sqlite_db, eq_, ne_, \ capture_context_buffer, three_rev_fixture, env_file_fixture,\ assert_raises_message from alembic import command, util @@ -9,7 +9,7 @@ from unittest import TestCase class OfflineEnvironmentTest(TestCase): def setUp(self): env = staging_env() - self.cfg = no_sql_testing_config() + self.cfg = _no_sql_testing_config() global a, b, c a, b, c = three_rev_fixture(self.cfg) diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py index 325cbb61..157b2e8b 100644 --- a/tests/test_postgresql.py +++ b/tests/test_postgresql.py @@ -1,6 +1,6 @@ from tests import op_fixture, db_for_dialect, eq_, staging_env, \ - clear_staging_env, no_sql_testing_config,\ + clear_staging_env, _no_sql_testing_config,\ capture_context_buffer, requires_07 from unittest import TestCase from sqlalchemy import DateTime, MetaData, Table, Column, text, Integer, String @@ -12,13 +12,17 @@ class PGOfflineEnumTest(TestCase): @requires_07 def setUp(self): env = staging_env() - self.cfg = cfg = no_sql_testing_config() + self.cfg = cfg = _no_sql_testing_config() self.rid = rid = util.rev_id() self.script = script = ScriptDirectory.from_config(cfg) script.generate_rev(rid, None, refresh=True) + def tearDown(self): + clear_staging_env() + + def _inline_enum_script(self): self.script.write(self.rid, """ down_revision = None @@ -57,9 +61,6 @@ def downgrade(): """) - def tearDown(self): - clear_staging_env() - def test_offline_inline_enum_create(self): self._inline_enum_script() with capture_context_buffer() as buf: diff --git a/tests/test_sql_script.py b/tests/test_sql_script.py index e127cb73..85aa33d5 100644 --- a/tests/test_sql_script.py +++ b/tests/test_sql_script.py @@ -1,12 +1,12 @@ from tests import clear_staging_env, staging_env, \ - no_sql_testing_config, sqlite_db, eq_, ne_, capture_context_buffer, \ + _no_sql_testing_config, sqlite_db, eq_, ne_, capture_context_buffer, \ three_rev_fixture from alembic import command, util def setup(): global cfg, env env = staging_env() - cfg = no_sql_testing_config() + cfg = _no_sql_testing_config() global a, b, c a, b, c = three_rev_fixture(cfg) -- 2.47.2