alembic 1.14.1__py3-none-any.whl → 1.15.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. alembic/__init__.py +1 -1
  2. alembic/autogenerate/compare.py +11 -23
  3. alembic/autogenerate/render.py +25 -19
  4. alembic/command.py +3 -1
  5. alembic/context.pyi +5 -2
  6. alembic/ddl/base.py +2 -2
  7. alembic/ddl/impl.py +8 -9
  8. alembic/ddl/mysql.py +1 -2
  9. alembic/ddl/postgresql.py +5 -5
  10. alembic/ddl/sqlite.py +2 -1
  11. alembic/op.pyi +1 -2
  12. alembic/operations/base.py +1 -2
  13. alembic/operations/batch.py +5 -4
  14. alembic/operations/ops.py +1 -2
  15. alembic/operations/toimpl.py +0 -13
  16. alembic/runtime/environment.py +2 -2
  17. alembic/runtime/migration.py +4 -4
  18. alembic/templates/async/alembic.ini.mako +1 -1
  19. alembic/templates/async/script.py.mako +2 -0
  20. alembic/templates/generic/alembic.ini.mako +1 -1
  21. alembic/templates/generic/script.py.mako +2 -0
  22. alembic/templates/multidb/alembic.ini.mako +1 -1
  23. alembic/templates/multidb/script.py.mako +4 -0
  24. alembic/testing/assertions.py +2 -3
  25. alembic/testing/env.py +62 -78
  26. alembic/testing/fixtures.py +3 -15
  27. alembic/testing/requirements.py +1 -35
  28. alembic/testing/suite/test_autogen_computed.py +2 -62
  29. alembic/testing/warnings.py +0 -9
  30. alembic/util/__init__.py +0 -7
  31. alembic/util/exc.py +20 -1
  32. alembic/util/messaging.py +1 -4
  33. alembic/util/sqla_compat.py +72 -238
  34. {alembic-1.14.1.dist-info → alembic-1.15.1.dist-info}/METADATA +7 -11
  35. {alembic-1.14.1.dist-info → alembic-1.15.1.dist-info}/RECORD +39 -39
  36. {alembic-1.14.1.dist-info → alembic-1.15.1.dist-info}/WHEEL +1 -1
  37. {alembic-1.14.1.dist-info → alembic-1.15.1.dist-info}/LICENSE +0 -0
  38. {alembic-1.14.1.dist-info → alembic-1.15.1.dist-info}/entry_points.txt +0 -0
  39. {alembic-1.14.1.dist-info → alembic-1.15.1.dist-info}/top_level.txt +0 -0
alembic/testing/env.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import importlib.machinery
2
2
  import os
3
+ from pathlib import Path
3
4
  import shutil
4
5
  import textwrap
5
6
 
@@ -16,7 +17,7 @@ from ..script import ScriptDirectory
16
17
 
17
18
  def _get_staging_directory():
18
19
  if provision.FOLLOWER_IDENT:
19
- return "scratch_%s" % provision.FOLLOWER_IDENT
20
+ return f"scratch_{provision.FOLLOWER_IDENT}"
20
21
  else:
21
22
  return "scratch"
22
23
 
@@ -24,7 +25,7 @@ def _get_staging_directory():
24
25
  def staging_env(create=True, template="generic", sourceless=False):
25
26
  cfg = _testing_config()
26
27
  if create:
27
- path = os.path.join(_get_staging_directory(), "scripts")
28
+ path = _join_path(_get_staging_directory(), "scripts")
28
29
  assert not os.path.exists(path), (
29
30
  "staging directory %s already exists; poor cleanup?" % path
30
31
  )
@@ -47,7 +48,7 @@ def staging_env(create=True, template="generic", sourceless=False):
47
48
  "pep3147_everything",
48
49
  ), sourceless
49
50
  make_sourceless(
50
- os.path.join(path, "env.py"),
51
+ _join_path(path, "env.py"),
51
52
  "pep3147" if "pep3147" in sourceless else "simple",
52
53
  )
53
54
 
@@ -63,14 +64,14 @@ def clear_staging_env():
63
64
 
64
65
 
65
66
  def script_file_fixture(txt):
66
- dir_ = os.path.join(_get_staging_directory(), "scripts")
67
- path = os.path.join(dir_, "script.py.mako")
67
+ dir_ = _join_path(_get_staging_directory(), "scripts")
68
+ path = _join_path(dir_, "script.py.mako")
68
69
  with open(path, "w") as f:
69
70
  f.write(txt)
70
71
 
71
72
 
72
73
  def env_file_fixture(txt):
73
- dir_ = os.path.join(_get_staging_directory(), "scripts")
74
+ dir_ = _join_path(_get_staging_directory(), "scripts")
74
75
  txt = (
75
76
  """
76
77
  from alembic import context
@@ -80,7 +81,7 @@ config = context.config
80
81
  + txt
81
82
  )
82
83
 
83
- path = os.path.join(dir_, "env.py")
84
+ path = _join_path(dir_, "env.py")
84
85
  pyc_path = util.pyc_file_from_path(path)
85
86
  if pyc_path:
86
87
  os.unlink(pyc_path)
@@ -90,26 +91,26 @@ config = context.config
90
91
 
91
92
 
92
93
  def _sqlite_file_db(tempname="foo.db", future=False, scope=None, **options):
93
- dir_ = os.path.join(_get_staging_directory(), "scripts")
94
+ dir_ = _join_path(_get_staging_directory(), "scripts")
94
95
  url = "sqlite:///%s/%s" % (dir_, tempname)
95
- if scope and util.sqla_14:
96
+ if scope:
96
97
  options["scope"] = scope
97
98
  return testing_util.testing_engine(url=url, future=future, options=options)
98
99
 
99
100
 
100
101
  def _sqlite_testing_config(sourceless=False, future=False):
101
- dir_ = os.path.join(_get_staging_directory(), "scripts")
102
- url = "sqlite:///%s/foo.db" % dir_
102
+ dir_ = _join_path(_get_staging_directory(), "scripts")
103
+ url = f"sqlite:///{dir_}/foo.db"
103
104
 
104
105
  sqlalchemy_future = future or ("future" in config.db.__class__.__module__)
105
106
 
106
107
  return _write_config_file(
107
- """
108
+ f"""
108
109
  [alembic]
109
- script_location = %s
110
- sqlalchemy.url = %s
111
- sourceless = %s
112
- %s
110
+ script_location = {dir_}
111
+ sqlalchemy.url = {url}
112
+ sourceless = {"true" if sourceless else "false"}
113
+ {"sqlalchemy.future = true" if sqlalchemy_future else ""}
113
114
 
114
115
  [loggers]
115
116
  keys = root,sqlalchemy
@@ -140,29 +141,24 @@ keys = generic
140
141
  format = %%(levelname)-5.5s [%%(name)s] %%(message)s
141
142
  datefmt = %%H:%%M:%%S
142
143
  """
143
- % (
144
- dir_,
145
- url,
146
- "true" if sourceless else "false",
147
- "sqlalchemy.future = true" if sqlalchemy_future else "",
148
- )
149
144
  )
150
145
 
151
146
 
152
147
  def _multi_dir_testing_config(sourceless=False, extra_version_location=""):
153
- dir_ = os.path.join(_get_staging_directory(), "scripts")
148
+ dir_ = _join_path(_get_staging_directory(), "scripts")
154
149
  sqlalchemy_future = "future" in config.db.__class__.__module__
155
150
 
156
151
  url = "sqlite:///%s/foo.db" % dir_
157
152
 
158
153
  return _write_config_file(
159
- """
154
+ f"""
160
155
  [alembic]
161
- script_location = %s
162
- sqlalchemy.url = %s
163
- sqlalchemy.future = %s
164
- sourceless = %s
165
- version_locations = %%(here)s/model1/ %%(here)s/model2/ %%(here)s/model3/ %s
156
+ script_location = {dir_}
157
+ sqlalchemy.url = {url}
158
+ sqlalchemy.future = {"true" if sqlalchemy_future else "false"}
159
+ sourceless = {"true" if sourceless else "false"}
160
+ version_locations = %(here)s/model1/ %(here)s/model2/ %(here)s/model3/ \
161
+ {extra_version_location}
166
162
 
167
163
  [loggers]
168
164
  keys = root
@@ -188,26 +184,19 @@ keys = generic
188
184
  format = %%(levelname)-5.5s [%%(name)s] %%(message)s
189
185
  datefmt = %%H:%%M:%%S
190
186
  """
191
- % (
192
- dir_,
193
- url,
194
- "true" if sqlalchemy_future else "false",
195
- "true" if sourceless else "false",
196
- extra_version_location,
197
- )
198
187
  )
199
188
 
200
189
 
201
190
  def _no_sql_testing_config(dialect="postgresql", directives=""):
202
191
  """use a postgresql url with no host so that
203
192
  connections guaranteed to fail"""
204
- dir_ = os.path.join(_get_staging_directory(), "scripts")
193
+ dir_ = _join_path(_get_staging_directory(), "scripts")
205
194
  return _write_config_file(
206
- """
195
+ f"""
207
196
  [alembic]
208
- script_location = %s
209
- sqlalchemy.url = %s://
210
- %s
197
+ script_location ={dir_}
198
+ sqlalchemy.url = {dialect}://
199
+ {directives}
211
200
 
212
201
  [loggers]
213
202
  keys = root
@@ -234,7 +223,6 @@ format = %%(levelname)-5.5s [%%(name)s] %%(message)s
234
223
  datefmt = %%H:%%M:%%S
235
224
 
236
225
  """
237
- % (dir_, dialect, directives)
238
226
  )
239
227
 
240
228
 
@@ -250,7 +238,7 @@ def _testing_config():
250
238
 
251
239
  if not os.access(_get_staging_directory(), os.F_OK):
252
240
  os.mkdir(_get_staging_directory())
253
- return Config(os.path.join(_get_staging_directory(), "test_alembic.ini"))
241
+ return Config(_join_path(_get_staging_directory(), "test_alembic.ini"))
254
242
 
255
243
 
256
244
  def write_script(
@@ -270,9 +258,7 @@ def write_script(
270
258
  script = Script._from_path(scriptdir, path)
271
259
  old = scriptdir.revision_map.get_revision(script.revision)
272
260
  if old.down_revision != script.down_revision:
273
- raise Exception(
274
- "Can't change down_revision " "on a refresh operation."
275
- )
261
+ raise Exception("Can't change down_revision on a refresh operation.")
276
262
  scriptdir.revision_map.add_revision(script, _replace=True)
277
263
 
278
264
  if sourceless:
@@ -312,9 +298,9 @@ def three_rev_fixture(cfg):
312
298
  write_script(
313
299
  script,
314
300
  a,
315
- """\
301
+ f"""\
316
302
  "Rev A"
317
- revision = '%s'
303
+ revision = '{a}'
318
304
  down_revision = None
319
305
 
320
306
  from alembic import op
@@ -327,8 +313,7 @@ def upgrade():
327
313
  def downgrade():
328
314
  op.execute("DROP STEP 1")
329
315
 
330
- """
331
- % a,
316
+ """,
332
317
  )
333
318
 
334
319
  script.generate_revision(b, "revision b", refresh=True, head=a)
@@ -358,10 +343,10 @@ def downgrade():
358
343
  write_script(
359
344
  script,
360
345
  c,
361
- """\
346
+ f"""\
362
347
  "Rev C"
363
- revision = '%s'
364
- down_revision = '%s'
348
+ revision = '{c}'
349
+ down_revision = '{b}'
365
350
 
366
351
  from alembic import op
367
352
 
@@ -373,8 +358,7 @@ def upgrade():
373
358
  def downgrade():
374
359
  op.execute("DROP STEP 3")
375
360
 
376
- """
377
- % (c, b),
361
+ """,
378
362
  )
379
363
  return a, b, c
380
364
 
@@ -396,10 +380,10 @@ def multi_heads_fixture(cfg, a, b, c):
396
380
  write_script(
397
381
  script,
398
382
  d,
399
- """\
383
+ f"""\
400
384
  "Rev D"
401
- revision = '%s'
402
- down_revision = '%s'
385
+ revision = '{d}'
386
+ down_revision = '{b}'
403
387
 
404
388
  from alembic import op
405
389
 
@@ -411,8 +395,7 @@ def upgrade():
411
395
  def downgrade():
412
396
  op.execute("DROP STEP 4")
413
397
 
414
- """
415
- % (d, b),
398
+ """,
416
399
  )
417
400
 
418
401
  script.generate_revision(
@@ -421,10 +404,10 @@ def downgrade():
421
404
  write_script(
422
405
  script,
423
406
  e,
424
- """\
407
+ f"""\
425
408
  "Rev E"
426
- revision = '%s'
427
- down_revision = '%s'
409
+ revision = '{e}'
410
+ down_revision = '{d}'
428
411
 
429
412
  from alembic import op
430
413
 
@@ -436,8 +419,7 @@ def upgrade():
436
419
  def downgrade():
437
420
  op.execute("DROP STEP 5")
438
421
 
439
- """
440
- % (e, d),
422
+ """,
441
423
  )
442
424
 
443
425
  script.generate_revision(
@@ -446,10 +428,10 @@ def downgrade():
446
428
  write_script(
447
429
  script,
448
430
  f,
449
- """\
431
+ f"""\
450
432
  "Rev F"
451
- revision = '%s'
452
- down_revision = '%s'
433
+ revision = '{f}'
434
+ down_revision = '{b}'
453
435
 
454
436
  from alembic import op
455
437
 
@@ -461,8 +443,7 @@ def upgrade():
461
443
  def downgrade():
462
444
  op.execute("DROP STEP 6")
463
445
 
464
- """
465
- % (f, b),
446
+ """,
466
447
  )
467
448
 
468
449
  return d, e, f
@@ -471,25 +452,25 @@ def downgrade():
471
452
  def _multidb_testing_config(engines):
472
453
  """alembic.ini fixture to work exactly with the 'multidb' template"""
473
454
 
474
- dir_ = os.path.join(_get_staging_directory(), "scripts")
455
+ dir_ = _join_path(_get_staging_directory(), "scripts")
475
456
 
476
457
  sqlalchemy_future = "future" in config.db.__class__.__module__
477
458
 
478
459
  databases = ", ".join(engines.keys())
479
460
  engines = "\n\n".join(
480
- "[%s]\n" "sqlalchemy.url = %s" % (key, value.url)
461
+ f"[{key}]\nsqlalchemy.url = {value.url}"
481
462
  for key, value in engines.items()
482
463
  )
483
464
 
484
465
  return _write_config_file(
485
- """
466
+ f"""
486
467
  [alembic]
487
- script_location = %s
468
+ script_location = {dir_}
488
469
  sourceless = false
489
- sqlalchemy.future = %s
490
- databases = %s
470
+ sqlalchemy.future = {"true" if sqlalchemy_future else "false"}
471
+ databases = {databases}
491
472
 
492
- %s
473
+ {engines}
493
474
  [loggers]
494
475
  keys = root
495
476
 
@@ -514,5 +495,8 @@ keys = generic
514
495
  format = %%(levelname)-5.5s [%%(name)s] %%(message)s
515
496
  datefmt = %%H:%%M:%%S
516
497
  """
517
- % (dir_, "true" if sqlalchemy_future else "false", databases, engines)
518
498
  )
499
+
500
+
501
+ def _join_path(base: str, *more: str):
502
+ return str(Path(base).joinpath(*more).as_posix())
@@ -8,6 +8,7 @@ from typing import Any
8
8
  from typing import Dict
9
9
 
10
10
  from sqlalchemy import Column
11
+ from sqlalchemy import create_mock_engine
11
12
  from sqlalchemy import inspect
12
13
  from sqlalchemy import MetaData
13
14
  from sqlalchemy import String
@@ -17,6 +18,7 @@ from sqlalchemy import text
17
18
  from sqlalchemy.testing import config
18
19
  from sqlalchemy.testing import mock
19
20
  from sqlalchemy.testing.assertions import eq_
21
+ from sqlalchemy.testing.fixtures import FutureEngineMixin
20
22
  from sqlalchemy.testing.fixtures import TablesTest as SQLAlchemyTablesTest
21
23
  from sqlalchemy.testing.fixtures import TestBase as SQLAlchemyTestBase
22
24
 
@@ -26,8 +28,6 @@ from ..environment import EnvironmentContext
26
28
  from ..migration import MigrationContext
27
29
  from ..operations import Operations
28
30
  from ..util import sqla_compat
29
- from ..util.sqla_compat import create_mock_engine
30
- from ..util.sqla_compat import sqla_14
31
31
  from ..util.sqla_compat import sqla_2
32
32
 
33
33
 
@@ -65,14 +65,6 @@ class TablesTest(TestBase, SQLAlchemyTablesTest):
65
65
  pass
66
66
 
67
67
 
68
- if sqla_14:
69
- from sqlalchemy.testing.fixtures import FutureEngineMixin
70
- else:
71
-
72
- class FutureEngineMixin: # type:ignore[no-redef]
73
- __requires__ = ("sqlalchemy_14",)
74
-
75
-
76
68
  FutureEngineMixin.is_sqlalchemy_future = True
77
69
 
78
70
 
@@ -190,12 +182,8 @@ def op_fixture(
190
182
  opts["as_sql"] = as_sql
191
183
  if literal_binds:
192
184
  opts["literal_binds"] = literal_binds
193
- if not sqla_14 and dialect == "mariadb":
194
- ctx_dialect = _get_dialect("mysql")
195
- ctx_dialect.server_version_info = (10, 4, 0, "MariaDB")
196
185
 
197
- else:
198
- ctx_dialect = _get_dialect(dialect)
186
+ ctx_dialect = _get_dialect(dialect)
199
187
  if native_boolean is not None:
200
188
  ctx_dialect.supports_native_boolean = native_boolean
201
189
  # this is new as of SQLAlchemy 1.2.7 and is used by SQL Server,
@@ -1,7 +1,6 @@
1
1
  from sqlalchemy.testing.requirements import Requirements
2
2
 
3
3
  from alembic import util
4
- from alembic.util import sqla_compat
5
4
  from ..testing import exclusions
6
5
 
7
6
 
@@ -74,13 +73,6 @@ class SuiteRequirements(Requirements):
74
73
  def reflects_fk_options(self):
75
74
  return exclusions.closed()
76
75
 
77
- @property
78
- def sqlalchemy_14(self):
79
- return exclusions.skip_if(
80
- lambda config: not util.sqla_14,
81
- "SQLAlchemy 1.4 or greater required",
82
- )
83
-
84
76
  @property
85
77
  def sqlalchemy_1x(self):
86
78
  return exclusions.skip_if(
@@ -105,7 +97,7 @@ class SuiteRequirements(Requirements):
105
97
  else:
106
98
  return True
107
99
 
108
- return self.sqlalchemy_14 + exclusions.only_if(go)
100
+ return exclusions.only_if(go)
109
101
 
110
102
  @property
111
103
  def comments(self):
@@ -121,26 +113,6 @@ class SuiteRequirements(Requirements):
121
113
  def computed_columns(self):
122
114
  return exclusions.closed()
123
115
 
124
- @property
125
- def computed_columns_api(self):
126
- return exclusions.only_if(
127
- exclusions.BooleanPredicate(sqla_compat.has_computed)
128
- )
129
-
130
- @property
131
- def computed_reflects_normally(self):
132
- return exclusions.only_if(
133
- exclusions.BooleanPredicate(sqla_compat.has_computed_reflection)
134
- )
135
-
136
- @property
137
- def computed_reflects_as_server_default(self):
138
- return exclusions.closed()
139
-
140
- @property
141
- def computed_doesnt_reflect_as_server_default(self):
142
- return exclusions.closed()
143
-
144
116
  @property
145
117
  def autoincrement_on_composite_pk(self):
146
118
  return exclusions.closed()
@@ -202,9 +174,3 @@ class SuiteRequirements(Requirements):
202
174
  @property
203
175
  def identity_columns_alter(self):
204
176
  return exclusions.closed()
205
-
206
- @property
207
- def identity_columns_api(self):
208
- return exclusions.only_if(
209
- exclusions.BooleanPredicate(sqla_compat.has_identity)
210
- )
@@ -6,9 +6,7 @@ from sqlalchemy import Table
6
6
 
7
7
  from ._autogen_fixtures import AutogenFixtureTest
8
8
  from ... import testing
9
- from ...testing import config
10
9
  from ...testing import eq_
11
- from ...testing import exclusions
12
10
  from ...testing import is_
13
11
  from ...testing import is_true
14
12
  from ...testing import mock
@@ -63,18 +61,8 @@ class AutogenerateComputedTest(AutogenFixtureTest, TestBase):
63
61
  c = diffs[0][3]
64
62
  eq_(c.name, "foo")
65
63
 
66
- if config.requirements.computed_reflects_normally.enabled:
67
- is_true(isinstance(c.computed, sa.Computed))
68
- else:
69
- is_(c.computed, None)
70
-
71
- if config.requirements.computed_reflects_as_server_default.enabled:
72
- is_true(isinstance(c.server_default, sa.DefaultClause))
73
- eq_(str(c.server_default.arg.text), "5")
74
- elif config.requirements.computed_reflects_normally.enabled:
75
- is_true(isinstance(c.computed, sa.Computed))
76
- else:
77
- is_(c.computed, None)
64
+ is_true(isinstance(c.computed, sa.Computed))
65
+ is_true(isinstance(c.server_default, sa.Computed))
78
66
 
79
67
  @testing.combinations(
80
68
  lambda: (None, sa.Computed("bar*5")),
@@ -85,7 +73,6 @@ class AutogenerateComputedTest(AutogenFixtureTest, TestBase):
85
73
  ),
86
74
  lambda: (sa.Computed("bar*5"), sa.Computed("bar * 42")),
87
75
  )
88
- @config.requirements.computed_reflects_normally
89
76
  def test_cant_change_computed_warning(self, test_case):
90
77
  arg_before, arg_after = testing.resolve_lambda(test_case, **locals())
91
78
  m1 = MetaData()
@@ -125,10 +112,6 @@ class AutogenerateComputedTest(AutogenFixtureTest, TestBase):
125
112
  lambda: (sa.Computed("5"), sa.Computed("5")),
126
113
  lambda: (sa.Computed("bar*5"), sa.Computed("bar*5")),
127
114
  lambda: (sa.Computed("bar*5"), sa.Computed("bar * \r\n\t5")),
128
- (
129
- lambda: (sa.Computed("bar*5"), None),
130
- config.requirements.computed_doesnt_reflect_as_server_default,
131
- ),
132
115
  )
133
116
  def test_computed_unchanged(self, test_case):
134
117
  arg_before, arg_after = testing.resolve_lambda(test_case, **locals())
@@ -159,46 +142,3 @@ class AutogenerateComputedTest(AutogenFixtureTest, TestBase):
159
142
  eq_(mock_warn.mock_calls, [])
160
143
 
161
144
  eq_(list(diffs), [])
162
-
163
- @config.requirements.computed_reflects_as_server_default
164
- def test_remove_computed_default_on_computed(self):
165
- """Asserts the current behavior which is that on PG and Oracle,
166
- the GENERATED ALWAYS AS is reflected as a server default which we can't
167
- tell is actually "computed", so these come out as a modification to
168
- the server default.
169
-
170
- """
171
- m1 = MetaData()
172
- m2 = MetaData()
173
-
174
- Table(
175
- "user",
176
- m1,
177
- Column("id", Integer, primary_key=True),
178
- Column("bar", Integer),
179
- Column("foo", Integer, sa.Computed("bar + 42")),
180
- )
181
-
182
- Table(
183
- "user",
184
- m2,
185
- Column("id", Integer, primary_key=True),
186
- Column("bar", Integer),
187
- Column("foo", Integer),
188
- )
189
-
190
- diffs = self._fixture(m1, m2)
191
-
192
- eq_(diffs[0][0][0], "modify_default")
193
- eq_(diffs[0][0][2], "user")
194
- eq_(diffs[0][0][3], "foo")
195
- old = diffs[0][0][-2]
196
- new = diffs[0][0][-1]
197
-
198
- is_(new, None)
199
- is_true(isinstance(old, sa.DefaultClause))
200
-
201
- if exclusions.against(config, "postgresql"):
202
- eq_(str(old.arg.text), "(bar + 42)")
203
- elif exclusions.against(config, "oracle"):
204
- eq_(str(old.arg.text), '"BAR"+42')
@@ -10,8 +10,6 @@ import warnings
10
10
 
11
11
  from sqlalchemy import exc as sa_exc
12
12
 
13
- from ..util import sqla_14
14
-
15
13
 
16
14
  def setup_filters():
17
15
  """Set global warning behavior for the test suite."""
@@ -23,13 +21,6 @@ def setup_filters():
23
21
 
24
22
  # some selected deprecations...
25
23
  warnings.filterwarnings("error", category=DeprecationWarning)
26
- if not sqla_14:
27
- # 1.3 uses pkg_resources in PluginLoader
28
- warnings.filterwarnings(
29
- "ignore",
30
- "pkg_resources is deprecated as an API",
31
- DeprecationWarning,
32
- )
33
24
  try:
34
25
  import pytest
35
26
  except ImportError:
alembic/util/__init__.py CHANGED
@@ -25,11 +25,4 @@ from .pyfiles import coerce_resource_to_filename as coerce_resource_to_filename
25
25
  from .pyfiles import load_python_file as load_python_file
26
26
  from .pyfiles import pyc_file_from_path as pyc_file_from_path
27
27
  from .pyfiles import template_to_file as template_to_file
28
- from .sqla_compat import has_computed as has_computed
29
- from .sqla_compat import sqla_13 as sqla_13
30
- from .sqla_compat import sqla_14 as sqla_14
31
28
  from .sqla_compat import sqla_2 as sqla_2
32
-
33
-
34
- if not sqla_13:
35
- raise CommandError("SQLAlchemy 1.3.0 or greater is required.")
alembic/util/exc.py CHANGED
@@ -1,6 +1,25 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+ from typing import List
5
+ from typing import Tuple
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from alembic.autogenerate import RevisionContext
10
+
11
+
1
12
  class CommandError(Exception):
2
13
  pass
3
14
 
4
15
 
5
16
  class AutogenerateDiffsDetected(CommandError):
6
- pass
17
+ def __init__(
18
+ self,
19
+ message: str,
20
+ revision_context: RevisionContext,
21
+ diffs: List[Tuple[Any, ...]],
22
+ ) -> None:
23
+ super().__init__(message)
24
+ self.revision_context = revision_context
25
+ self.diffs = diffs
alembic/util/messaging.py CHANGED
@@ -13,8 +13,6 @@ import warnings
13
13
 
14
14
  from sqlalchemy.engine import url
15
15
 
16
- from . import sqla_compat
17
-
18
16
  log = logging.getLogger(__name__)
19
17
 
20
18
  # disable "no handler found" errors
@@ -76,8 +74,7 @@ def err(message: str, quiet: bool = False) -> None:
76
74
 
77
75
 
78
76
  def obfuscate_url_pw(input_url: str) -> str:
79
- u = url.make_url(input_url)
80
- return sqla_compat.url_render_as_string(u, hide_password=True) # type: ignore # noqa: E501
77
+ return url.make_url(input_url).render_as_string(hide_password=True)
81
78
 
82
79
 
83
80
  def warn(msg: str, stacklevel: int = 2) -> None: