alembic 1.13.0__py3-none-any.whl → 1.13.2__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 (48) hide show
  1. alembic/__init__.py +1 -1
  2. alembic/autogenerate/__init__.py +10 -10
  3. alembic/autogenerate/api.py +9 -7
  4. alembic/autogenerate/compare.py +6 -5
  5. alembic/autogenerate/render.py +34 -24
  6. alembic/autogenerate/rewriter.py +26 -13
  7. alembic/command.py +27 -16
  8. alembic/config.py +25 -19
  9. alembic/context.pyi +10 -5
  10. alembic/ddl/__init__.py +1 -1
  11. alembic/ddl/_autogen.py +19 -13
  12. alembic/ddl/base.py +17 -13
  13. alembic/ddl/impl.py +27 -19
  14. alembic/ddl/mssql.py +4 -1
  15. alembic/ddl/mysql.py +54 -34
  16. alembic/ddl/oracle.py +9 -4
  17. alembic/ddl/postgresql.py +18 -10
  18. alembic/ddl/sqlite.py +8 -6
  19. alembic/op.pyi +46 -8
  20. alembic/operations/base.py +69 -16
  21. alembic/operations/batch.py +7 -8
  22. alembic/operations/ops.py +57 -35
  23. alembic/operations/schemaobj.py +11 -8
  24. alembic/operations/toimpl.py +3 -0
  25. alembic/runtime/environment.py +20 -13
  26. alembic/runtime/migration.py +34 -18
  27. alembic/script/base.py +24 -24
  28. alembic/script/revision.py +53 -33
  29. alembic/script/write_hooks.py +3 -0
  30. alembic/templates/async/alembic.ini.mako +3 -3
  31. alembic/templates/generic/alembic.ini.mako +2 -2
  32. alembic/templates/multidb/alembic.ini.mako +2 -2
  33. alembic/testing/fixtures.py +20 -8
  34. alembic/testing/suite/test_autogen_computed.py +1 -0
  35. alembic/testing/suite/test_environment.py +3 -3
  36. alembic/util/__init__.py +31 -31
  37. alembic/util/compat.py +25 -8
  38. alembic/util/langhelpers.py +78 -36
  39. alembic/util/messaging.py +15 -6
  40. alembic/util/pyfiles.py +7 -3
  41. alembic/util/sqla_compat.py +41 -14
  42. {alembic-1.13.0.dist-info → alembic-1.13.2.dist-info}/LICENSE +2 -2
  43. {alembic-1.13.0.dist-info → alembic-1.13.2.dist-info}/METADATA +1 -1
  44. alembic-1.13.2.dist-info/RECORD +83 -0
  45. {alembic-1.13.0.dist-info → alembic-1.13.2.dist-info}/WHEEL +1 -1
  46. alembic-1.13.0.dist-info/RECORD +0 -83
  47. {alembic-1.13.0.dist-info → alembic-1.13.2.dist-info}/entry_points.txt +0 -0
  48. {alembic-1.13.0.dist-info → alembic-1.13.2.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,6 @@
1
+ # mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
2
+ # mypy: no-warn-return-any, allow-any-generics
3
+
1
4
  from __future__ import annotations
2
5
 
3
6
  from typing import Any
@@ -220,10 +223,12 @@ class SchemaObjects:
220
223
  t = sa_schema.Table(name, m, *cols, **kw)
221
224
 
222
225
  constraints = [
223
- sqla_compat._copy(elem, target_table=t)
224
- if getattr(elem, "parent", None) is not t
225
- and getattr(elem, "parent", None) is not None
226
- else elem
226
+ (
227
+ sqla_compat._copy(elem, target_table=t)
228
+ if getattr(elem, "parent", None) is not t
229
+ and getattr(elem, "parent", None) is not None
230
+ else elem
231
+ )
227
232
  for elem in columns
228
233
  if isinstance(elem, (Constraint, Index))
229
234
  ]
@@ -274,10 +279,8 @@ class SchemaObjects:
274
279
  ForeignKey.
275
280
 
276
281
  """
277
- if isinstance(fk._colspec, str): # type:ignore[attr-defined]
278
- table_key, cname = fk._colspec.rsplit( # type:ignore[attr-defined]
279
- ".", 1
280
- )
282
+ if isinstance(fk._colspec, str):
283
+ table_key, cname = fk._colspec.rsplit(".", 1)
281
284
  sname, tname = self._parse_table_key(table_key)
282
285
  if table_key not in metadata.tables:
283
286
  rel_t = sa_schema.Table(tname, metadata, schema=sname)
@@ -1,3 +1,6 @@
1
+ # mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
2
+ # mypy: no-warn-return-any, allow-any-generics
3
+
1
4
  from typing import TYPE_CHECKING
2
5
 
3
6
  from sqlalchemy import schema as sa_schema
@@ -108,7 +108,6 @@ CompareType = Callable[
108
108
 
109
109
 
110
110
  class EnvironmentContext(util.ModuleClsProxy):
111
-
112
111
  """A configurational facade made available in an ``env.py`` script.
113
112
 
114
113
  The :class:`.EnvironmentContext` acts as a *facade* to the more
@@ -228,9 +227,9 @@ class EnvironmentContext(util.ModuleClsProxy):
228
227
  has been configured.
229
228
 
230
229
  """
231
- return self.context_opts.get("as_sql", False)
230
+ return self.context_opts.get("as_sql", False) # type: ignore[no-any-return] # noqa: E501
232
231
 
233
- def is_transactional_ddl(self):
232
+ def is_transactional_ddl(self) -> bool:
234
233
  """Return True if the context is configured to expect a
235
234
  transactional DDL capable backend.
236
235
 
@@ -339,21 +338,20 @@ class EnvironmentContext(util.ModuleClsProxy):
339
338
  line.
340
339
 
341
340
  """
342
- return self.context_opts.get("tag", None)
341
+ return self.context_opts.get("tag", None) # type: ignore[no-any-return] # noqa: E501
343
342
 
344
343
  @overload
345
- def get_x_argument(self, as_dictionary: Literal[False]) -> List[str]:
346
- ...
344
+ def get_x_argument(self, as_dictionary: Literal[False]) -> List[str]: ...
347
345
 
348
346
  @overload
349
- def get_x_argument(self, as_dictionary: Literal[True]) -> Dict[str, str]:
350
- ...
347
+ def get_x_argument(
348
+ self, as_dictionary: Literal[True]
349
+ ) -> Dict[str, str]: ...
351
350
 
352
351
  @overload
353
352
  def get_x_argument(
354
353
  self, as_dictionary: bool = ...
355
- ) -> Union[List[str], Dict[str, str]]:
356
- ...
354
+ ) -> Union[List[str], Dict[str, str]]: ...
357
355
 
358
356
  def get_x_argument(
359
357
  self, as_dictionary: bool = False
@@ -367,7 +365,11 @@ class EnvironmentContext(util.ModuleClsProxy):
367
365
  The return value is a list, returned directly from the ``argparse``
368
366
  structure. If ``as_dictionary=True`` is passed, the ``x`` arguments
369
367
  are parsed using ``key=value`` format into a dictionary that is
370
- then returned.
368
+ then returned. If there is no ``=`` in the argument, value is an empty
369
+ string.
370
+
371
+ .. versionchanged:: 1.13.1 Support ``as_dictionary=True`` when
372
+ arguments are passed without the ``=`` symbol.
371
373
 
372
374
  For example, to support passing a database URL on the command line,
373
375
  the standard ``env.py`` script can be modified like this::
@@ -401,7 +403,12 @@ class EnvironmentContext(util.ModuleClsProxy):
401
403
  else:
402
404
  value = []
403
405
  if as_dictionary:
404
- value = dict(arg.split("=", 1) for arg in value)
406
+ dict_value = {}
407
+ for arg in value:
408
+ x_key, _, x_value = arg.partition("=")
409
+ dict_value[x_key] = x_value
410
+ value = dict_value
411
+
405
412
  return value
406
413
 
407
414
  def configure(
@@ -941,7 +948,7 @@ class EnvironmentContext(util.ModuleClsProxy):
941
948
  def execute(
942
949
  self,
943
950
  sql: Union[Executable, str],
944
- execution_options: Optional[dict] = None,
951
+ execution_options: Optional[Dict[str, Any]] = None,
945
952
  ) -> None:
946
953
  """Execute the given SQL using the current change context.
947
954
 
@@ -1,3 +1,6 @@
1
+ # mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
2
+ # mypy: no-warn-return-any, allow-any-generics
3
+
1
4
  from __future__ import annotations
2
5
 
3
6
  from contextlib import contextmanager
@@ -83,7 +86,6 @@ class _ProxyTransaction:
83
86
 
84
87
 
85
88
  class MigrationContext:
86
-
87
89
  """Represent the database state made available to a migration
88
90
  script.
89
91
 
@@ -215,9 +217,11 @@ class MigrationContext:
215
217
  log.info("Generating static SQL")
216
218
  log.info(
217
219
  "Will assume %s DDL.",
218
- "transactional"
219
- if self.impl.transactional_ddl
220
- else "non-transactional",
220
+ (
221
+ "transactional"
222
+ if self.impl.transactional_ddl
223
+ else "non-transactional"
224
+ ),
221
225
  )
222
226
 
223
227
  @classmethod
@@ -342,9 +346,9 @@ class MigrationContext:
342
346
  # except that it will not know it's in "autocommit" and will
343
347
  # emit deprecation warnings when an autocommit action takes
344
348
  # place.
345
- self.connection = (
346
- self.impl.connection
347
- ) = base_connection.execution_options(isolation_level="AUTOCOMMIT")
349
+ self.connection = self.impl.connection = (
350
+ base_connection.execution_options(isolation_level="AUTOCOMMIT")
351
+ )
348
352
 
349
353
  # sqlalchemy future mode will "autobegin" in any case, so take
350
354
  # control of that "transaction" here
@@ -521,7 +525,7 @@ class MigrationContext:
521
525
  start_from_rev = None
522
526
  elif start_from_rev is not None and self.script:
523
527
  start_from_rev = [
524
- cast("Script", self.script.get_revision(sfr)).revision
528
+ self.script.get_revision(sfr).revision
525
529
  for sfr in util.to_list(start_from_rev)
526
530
  if sfr not in (None, "base")
527
531
  ]
@@ -652,7 +656,7 @@ class MigrationContext:
652
656
  def execute(
653
657
  self,
654
658
  sql: Union[Executable, str],
655
- execution_options: Optional[dict] = None,
659
+ execution_options: Optional[Dict[str, Any]] = None,
656
660
  ) -> None:
657
661
  """Execute a SQL construct or string statement.
658
662
 
@@ -1000,6 +1004,11 @@ class MigrationStep:
1000
1004
  is_upgrade: bool
1001
1005
  migration_fn: Any
1002
1006
 
1007
+ if TYPE_CHECKING:
1008
+
1009
+ @property
1010
+ def doc(self) -> Optional[str]: ...
1011
+
1003
1012
  @property
1004
1013
  def name(self) -> str:
1005
1014
  return self.migration_fn.__name__
@@ -1048,13 +1057,9 @@ class RevisionStep(MigrationStep):
1048
1057
  self.revision = revision
1049
1058
  self.is_upgrade = is_upgrade
1050
1059
  if is_upgrade:
1051
- self.migration_fn = (
1052
- revision.module.upgrade # type:ignore[attr-defined]
1053
- )
1060
+ self.migration_fn = revision.module.upgrade
1054
1061
  else:
1055
- self.migration_fn = (
1056
- revision.module.downgrade # type:ignore[attr-defined]
1057
- )
1062
+ self.migration_fn = revision.module.downgrade
1058
1063
 
1059
1064
  def __repr__(self):
1060
1065
  return "RevisionStep(%r, is_upgrade=%r)" % (
@@ -1070,7 +1075,7 @@ class RevisionStep(MigrationStep):
1070
1075
  )
1071
1076
 
1072
1077
  @property
1073
- def doc(self) -> str:
1078
+ def doc(self) -> Optional[str]:
1074
1079
  return self.revision.doc
1075
1080
 
1076
1081
  @property
@@ -1168,7 +1173,18 @@ class RevisionStep(MigrationStep):
1168
1173
  }
1169
1174
  return tuple(set(self.to_revisions).difference(ancestors))
1170
1175
  else:
1171
- return self.to_revisions
1176
+ # for each revision we plan to return, compute its ancestors
1177
+ # (excluding self), and remove those from the final output since
1178
+ # they are already accounted for.
1179
+ ancestors = {
1180
+ r.revision
1181
+ for to_revision in self.to_revisions
1182
+ for r in self.revision_map._get_ancestor_nodes(
1183
+ self.revision_map.get_revisions(to_revision), check=False
1184
+ )
1185
+ if r.revision != to_revision
1186
+ }
1187
+ return tuple(set(self.to_revisions).difference(ancestors))
1172
1188
 
1173
1189
  def unmerge_branch_idents(
1174
1190
  self, heads: Set[str]
@@ -1283,7 +1299,7 @@ class StampStep(MigrationStep):
1283
1299
  def __eq__(self, other):
1284
1300
  return (
1285
1301
  isinstance(other, StampStep)
1286
- and other.from_revisions == self.revisions
1302
+ and other.from_revisions == self.from_revisions
1287
1303
  and other.to_revisions == self.to_revisions
1288
1304
  and other.branch_move == self.branch_move
1289
1305
  and self.is_upgrade == other.is_upgrade
alembic/script/base.py CHANGED
@@ -41,7 +41,7 @@ try:
41
41
  from zoneinfo import ZoneInfoNotFoundError
42
42
  else:
43
43
  from backports.zoneinfo import ZoneInfo # type: ignore[import-not-found,no-redef] # noqa: E501
44
- from backports.zoneinfo import ZoneInfoNotFoundError # type: ignore[import-not-found,no-redef] # noqa: E501
44
+ from backports.zoneinfo import ZoneInfoNotFoundError # type: ignore[no-redef] # noqa: E501
45
45
  except ImportError:
46
46
  ZoneInfo = None # type: ignore[assignment, misc]
47
47
 
@@ -56,7 +56,6 @@ _split_on_space_comma_colon = re.compile(r", *|(?: +)|\:")
56
56
 
57
57
 
58
58
  class ScriptDirectory:
59
-
60
59
  """Provides operations upon an Alembic script directory.
61
60
 
62
61
  This object is useful to get information as to current revisions,
@@ -119,7 +118,7 @@ class ScriptDirectory:
119
118
  return loc[0]
120
119
 
121
120
  @util.memoized_property
122
- def _version_locations(self):
121
+ def _version_locations(self) -> Sequence[str]:
123
122
  if self.version_locations:
124
123
  return [
125
124
  os.path.abspath(util.coerce_resource_to_filename(location))
@@ -303,24 +302,22 @@ class ScriptDirectory:
303
302
  ):
304
303
  yield cast(Script, rev)
305
304
 
306
- def get_revisions(self, id_: _GetRevArg) -> Tuple[Optional[Script], ...]:
305
+ def get_revisions(self, id_: _GetRevArg) -> Tuple[Script, ...]:
307
306
  """Return the :class:`.Script` instance with the given rev identifier,
308
307
  symbolic name, or sequence of identifiers.
309
308
 
310
309
  """
311
310
  with self._catch_revision_errors():
312
311
  return cast(
313
- Tuple[Optional[Script], ...],
312
+ Tuple[Script, ...],
314
313
  self.revision_map.get_revisions(id_),
315
314
  )
316
315
 
317
- def get_all_current(self, id_: Tuple[str, ...]) -> Set[Optional[Script]]:
316
+ def get_all_current(self, id_: Tuple[str, ...]) -> Set[Script]:
318
317
  with self._catch_revision_errors():
319
- return cast(
320
- Set[Optional[Script]], self.revision_map._get_all_current(id_)
321
- )
318
+ return cast(Set[Script], self.revision_map._get_all_current(id_))
322
319
 
323
- def get_revision(self, id_: str) -> Optional[Script]:
320
+ def get_revision(self, id_: str) -> Script:
324
321
  """Return the :class:`.Script` instance with the given rev id.
325
322
 
326
323
  .. seealso::
@@ -330,7 +327,7 @@ class ScriptDirectory:
330
327
  """
331
328
 
332
329
  with self._catch_revision_errors():
333
- return cast(Optional[Script], self.revision_map.get_revision(id_))
330
+ return cast(Script, self.revision_map.get_revision(id_))
334
331
 
335
332
  def as_revision_number(
336
333
  self, id_: Optional[str]
@@ -585,7 +582,7 @@ class ScriptDirectory:
585
582
  util.load_python_file(self.dir, "env.py")
586
583
 
587
584
  @property
588
- def env_py_location(self):
585
+ def env_py_location(self) -> str:
589
586
  return os.path.abspath(os.path.join(self.dir, "env.py"))
590
587
 
591
588
  def _generate_template(self, src: str, dest: str, **kw: Any) -> None:
@@ -612,7 +609,7 @@ class ScriptDirectory:
612
609
  if self.timezone is not None:
613
610
  if ZoneInfo is None:
614
611
  raise util.CommandError(
615
- "Python >= 3.9 is required for timezone support or"
612
+ "Python >= 3.9 is required for timezone support or "
616
613
  "the 'backports.zoneinfo' package must be installed."
617
614
  )
618
615
  # First, assume correct capitalization
@@ -684,7 +681,7 @@ class ScriptDirectory:
684
681
  self.revision_map.get_revisions(head),
685
682
  )
686
683
  for h in heads:
687
- assert h != "base"
684
+ assert h != "base" # type: ignore[comparison-overlap]
688
685
 
689
686
  if len(set(heads)) != len(heads):
690
687
  raise util.CommandError("Duplicate head revisions specified")
@@ -734,9 +731,11 @@ class ScriptDirectory:
734
731
  if depends_on:
735
732
  with self._catch_revision_errors():
736
733
  resolved_depends_on = [
737
- dep
738
- if dep in rev.branch_labels # maintain branch labels
739
- else rev.revision # resolve partial revision identifiers
734
+ (
735
+ dep
736
+ if dep in rev.branch_labels # maintain branch labels
737
+ else rev.revision
738
+ ) # resolve partial revision identifiers
740
739
  for rev, dep in [
741
740
  (not_none(self.revision_map.get_revision(dep)), dep)
742
741
  for dep in util.to_list(depends_on)
@@ -810,7 +809,6 @@ class ScriptDirectory:
810
809
 
811
810
 
812
811
  class Script(revision.Revision):
813
-
814
812
  """Represent a single revision file in a ``versions/`` directory.
815
813
 
816
814
  The :class:`.Script` instance is returned by methods
@@ -823,7 +821,7 @@ class Script(revision.Revision):
823
821
  self.path = path
824
822
  super().__init__(
825
823
  rev_id,
826
- module.down_revision, # type: ignore[attr-defined]
824
+ module.down_revision,
827
825
  branch_labels=util.to_tuple(
828
826
  getattr(module, "branch_labels", None), default=()
829
827
  ),
@@ -856,7 +854,7 @@ class Script(revision.Revision):
856
854
  if doc:
857
855
  if hasattr(self.module, "_alembic_source_encoding"):
858
856
  doc = doc.decode( # type: ignore[attr-defined]
859
- self.module._alembic_source_encoding # type: ignore[attr-defined] # noqa
857
+ self.module._alembic_source_encoding
860
858
  )
861
859
  return doc.strip() # type: ignore[union-attr]
862
860
  else:
@@ -898,7 +896,7 @@ class Script(revision.Revision):
898
896
  )
899
897
  return entry
900
898
 
901
- def __str__(self):
899
+ def __str__(self) -> str:
902
900
  return "%s -> %s%s%s%s, %s" % (
903
901
  self._format_down_revision(),
904
902
  self.revision,
@@ -932,9 +930,11 @@ class Script(revision.Revision):
932
930
  if head_indicators or tree_indicators:
933
931
  text += "%s%s%s" % (
934
932
  " (head)" if self._is_real_head else "",
935
- " (effective head)"
936
- if self.is_head and not self._is_real_head
937
- else "",
933
+ (
934
+ " (effective head)"
935
+ if self.is_head and not self._is_real_head
936
+ else ""
937
+ ),
938
938
  " (current)" if self._db_current_indicator else "",
939
939
  )
940
940
  if tree_indicators:
@@ -14,6 +14,7 @@ from typing import Iterator
14
14
  from typing import List
15
15
  from typing import Optional
16
16
  from typing import overload
17
+ from typing import Protocol
17
18
  from typing import Sequence
18
19
  from typing import Set
19
20
  from typing import Tuple
@@ -47,6 +48,17 @@ _relative_destination = re.compile(r"(?:(.+?)@)?(\w+)?((?:\+|-)\d+)")
47
48
  _revision_illegal_chars = ["@", "-", "+"]
48
49
 
49
50
 
51
+ class _CollectRevisionsProtocol(Protocol):
52
+ def __call__(
53
+ self,
54
+ upper: _RevisionIdentifierType,
55
+ lower: _RevisionIdentifierType,
56
+ inclusive: bool,
57
+ implicit_base: bool,
58
+ assert_relative_length: bool,
59
+ ) -> Tuple[Set[Revision], Tuple[Optional[_RevisionOrBase], ...]]: ...
60
+
61
+
50
62
  class RevisionError(Exception):
51
63
  pass
52
64
 
@@ -396,7 +408,7 @@ class RevisionMap:
396
408
  for rev in self._get_ancestor_nodes(
397
409
  [revision],
398
410
  include_dependencies=False,
399
- map_=cast(_RevisionMapType, map_),
411
+ map_=map_,
400
412
  ):
401
413
  if rev is revision:
402
414
  continue
@@ -707,9 +719,11 @@ class RevisionMap:
707
719
  resolved_target = target
708
720
 
709
721
  resolved_test_against_revs = [
710
- self._revision_for_ident(test_against_rev)
711
- if not isinstance(test_against_rev, Revision)
712
- else test_against_rev
722
+ (
723
+ self._revision_for_ident(test_against_rev)
724
+ if not isinstance(test_against_rev, Revision)
725
+ else test_against_rev
726
+ )
713
727
  for test_against_rev in util.to_tuple(
714
728
  test_against_revs, default=()
715
729
  )
@@ -791,7 +805,7 @@ class RevisionMap:
791
805
  The iterator yields :class:`.Revision` objects.
792
806
 
793
807
  """
794
- fn: Callable
808
+ fn: _CollectRevisionsProtocol
795
809
  if select_for_downgrade:
796
810
  fn = self._collect_downgrade_revisions
797
811
  else:
@@ -818,7 +832,7 @@ class RevisionMap:
818
832
  ) -> Iterator[Any]:
819
833
  if omit_immediate_dependencies:
820
834
 
821
- def fn(rev):
835
+ def fn(rev: Revision) -> Iterable[str]:
822
836
  if rev not in targets:
823
837
  return rev._all_nextrev
824
838
  else:
@@ -826,12 +840,12 @@ class RevisionMap:
826
840
 
827
841
  elif include_dependencies:
828
842
 
829
- def fn(rev):
843
+ def fn(rev: Revision) -> Iterable[str]:
830
844
  return rev._all_nextrev
831
845
 
832
846
  else:
833
847
 
834
- def fn(rev):
848
+ def fn(rev: Revision) -> Iterable[str]:
835
849
  return rev.nextrev
836
850
 
837
851
  return self._iterate_related_revisions(
@@ -847,12 +861,12 @@ class RevisionMap:
847
861
  ) -> Iterator[Revision]:
848
862
  if include_dependencies:
849
863
 
850
- def fn(rev):
864
+ def fn(rev: Revision) -> Iterable[str]:
851
865
  return rev._normalized_down_revisions
852
866
 
853
867
  else:
854
868
 
855
- def fn(rev):
869
+ def fn(rev: Revision) -> Iterable[str]:
856
870
  return rev._versioned_down_revisions
857
871
 
858
872
  return self._iterate_related_revisions(
@@ -861,7 +875,7 @@ class RevisionMap:
861
875
 
862
876
  def _iterate_related_revisions(
863
877
  self,
864
- fn: Callable,
878
+ fn: Callable[[Revision], Iterable[str]],
865
879
  targets: Collection[Optional[_RevisionOrBase]],
866
880
  map_: Optional[_RevisionMapType],
867
881
  check: bool = False,
@@ -923,7 +937,7 @@ class RevisionMap:
923
937
 
924
938
  id_to_rev = self._revision_map
925
939
 
926
- def get_ancestors(rev_id):
940
+ def get_ancestors(rev_id: str) -> Set[str]:
927
941
  return {
928
942
  r.revision
929
943
  for r in self._get_ancestor_nodes([id_to_rev[rev_id]])
@@ -1003,9 +1017,9 @@ class RevisionMap:
1003
1017
  # each time but it was getting complicated
1004
1018
  current_heads[current_candidate_idx] = heads_to_add[0]
1005
1019
  current_heads.extend(heads_to_add[1:])
1006
- ancestors_by_idx[
1007
- current_candidate_idx
1008
- ] = get_ancestors(heads_to_add[0])
1020
+ ancestors_by_idx[current_candidate_idx] = (
1021
+ get_ancestors(heads_to_add[0])
1022
+ )
1009
1023
  ancestors_by_idx.extend(
1010
1024
  get_ancestors(head) for head in heads_to_add[1:]
1011
1025
  )
@@ -1041,7 +1055,7 @@ class RevisionMap:
1041
1055
  children: Sequence[Optional[_RevisionOrBase]]
1042
1056
  for _ in range(abs(steps)):
1043
1057
  if steps > 0:
1044
- assert initial != "base"
1058
+ assert initial != "base" # type: ignore[comparison-overlap]
1045
1059
  # Walk up
1046
1060
  walk_up = [
1047
1061
  is_revision(rev)
@@ -1055,7 +1069,7 @@ class RevisionMap:
1055
1069
  children = walk_up
1056
1070
  else:
1057
1071
  # Walk down
1058
- if initial == "base":
1072
+ if initial == "base": # type: ignore[comparison-overlap]
1059
1073
  children = ()
1060
1074
  else:
1061
1075
  children = self.get_revisions(
@@ -1170,9 +1184,13 @@ class RevisionMap:
1170
1184
  branch_label = symbol
1171
1185
  # Walk down the tree to find downgrade target.
1172
1186
  rev = self._walk(
1173
- start=self.get_revision(symbol)
1174
- if branch_label is None
1175
- else self.get_revision("%s@%s" % (branch_label, symbol)),
1187
+ start=(
1188
+ self.get_revision(symbol)
1189
+ if branch_label is None
1190
+ else self.get_revision(
1191
+ "%s@%s" % (branch_label, symbol)
1192
+ )
1193
+ ),
1176
1194
  steps=rel_int,
1177
1195
  no_overwalk=assert_relative_length,
1178
1196
  )
@@ -1189,7 +1207,7 @@ class RevisionMap:
1189
1207
  # No relative destination given, revision specified is absolute.
1190
1208
  branch_label, _, symbol = target.rpartition("@")
1191
1209
  if not branch_label:
1192
- branch_label = None # type:ignore[assignment]
1210
+ branch_label = None
1193
1211
  return branch_label, self.get_revision(symbol)
1194
1212
 
1195
1213
  def _parse_upgrade_target(
@@ -1290,9 +1308,13 @@ class RevisionMap:
1290
1308
  )
1291
1309
  return (
1292
1310
  self._walk(
1293
- start=self.get_revision(symbol)
1294
- if branch_label is None
1295
- else self.get_revision("%s@%s" % (branch_label, symbol)),
1311
+ start=(
1312
+ self.get_revision(symbol)
1313
+ if branch_label is None
1314
+ else self.get_revision(
1315
+ "%s@%s" % (branch_label, symbol)
1316
+ )
1317
+ ),
1296
1318
  steps=relative,
1297
1319
  no_overwalk=assert_relative_length,
1298
1320
  ),
@@ -1301,11 +1323,11 @@ class RevisionMap:
1301
1323
  def _collect_downgrade_revisions(
1302
1324
  self,
1303
1325
  upper: _RevisionIdentifierType,
1304
- target: _RevisionIdentifierType,
1326
+ lower: _RevisionIdentifierType,
1305
1327
  inclusive: bool,
1306
1328
  implicit_base: bool,
1307
1329
  assert_relative_length: bool,
1308
- ) -> Any:
1330
+ ) -> Tuple[Set[Revision], Tuple[Optional[_RevisionOrBase], ...]]:
1309
1331
  """
1310
1332
  Compute the set of current revisions specified by :upper, and the
1311
1333
  downgrade target specified by :target. Return all dependents of target
@@ -1316,7 +1338,7 @@ class RevisionMap:
1316
1338
 
1317
1339
  branch_label, target_revision = self._parse_downgrade_target(
1318
1340
  current_revisions=upper,
1319
- target=target,
1341
+ target=lower,
1320
1342
  assert_relative_length=assert_relative_length,
1321
1343
  )
1322
1344
  if target_revision == "base":
@@ -1408,7 +1430,7 @@ class RevisionMap:
1408
1430
  inclusive: bool,
1409
1431
  implicit_base: bool,
1410
1432
  assert_relative_length: bool,
1411
- ) -> Tuple[Set[Revision], Tuple[Optional[_RevisionOrBase]]]:
1433
+ ) -> Tuple[Set[Revision], Tuple[Revision, ...]]:
1412
1434
  """
1413
1435
  Compute the set of required revisions specified by :upper, and the
1414
1436
  current set of active revisions specified by :lower. Find the
@@ -1500,7 +1522,7 @@ class RevisionMap:
1500
1522
  )
1501
1523
  needs.intersection_update(lower_descendents)
1502
1524
 
1503
- return needs, tuple(targets) # type:ignore[return-value]
1525
+ return needs, tuple(targets)
1504
1526
 
1505
1527
  def _get_all_current(
1506
1528
  self, id_: Tuple[str, ...]
@@ -1681,15 +1703,13 @@ class Revision:
1681
1703
 
1682
1704
 
1683
1705
  @overload
1684
- def tuple_rev_as_scalar(rev: None) -> None:
1685
- ...
1706
+ def tuple_rev_as_scalar(rev: None) -> None: ...
1686
1707
 
1687
1708
 
1688
1709
  @overload
1689
1710
  def tuple_rev_as_scalar(
1690
1711
  rev: Union[Tuple[_T, ...], List[_T]]
1691
- ) -> Union[_T, Tuple[_T, ...], List[_T]]:
1692
- ...
1712
+ ) -> Union[_T, Tuple[_T, ...], List[_T]]: ...
1693
1713
 
1694
1714
 
1695
1715
  def tuple_rev_as_scalar(
@@ -1,3 +1,6 @@
1
+ # mypy: allow-untyped-defs, allow-incomplete-defs, allow-untyped-calls
2
+ # mypy: no-warn-return-any, allow-any-generics
3
+
1
4
  from __future__ import annotations
2
5
 
3
6
  import shlex
@@ -1,7 +1,8 @@
1
1
  # A generic, single database configuration.
2
2
 
3
3
  [alembic]
4
- # path to migration scripts
4
+ # path to migration scripts.
5
+ # Use forward slashes (/) also on windows to provide an os agnostic path
5
6
  script_location = ${script_location}
6
7
 
7
8
  # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
@@ -20,8 +21,7 @@ prepend_sys_path = .
20
21
  # leave blank for localtime
21
22
  # timezone =
22
23
 
23
- # max length of characters to apply to the
24
- # "slug" field
24
+ # max length of characters to apply to the "slug" field
25
25
  # truncate_slug_length = 40
26
26
 
27
27
  # set to 'true' to run the environment during