alembic 1.16.1__py3-none-any.whl → 1.16.3__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 (30) hide show
  1. alembic/__init__.py +1 -1
  2. alembic/autogenerate/compare.py +2 -2
  3. alembic/autogenerate/render.py +34 -11
  4. alembic/autogenerate/rewriter.py +2 -2
  5. alembic/config.py +14 -1
  6. alembic/runtime/environment.py +1 -1
  7. alembic/runtime/migration.py +5 -1
  8. alembic/script/base.py +6 -2
  9. alembic/script/write_hooks.py +42 -44
  10. alembic/templates/async/alembic.ini.mako +8 -2
  11. alembic/templates/async/script.py.mako +1 -1
  12. alembic/templates/generic/alembic.ini.mako +8 -2
  13. alembic/templates/generic/script.py.mako +1 -1
  14. alembic/templates/multidb/alembic.ini.mako +8 -2
  15. alembic/templates/multidb/script.py.mako +1 -1
  16. alembic/templates/pyproject/pyproject.toml.mako +9 -3
  17. alembic/templates/pyproject/script.py.mako +1 -1
  18. alembic/templates/pyproject_async/README +1 -0
  19. alembic/templates/pyproject_async/alembic.ini.mako +44 -0
  20. alembic/templates/pyproject_async/env.py +89 -0
  21. alembic/templates/pyproject_async/pyproject.toml.mako +82 -0
  22. alembic/templates/pyproject_async/script.py.mako +28 -0
  23. alembic/util/pyfiles.py +4 -2
  24. alembic/util/sqla_compat.py +2 -4
  25. {alembic-1.16.1.dist-info → alembic-1.16.3.dist-info}/METADATA +1 -1
  26. {alembic-1.16.1.dist-info → alembic-1.16.3.dist-info}/RECORD +30 -25
  27. {alembic-1.16.1.dist-info → alembic-1.16.3.dist-info}/WHEEL +1 -1
  28. {alembic-1.16.1.dist-info → alembic-1.16.3.dist-info}/entry_points.txt +0 -0
  29. {alembic-1.16.1.dist-info → alembic-1.16.3.dist-info}/licenses/LICENSE +0 -0
  30. {alembic-1.16.1.dist-info → alembic-1.16.3.dist-info}/top_level.txt +0 -0
alembic/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  from . import context
2
2
  from . import op
3
3
 
4
- __version__ = "1.16.1"
4
+ __version__ = "1.16.3"
@@ -683,7 +683,7 @@ def _compare_indexes_and_uniques(
683
683
  ):
684
684
  modify_ops.ops.append(ops.CreateIndexOp.from_index(obj.const))
685
685
  log.info(
686
- "Detected added index '%r' on '%s'",
686
+ "Detected added index %r on '%s'",
687
687
  obj.name,
688
688
  obj.column_names,
689
689
  )
@@ -1282,7 +1282,7 @@ def _compare_foreign_keys(
1282
1282
  obj.const, obj.name, "foreign_key_constraint", False, compare_to
1283
1283
  ):
1284
1284
  modify_table_ops.ops.append(
1285
- ops.CreateForeignKeyOp.from_constraint(const.const) # type: ignore[has-type] # noqa: E501
1285
+ ops.CreateForeignKeyOp.from_constraint(const.const)
1286
1286
  )
1287
1287
 
1288
1288
  log.info(
@@ -18,6 +18,7 @@ from mako.pygen import PythonPrinter
18
18
  from sqlalchemy import schema as sa_schema
19
19
  from sqlalchemy import sql
20
20
  from sqlalchemy import types as sqltypes
21
+ from sqlalchemy.sql.base import _DialectArgView
21
22
  from sqlalchemy.sql.elements import conv
22
23
  from sqlalchemy.sql.elements import Label
23
24
  from sqlalchemy.sql.elements import quoted_name
@@ -31,7 +32,6 @@ if TYPE_CHECKING:
31
32
 
32
33
  from sqlalchemy import Computed
33
34
  from sqlalchemy import Identity
34
- from sqlalchemy.sql.base import DialectKWArgs
35
35
  from sqlalchemy.sql.elements import ColumnElement
36
36
  from sqlalchemy.sql.elements import TextClause
37
37
  from sqlalchemy.sql.schema import CheckConstraint
@@ -304,11 +304,11 @@ def _drop_table(autogen_context: AutogenContext, op: ops.DropTableOp) -> str:
304
304
 
305
305
 
306
306
  def _render_dialect_kwargs_items(
307
- autogen_context: AutogenContext, item: DialectKWArgs
307
+ autogen_context: AutogenContext, dialect_kwargs: _DialectArgView
308
308
  ) -> list[str]:
309
309
  return [
310
310
  f"{key}={_render_potential_expr(val, autogen_context)}"
311
- for key, val in item.dialect_kwargs.items()
311
+ for key, val in dialect_kwargs.items()
312
312
  ]
313
313
 
314
314
 
@@ -331,7 +331,7 @@ def _add_index(autogen_context: AutogenContext, op: ops.CreateIndexOp) -> str:
331
331
 
332
332
  assert index.table is not None
333
333
 
334
- opts = _render_dialect_kwargs_items(autogen_context, index)
334
+ opts = _render_dialect_kwargs_items(autogen_context, index.dialect_kwargs)
335
335
  if op.if_not_exists is not None:
336
336
  opts.append("if_not_exists=%r" % bool(op.if_not_exists))
337
337
  text = tmpl % {
@@ -365,7 +365,7 @@ def _drop_index(autogen_context: AutogenContext, op: ops.DropIndexOp) -> str:
365
365
  "%(prefix)sdrop_index(%(name)r, "
366
366
  "table_name=%(table_name)r%(schema)s%(kwargs)s)"
367
367
  )
368
- opts = _render_dialect_kwargs_items(autogen_context, index)
368
+ opts = _render_dialect_kwargs_items(autogen_context, index.dialect_kwargs)
369
369
  if op.if_exists is not None:
370
370
  opts.append("if_exists=%r" % bool(op.if_exists))
371
371
  text = tmpl % {
@@ -389,6 +389,7 @@ def _add_unique_constraint(
389
389
  def _add_fk_constraint(
390
390
  autogen_context: AutogenContext, op: ops.CreateForeignKeyOp
391
391
  ) -> str:
392
+ constraint = op.to_constraint()
392
393
  args = [repr(_render_gen_name(autogen_context, op.constraint_name))]
393
394
  if not autogen_context._has_batch:
394
395
  args.append(repr(_ident(op.source_table)))
@@ -418,9 +419,16 @@ def _add_fk_constraint(
418
419
  if value is not None:
419
420
  args.append("%s=%r" % (k, value))
420
421
 
421
- return "%(prefix)screate_foreign_key(%(args)s)" % {
422
+ dialect_kwargs = _render_dialect_kwargs_items(
423
+ autogen_context, constraint.dialect_kwargs
424
+ )
425
+
426
+ return "%(prefix)screate_foreign_key(%(args)s%(dialect_kwargs)s)" % {
422
427
  "prefix": _alembic_autogenerate_prefix(autogen_context),
423
428
  "args": ", ".join(args),
429
+ "dialect_kwargs": (
430
+ ", " + ", ".join(dialect_kwargs) if dialect_kwargs else ""
431
+ ),
424
432
  }
425
433
 
426
434
 
@@ -664,7 +672,9 @@ def _uq_constraint(
664
672
  opts.append(
665
673
  ("name", _render_gen_name(autogen_context, constraint.name))
666
674
  )
667
- dialect_options = _render_dialect_kwargs_items(autogen_context, constraint)
675
+ dialect_options = _render_dialect_kwargs_items(
676
+ autogen_context, constraint.dialect_kwargs
677
+ )
668
678
 
669
679
  if alter:
670
680
  args = [repr(_render_gen_name(autogen_context, constraint.name))]
@@ -803,6 +813,8 @@ def _render_server_default(
803
813
  return _render_potential_expr(
804
814
  default.arg, autogen_context, is_server_default=True
805
815
  )
816
+ elif isinstance(default, sa_schema.FetchedValue):
817
+ return _render_fetched_value(autogen_context)
806
818
 
807
819
  if isinstance(default, str) and repr_:
808
820
  default = repr(re.sub(r"^'|'$", "", default))
@@ -840,6 +852,12 @@ def _render_identity(
840
852
  }
841
853
 
842
854
 
855
+ def _render_fetched_value(autogen_context: AutogenContext) -> str:
856
+ return "%(prefix)sFetchedValue()" % {
857
+ "prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
858
+ }
859
+
860
+
843
861
  def _repr_type(
844
862
  type_: TypeEngine,
845
863
  autogen_context: AutogenContext,
@@ -990,7 +1008,7 @@ def _render_primary_key(
990
1008
  def _fk_colspec(
991
1009
  fk: ForeignKey,
992
1010
  metadata_schema: Optional[str],
993
- namespace_metadata: MetaData,
1011
+ namespace_metadata: Optional[MetaData],
994
1012
  ) -> str:
995
1013
  """Implement a 'safe' version of ForeignKey._get_colspec() that
996
1014
  won't fail if the remote table can't be resolved.
@@ -1014,7 +1032,10 @@ def _fk_colspec(
1014
1032
  # the FK constraint needs to be rendered in terms of the column
1015
1033
  # name.
1016
1034
 
1017
- if table_fullname in namespace_metadata.tables:
1035
+ if (
1036
+ namespace_metadata is not None
1037
+ and table_fullname in namespace_metadata.tables
1038
+ ):
1018
1039
  col = namespace_metadata.tables[table_fullname].c.get(colname)
1019
1040
  if col is not None:
1020
1041
  colname = _ident(col.name) # type: ignore[assignment]
@@ -1045,7 +1066,7 @@ def _populate_render_fk_opts(
1045
1066
  def _render_foreign_key(
1046
1067
  constraint: ForeignKeyConstraint,
1047
1068
  autogen_context: AutogenContext,
1048
- namespace_metadata: MetaData,
1069
+ namespace_metadata: Optional[MetaData],
1049
1070
  ) -> Optional[str]:
1050
1071
  rendered = _user_defined_render("foreign_key", constraint, autogen_context)
1051
1072
  if rendered is not False:
@@ -1059,7 +1080,9 @@ def _render_foreign_key(
1059
1080
 
1060
1081
  _populate_render_fk_opts(constraint, opts)
1061
1082
 
1062
- apply_metadata_schema = namespace_metadata.schema
1083
+ apply_metadata_schema = (
1084
+ namespace_metadata.schema if namespace_metadata is not None else None
1085
+ )
1063
1086
  return (
1064
1087
  "%(prefix)sForeignKeyConstraint([%(cols)s], "
1065
1088
  "[%(refcols)s], %(args)s)"
@@ -177,7 +177,7 @@ class Rewriter:
177
177
  )
178
178
  upgrade_ops_list.append(ret[0])
179
179
 
180
- directive.upgrade_ops = upgrade_ops_list # type: ignore
180
+ directive.upgrade_ops = upgrade_ops_list
181
181
 
182
182
  downgrade_ops_list: List[DowngradeOps] = []
183
183
  for downgrade_ops in directive.downgrade_ops_list:
@@ -187,7 +187,7 @@ class Rewriter:
187
187
  "Can only return single object for DowngradeOps traverse"
188
188
  )
189
189
  downgrade_ops_list.append(ret[0])
190
- directive.downgrade_ops = downgrade_ops_list # type: ignore
190
+ directive.downgrade_ops = downgrade_ops_list
191
191
 
192
192
  @_traverse.dispatch_for(ops.OpContainer)
193
193
  def _traverse_op_container(
alembic/config.py CHANGED
@@ -75,7 +75,20 @@ class Config:
75
75
  alembic_cfg.attributes['connection'] = connection
76
76
  command.upgrade(alembic_cfg, "head")
77
77
 
78
- :param file\_: name of the .ini file to open.
78
+ :param file\_: name of the .ini file to open if an ``alembic.ini`` is
79
+ to be used. This should refer to the ``alembic.ini`` file, either as
80
+ a filename or a full path to the file. This filename if passed must refer
81
+ to an **ini file in ConfigParser format** only.
82
+
83
+ :param toml\_file: name of the pyproject.toml file to open if a
84
+ ``pyproject.toml`` file is to be used. This should refer to the
85
+ ``pyproject.toml`` file, either as a filename or a full path to the file.
86
+ This file must be in toml format. Both :paramref:`.Config.file\_` and
87
+ :paramref:`.Config.toml\_file` may be passed simultaneously, or
88
+ exclusively.
89
+
90
+ .. versionadded:: 1.16.0
91
+
79
92
  :param ini_section: name of the main Alembic section within the
80
93
  .ini file
81
94
  :param output_buffer: optional file-like input buffer which
@@ -338,7 +338,7 @@ class EnvironmentContext(util.ModuleClsProxy):
338
338
  line.
339
339
 
340
340
  """
341
- return self.context_opts.get("tag", None) # type: ignore[no-any-return] # noqa: E501
341
+ return self.context_opts.get("tag", None)
342
342
 
343
343
  @overload
344
344
  def get_x_argument(self, as_dictionary: Literal[False]) -> List[str]: ...
@@ -175,7 +175,11 @@ class MigrationContext:
175
175
  opts["output_encoding"],
176
176
  )
177
177
  else:
178
- self.output_buffer = opts.get("output_buffer", sys.stdout)
178
+ self.output_buffer = opts.get(
179
+ "output_buffer", sys.stdout
180
+ ) # type:ignore[assignment] # noqa: E501
181
+
182
+ self.transactional_ddl = transactional_ddl
179
183
 
180
184
  self._user_compare_type = opts.get("compare_type", True)
181
185
  self._user_compare_server_default = opts.get(
alembic/script/base.py CHANGED
@@ -560,7 +560,11 @@ class ScriptDirectory:
560
560
  **self.messaging_opts,
561
561
  ):
562
562
  util.template_to_file(
563
- src, dest, self.output_encoding, append=True, **kw
563
+ src,
564
+ dest,
565
+ self.output_encoding,
566
+ append_with_newlines=True,
567
+ **kw,
564
568
  )
565
569
 
566
570
  def _generate_template(self, src: Path, dest: Path, **kw: Any) -> None:
@@ -846,7 +850,7 @@ class Script(revision.Revision):
846
850
  doc = doc.decode( # type: ignore[attr-defined]
847
851
  self.module._alembic_source_encoding
848
852
  )
849
- return doc.strip() # type: ignore[union-attr]
853
+ return doc.strip()
850
854
  else:
851
855
  return ""
852
856
 
@@ -3,6 +3,7 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
+ import importlib.util
6
7
  import os
7
8
  import shlex
8
9
  import subprocess
@@ -112,17 +113,35 @@ def _parse_cmdline_options(cmdline_options_str: str, path: str) -> List[str]:
112
113
  return cmdline_options_list
113
114
 
114
115
 
115
- @register("console_scripts")
116
- def console_scripts(
117
- path: str, options: dict, ignore_output: bool = False
118
- ) -> None:
116
+ def _get_required_option(options: dict, name: str) -> str:
119
117
  try:
120
- entrypoint_name = options["entrypoint"]
118
+ return options[name]
121
119
  except KeyError as ke:
122
120
  raise util.CommandError(
123
- f"Key {options['_hook_name']}.entrypoint is required for post "
121
+ f"Key {options['_hook_name']}.{name} is required for post "
124
122
  f"write hook {options['_hook_name']!r}"
125
123
  ) from ke
124
+
125
+
126
+ def _run_hook(
127
+ path: str, options: dict, ignore_output: bool, command: List[str]
128
+ ) -> None:
129
+ cwd: Optional[str] = options.get("cwd", None)
130
+ cmdline_options_str = options.get("options", "")
131
+ cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
132
+
133
+ kw: Dict[str, Any] = {}
134
+ if ignore_output:
135
+ kw["stdout"] = kw["stderr"] = subprocess.DEVNULL
136
+
137
+ subprocess.run([*command, *cmdline_options_list], cwd=cwd, **kw)
138
+
139
+
140
+ @register("console_scripts")
141
+ def console_scripts(
142
+ path: str, options: dict, ignore_output: bool = False
143
+ ) -> None:
144
+ entrypoint_name = _get_required_option(options, "entrypoint")
126
145
  for entry in compat.importlib_metadata_get("console_scripts"):
127
146
  if entry.name == entrypoint_name:
128
147
  impl: Any = entry
@@ -131,48 +150,27 @@ def console_scripts(
131
150
  raise util.CommandError(
132
151
  f"Could not find entrypoint console_scripts.{entrypoint_name}"
133
152
  )
134
- cwd: Optional[str] = options.get("cwd", None)
135
- cmdline_options_str = options.get("options", "")
136
- cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
137
-
138
- kw: Dict[str, Any] = {}
139
- if ignore_output:
140
- kw["stdout"] = kw["stderr"] = subprocess.DEVNULL
141
153
 
142
- subprocess.run(
143
- [
144
- sys.executable,
145
- "-c",
146
- f"import {impl.module}; {impl.module}.{impl.attr}()",
147
- ]
148
- + cmdline_options_list,
149
- cwd=cwd,
150
- **kw,
151
- )
154
+ command = [
155
+ sys.executable,
156
+ "-c",
157
+ f"import {impl.module}; {impl.module}.{impl.attr}()",
158
+ ]
159
+ _run_hook(path, options, ignore_output, command)
152
160
 
153
161
 
154
162
  @register("exec")
155
163
  def exec_(path: str, options: dict, ignore_output: bool = False) -> None:
156
- try:
157
- executable = options["executable"]
158
- except KeyError as ke:
159
- raise util.CommandError(
160
- f"Key {options['_hook_name']}.executable is required for post "
161
- f"write hook {options['_hook_name']!r}"
162
- ) from ke
163
- cwd: Optional[str] = options.get("cwd", None)
164
- cmdline_options_str = options.get("options", "")
165
- cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
164
+ executable = _get_required_option(options, "executable")
165
+ _run_hook(path, options, ignore_output, command=[executable])
166
166
 
167
- kw: Dict[str, Any] = {}
168
- if ignore_output:
169
- kw["stdout"] = kw["stderr"] = subprocess.DEVNULL
170
167
 
171
- subprocess.run(
172
- [
173
- executable,
174
- *cmdline_options_list,
175
- ],
176
- cwd=cwd,
177
- **kw,
178
- )
168
+ @register("module")
169
+ def module(path: str, options: dict, ignore_output: bool = False) -> None:
170
+ module_name = _get_required_option(options, "module")
171
+
172
+ if importlib.util.find_spec(module_name) is None:
173
+ raise util.CommandError(f"Could not find module {module_name}")
174
+
175
+ command = [sys.executable, "-m", module_name]
176
+ _run_hook(path, options, ignore_output, command)
@@ -98,10 +98,16 @@ sqlalchemy.url = driver://user:pass@localhost/dbname
98
98
  # black.entrypoint = black
99
99
  # black.options = -l 79 REVISION_SCRIPT_FILENAME
100
100
 
101
- # lint with attempts to fix using "ruff" - use the exec runner, execute a binary
101
+ # lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
102
+ # hooks = ruff
103
+ # ruff.type = module
104
+ # ruff.module = ruff
105
+ # ruff.options = check --fix REVISION_SCRIPT_FILENAME
106
+
107
+ # Alternatively, use the exec runner to execute a binary found on your PATH
102
108
  # hooks = ruff
103
109
  # ruff.type = exec
104
- # ruff.executable = %(here)s/.venv/bin/ruff
110
+ # ruff.executable = ruff
105
111
  # ruff.options = check --fix REVISION_SCRIPT_FILENAME
106
112
 
107
113
  # Logging configuration. This is also consumed by the user-maintained
@@ -13,7 +13,7 @@ ${imports if imports else ""}
13
13
 
14
14
  # revision identifiers, used by Alembic.
15
15
  revision: str = ${repr(up_revision)}
16
- down_revision: Union[str, None] = ${repr(down_revision)}
16
+ down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
17
17
  branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
18
  depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
19
 
@@ -98,10 +98,16 @@ sqlalchemy.url = driver://user:pass@localhost/dbname
98
98
  # black.entrypoint = black
99
99
  # black.options = -l 79 REVISION_SCRIPT_FILENAME
100
100
 
101
- # lint with attempts to fix using "ruff" - use the exec runner, execute a binary
101
+ # lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
102
+ # hooks = ruff
103
+ # ruff.type = module
104
+ # ruff.module = ruff
105
+ # ruff.options = check --fix REVISION_SCRIPT_FILENAME
106
+
107
+ # Alternatively, use the exec runner to execute a binary found on your PATH
102
108
  # hooks = ruff
103
109
  # ruff.type = exec
104
- # ruff.executable = %(here)s/.venv/bin/ruff
110
+ # ruff.executable = ruff
105
111
  # ruff.options = check --fix REVISION_SCRIPT_FILENAME
106
112
 
107
113
  # Logging configuration. This is also consumed by the user-maintained
@@ -13,7 +13,7 @@ ${imports if imports else ""}
13
13
 
14
14
  # revision identifiers, used by Alembic.
15
15
  revision: str = ${repr(up_revision)}
16
- down_revision: Union[str, None] = ${repr(down_revision)}
16
+ down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
17
17
  branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
18
  depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
19
 
@@ -106,10 +106,16 @@ sqlalchemy.url = driver://user:pass@localhost/dbname2
106
106
  # black.entrypoint = black
107
107
  # black.options = -l 79 REVISION_SCRIPT_FILENAME
108
108
 
109
- # lint with attempts to fix using "ruff" - use the exec runner, execute a binary
109
+ # lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
110
+ # hooks = ruff
111
+ # ruff.type = module
112
+ # ruff.module = ruff
113
+ # ruff.options = check --fix REVISION_SCRIPT_FILENAME
114
+
115
+ # Alternatively, use the exec runner to execute a binary found on your PATH
110
116
  # hooks = ruff
111
117
  # ruff.type = exec
112
- # ruff.executable = %(here)s/.venv/bin/ruff
118
+ # ruff.executable = ruff
113
119
  # ruff.options = check --fix REVISION_SCRIPT_FILENAME
114
120
 
115
121
  # Logging configuration. This is also consumed by the user-maintained
@@ -16,7 +16,7 @@ ${imports if imports else ""}
16
16
 
17
17
  # revision identifiers, used by Alembic.
18
18
  revision: str = ${repr(up_revision)}
19
- down_revision: Union[str, None] = ${repr(down_revision)}
19
+ down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
20
20
  branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
21
21
  depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
22
22
 
@@ -67,10 +67,16 @@ prepend_sys_path = [
67
67
  # options = "-l 79 REVISION_SCRIPT_FILENAME"
68
68
  #
69
69
  # [[tool.alembic.post_write_hooks]]
70
- # lint with attempts to fix using "ruff" - use the exec runner,
71
- # execute a binary
70
+ # lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
71
+ # name = "ruff"
72
+ # type = "module"
73
+ # module = "ruff"
74
+ # options = "check --fix REVISION_SCRIPT_FILENAME"
75
+ #
76
+ # [[tool.alembic.post_write_hooks]]
77
+ # Alternatively, use the exec runner to execute a binary found on your PATH
72
78
  # name = "ruff"
73
79
  # type = "exec"
74
- # executable = "%(here)s/.venv/bin/ruff"
80
+ # executable = "ruff"
75
81
  # options = "check --fix REVISION_SCRIPT_FILENAME"
76
82
 
@@ -13,7 +13,7 @@ ${imports if imports else ""}
13
13
 
14
14
  # revision identifiers, used by Alembic.
15
15
  revision: str = ${repr(up_revision)}
16
- down_revision: Union[str, None] = ${repr(down_revision)}
16
+ down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
17
17
  branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
18
  depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
19
 
@@ -0,0 +1 @@
1
+ pyproject configuration, with an async dbapi.
@@ -0,0 +1,44 @@
1
+ # A generic, single database configuration.
2
+
3
+ [alembic]
4
+
5
+ # database URL. This is consumed by the user-maintained env.py script only.
6
+ # other means of configuring database URLs may be customized within the env.py
7
+ # file.
8
+ sqlalchemy.url = driver://user:pass@localhost/dbname
9
+
10
+
11
+ # Logging configuration
12
+ [loggers]
13
+ keys = root,sqlalchemy,alembic
14
+
15
+ [handlers]
16
+ keys = console
17
+
18
+ [formatters]
19
+ keys = generic
20
+
21
+ [logger_root]
22
+ level = WARNING
23
+ handlers = console
24
+ qualname =
25
+
26
+ [logger_sqlalchemy]
27
+ level = WARNING
28
+ handlers =
29
+ qualname = sqlalchemy.engine
30
+
31
+ [logger_alembic]
32
+ level = INFO
33
+ handlers =
34
+ qualname = alembic
35
+
36
+ [handler_console]
37
+ class = StreamHandler
38
+ args = (sys.stderr,)
39
+ level = NOTSET
40
+ formatter = generic
41
+
42
+ [formatter_generic]
43
+ format = %(levelname)-5.5s [%(name)s] %(message)s
44
+ datefmt = %H:%M:%S
@@ -0,0 +1,89 @@
1
+ import asyncio
2
+ from logging.config import fileConfig
3
+
4
+ from sqlalchemy import pool
5
+ from sqlalchemy.engine import Connection
6
+ from sqlalchemy.ext.asyncio import async_engine_from_config
7
+
8
+ from alembic import context
9
+
10
+ # this is the Alembic Config object, which provides
11
+ # access to the values within the .ini file in use.
12
+ config = context.config
13
+
14
+ # Interpret the config file for Python logging.
15
+ # This line sets up loggers basically.
16
+ if config.config_file_name is not None:
17
+ fileConfig(config.config_file_name)
18
+
19
+ # add your model's MetaData object here
20
+ # for 'autogenerate' support
21
+ # from myapp import mymodel
22
+ # target_metadata = mymodel.Base.metadata
23
+ target_metadata = None
24
+
25
+ # other values from the config, defined by the needs of env.py,
26
+ # can be acquired:
27
+ # my_important_option = config.get_main_option("my_important_option")
28
+ # ... etc.
29
+
30
+
31
+ def run_migrations_offline() -> None:
32
+ """Run migrations in 'offline' mode.
33
+
34
+ This configures the context with just a URL
35
+ and not an Engine, though an Engine is acceptable
36
+ here as well. By skipping the Engine creation
37
+ we don't even need a DBAPI to be available.
38
+
39
+ Calls to context.execute() here emit the given string to the
40
+ script output.
41
+
42
+ """
43
+ url = config.get_main_option("sqlalchemy.url")
44
+ context.configure(
45
+ url=url,
46
+ target_metadata=target_metadata,
47
+ literal_binds=True,
48
+ dialect_opts={"paramstyle": "named"},
49
+ )
50
+
51
+ with context.begin_transaction():
52
+ context.run_migrations()
53
+
54
+
55
+ def do_run_migrations(connection: Connection) -> None:
56
+ context.configure(connection=connection, target_metadata=target_metadata)
57
+
58
+ with context.begin_transaction():
59
+ context.run_migrations()
60
+
61
+
62
+ async def run_async_migrations() -> None:
63
+ """In this scenario we need to create an Engine
64
+ and associate a connection with the context.
65
+
66
+ """
67
+
68
+ connectable = async_engine_from_config(
69
+ config.get_section(config.config_ini_section, {}),
70
+ prefix="sqlalchemy.",
71
+ poolclass=pool.NullPool,
72
+ )
73
+
74
+ async with connectable.connect() as connection:
75
+ await connection.run_sync(do_run_migrations)
76
+
77
+ await connectable.dispose()
78
+
79
+
80
+ def run_migrations_online() -> None:
81
+ """Run migrations in 'online' mode."""
82
+
83
+ asyncio.run(run_async_migrations())
84
+
85
+
86
+ if context.is_offline_mode():
87
+ run_migrations_offline()
88
+ else:
89
+ run_migrations_online()
@@ -0,0 +1,82 @@
1
+ [tool.alembic]
2
+
3
+ # path to migration scripts.
4
+ # this is typically a path given in POSIX (e.g. forward slashes)
5
+ # format, relative to the token %(here)s which refers to the location of this
6
+ # ini file
7
+ script_location = "${script_location}"
8
+
9
+ # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
10
+ # Uncomment the line below if you want the files to be prepended with date and time
11
+ # see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
12
+ # for all available tokens
13
+ # file_template = "%%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s"
14
+
15
+ # additional paths to be prepended to sys.path. defaults to the current working directory.
16
+ prepend_sys_path = [
17
+ "."
18
+ ]
19
+
20
+ # timezone to use when rendering the date within the migration file
21
+ # as well as the filename.
22
+ # If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
23
+ # Any required deps can installed by adding `alembic[tz]` to the pip requirements
24
+ # string value is passed to ZoneInfo()
25
+ # leave blank for localtime
26
+ # timezone =
27
+
28
+ # max length of characters to apply to the "slug" field
29
+ # truncate_slug_length = 40
30
+
31
+ # set to 'true' to run the environment during
32
+ # the 'revision' command, regardless of autogenerate
33
+ # revision_environment = false
34
+
35
+ # set to 'true' to allow .pyc and .pyo files without
36
+ # a source .py file to be detected as revisions in the
37
+ # versions/ directory
38
+ # sourceless = false
39
+
40
+ # version location specification; This defaults
41
+ # to <script_location>/versions. When using multiple version
42
+ # directories, initial revisions must be specified with --version-path.
43
+ # version_locations = [
44
+ # "%(here)s/alembic/versions",
45
+ # "%(here)s/foo/bar"
46
+ # ]
47
+
48
+
49
+ # set to 'true' to search source files recursively
50
+ # in each "version_locations" directory
51
+ # new in Alembic version 1.10
52
+ # recursive_version_locations = false
53
+
54
+ # the output encoding used when revision files
55
+ # are written from script.py.mako
56
+ # output_encoding = "utf-8"
57
+
58
+ # This section defines scripts or Python functions that are run
59
+ # on newly generated revision scripts. See the documentation for further
60
+ # detail and examples
61
+ # [[tool.alembic.post_write_hooks]]
62
+ # format using "black" - use the console_scripts runner,
63
+ # against the "black" entrypoint
64
+ # name = "black"
65
+ # type = "console_scripts"
66
+ # entrypoint = "black"
67
+ # options = "-l 79 REVISION_SCRIPT_FILENAME"
68
+ #
69
+ # [[tool.alembic.post_write_hooks]]
70
+ # lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
71
+ # name = "ruff"
72
+ # type = "module"
73
+ # module = "ruff"
74
+ # options = "check --fix REVISION_SCRIPT_FILENAME"
75
+ #
76
+ # [[tool.alembic.post_write_hooks]]
77
+ # Alternatively, use the exec runner to execute a binary found on your PATH
78
+ # name = "ruff"
79
+ # type = "exec"
80
+ # executable = "ruff"
81
+ # options = "check --fix REVISION_SCRIPT_FILENAME"
82
+
@@ -0,0 +1,28 @@
1
+ """${message}
2
+
3
+ Revision ID: ${up_revision}
4
+ Revises: ${down_revision | comma,n}
5
+ Create Date: ${create_date}
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ ${imports if imports else ""}
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = ${repr(up_revision)}
16
+ down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
17
+ branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
+ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
+
20
+
21
+ def upgrade() -> None:
22
+ """Upgrade schema."""
23
+ ${upgrades if upgrades else "pass"}
24
+
25
+
26
+ def downgrade() -> None:
27
+ """Downgrade schema."""
28
+ ${downgrades if downgrades else "pass"}
alembic/util/pyfiles.py CHANGED
@@ -26,7 +26,7 @@ def template_to_file(
26
26
  dest: Union[str, os.PathLike[str]],
27
27
  output_encoding: str,
28
28
  *,
29
- append: bool = False,
29
+ append_with_newlines: bool = False,
30
30
  **kw: Any,
31
31
  ) -> None:
32
32
  template = Template(filename=_preserving_path_as_str(template_file))
@@ -45,7 +45,9 @@ def template_to_file(
45
45
  "template-oriented traceback." % fname
46
46
  )
47
47
  else:
48
- with open(dest, "ab" if append else "wb") as f:
48
+ with open(dest, "ab" if append_with_newlines else "wb") as f:
49
+ if append_with_newlines:
50
+ f.write("\n\n".encode(output_encoding))
49
51
  f.write(output)
50
52
 
51
53
 
@@ -31,12 +31,10 @@ from sqlalchemy.sql.elements import BindParameter
31
31
  from sqlalchemy.sql.elements import ColumnClause
32
32
  from sqlalchemy.sql.elements import TextClause
33
33
  from sqlalchemy.sql.elements import UnaryExpression
34
+ from sqlalchemy.sql.naming import _NONE_NAME as _NONE_NAME # type: ignore[attr-defined] # noqa: E501
34
35
  from sqlalchemy.sql.visitors import traverse
35
36
  from typing_extensions import TypeGuard
36
37
 
37
- if True:
38
- from sqlalchemy.sql.naming import _NONE_NAME as _NONE_NAME # type: ignore[attr-defined] # noqa: E501
39
-
40
38
  if TYPE_CHECKING:
41
39
  from sqlalchemy import ClauseElement
42
40
  from sqlalchemy import Identity
@@ -81,7 +79,7 @@ if TYPE_CHECKING:
81
79
  ) -> Callable[[_CompilerProtocol], _CompilerProtocol]: ...
82
80
 
83
81
  else:
84
- from sqlalchemy.ext.compiler import compiles
82
+ from sqlalchemy.ext.compiler import compiles # noqa: I100,I202
85
83
 
86
84
 
87
85
  identity_has_dialect_kwargs = issubclass(schema.Identity, DialectKWArgs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alembic
3
- Version: 1.16.1
3
+ Version: 1.16.3
4
4
  Summary: A database migration tool for SQLAlchemy.
5
5
  Author-email: Mike Bayer <mike_mp@zzzcomputing.com>
6
6
  License-Expression: MIT
@@ -1,7 +1,7 @@
1
- alembic/__init__.py,sha256=dPYVgsjHZTtkz_8TPx47tDVuAPwMMa7aDa72Olb_rug,63
1
+ alembic/__init__.py,sha256=Xiav6FUpJXK44D15g2tA9mXBdrSZucpQuGLno4g5RDI,63
2
2
  alembic/__main__.py,sha256=373m7-TBh72JqrSMYviGrxCHZo-cnweM8AGF8A22PmY,78
3
3
  alembic/command.py,sha256=pZPQUGSxCjFu7qy0HMe02HJmByM0LOqoiK2AXKfRO3A,24855
4
- alembic/config.py,sha256=KSvrY2rmIBpxZVswKH9ucNHFdxlxWcGXwYxtUdeppMo,32897
4
+ alembic/config.py,sha256=jcWyXXCM-Uh6uOGmjgnBLhDSD0OkG5P0ZUWYCf5_ek8,33543
5
5
  alembic/context.py,sha256=hK1AJOQXJ29Bhn276GYcosxeG7pC5aZRT5E8c4bMJ4Q,195
6
6
  alembic/context.pyi,sha256=fdeFNTRc0bUgi7n2eZWVFh6NG-TzIv_0gAcapbfHnKY,31773
7
7
  alembic/environment.py,sha256=MM5lPayGT04H3aeng1H7GQ8HEAs3VGX5yy6mDLCPLT4,43
@@ -11,9 +11,9 @@ alembic/op.pyi,sha256=PQ4mKNp7EXrjVdIWQRoGiBSVke4PPxTc9I6qF8ZGGZE,50711
11
11
  alembic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  alembic/autogenerate/__init__.py,sha256=ntmUTXhjLm4_zmqIwyVaECdpPDn6_u1yM9vYk6-553E,543
13
13
  alembic/autogenerate/api.py,sha256=L4qkapSJO1Ypymx8HsjLl0vFFt202agwMYsQbIe6ZtI,22219
14
- alembic/autogenerate/compare.py,sha256=txW17LtHQkHzDdqf0MJ10fka0AbSt0qW2slu9QrcKLA,46021
15
- alembic/autogenerate/render.py,sha256=tIcYsSeHoglueoBfsMtFh0WuBMu_EpvPWNPVDlUUlNI,36489
16
- alembic/autogenerate/rewriter.py,sha256=uZWRkTYJoncoEJ5WY1QBRiozjyChqZDJPy4LtcRibjM,7846
14
+ alembic/autogenerate/compare.py,sha256=LRTxNijEBvcTauuUXuJjC6Sg_gUn33FCYBTF0neZFwE,45979
15
+ alembic/autogenerate/render.py,sha256=ceQL8nk8m2kBtQq5gtxtDLR9iR0Sck8xG_61Oez-Sqs,37270
16
+ alembic/autogenerate/rewriter.py,sha256=NIASSS-KaNKPmbm1k4pE45aawwjSh1Acf6eZrOwnUGM,7814
17
17
  alembic/ddl/__init__.py,sha256=Df8fy4Vn_abP8B7q3x8gyFwEwnLw6hs2Ljt_bV3EZWE,152
18
18
  alembic/ddl/_autogen.py,sha256=Blv2RrHNyF4cE6znCQXNXG5T9aO-YmiwD4Fz-qfoaWA,9275
19
19
  alembic/ddl/base.py,sha256=A1f89-rCZvqw-hgWmBbIszRqx94lL6gKLFXE9kHettA,10478
@@ -30,29 +30,34 @@ alembic/operations/ops.py,sha256=ftsFgcZIctxRDiuGgkQsaFHsMlRP7cLq7Dj_seKVBnQ,962
30
30
  alembic/operations/schemaobj.py,sha256=Wp-bBe4a8lXPTvIHJttBY0ejtpVR5Jvtb2kI-U2PztQ,9468
31
31
  alembic/operations/toimpl.py,sha256=rgufuSUNwpgrOYzzY3Q3ELW1rQv2fQbQVokXgnIYIrs,7503
32
32
  alembic/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- alembic/runtime/environment.py,sha256=W9Y_9tiecmYq885xqMZOrxZs80tN0M_ovXOdCLjGI5A,41524
34
- alembic/runtime/migration.py,sha256=X0O-sEuU54aNujyG_nxk1vs3BRBy2f-QwRJQmTucuVY,49874
33
+ alembic/runtime/environment.py,sha256=L6bDW1dvw8L4zwxlTG8KnT0xcCgLXxUfdRpzqlJoFjo,41479
34
+ alembic/runtime/migration.py,sha256=lu9_z_qyWmNzSM52_FgdXP_G52PTmTTeOeMBQAkQTFg,49997
35
35
  alembic/script/__init__.py,sha256=lSj06O391Iy5avWAiq8SPs6N8RBgxkSPjP8wpXcNDGg,100
36
- alembic/script/base.py,sha256=V-64yc3i3yZDVwSDd51NJKwTPUCdx4sqj3oog6nPq0A,36873
36
+ alembic/script/base.py,sha256=O9xYzMCesjlSoUGD613Co0PhoCcpPBxxJzD3yt1lKK8,36924
37
37
  alembic/script/revision.py,sha256=BQcJoMCIXtSJRLCvdasgLOtCx9O7A8wsSym1FsqLW4s,62307
38
- alembic/script/write_hooks.py,sha256=CAjh9U8m7eXz3W7pfQKVxG4UkHZrRIYKF6AkReakG2c,5015
38
+ alembic/script/write_hooks.py,sha256=uQWAtguSCrxU_k9d87NX19y6EzyjJRRQ5HS9cyPnK9o,5092
39
39
  alembic/templates/async/README,sha256=ISVtAOvqvKk_5ThM5ioJE-lMkvf9IbknFUFVU_vPma4,58
40
- alembic/templates/async/alembic.ini.mako,sha256=ubJvGp-ai_C3RGJ_k5sedviIcIb2HIeExT1Y1K4X44o,4684
40
+ alembic/templates/async/alembic.ini.mako,sha256=Bgi4WkaHYsT7xvsX-4WOGkcXKFroNoQLaUvZA23ZwGs,4864
41
41
  alembic/templates/async/env.py,sha256=zbOCf3Y7w2lg92hxSwmG1MM_7y56i_oRH4AKp0pQBYo,2389
42
- alembic/templates/async/script.py.mako,sha256=3qBrHBf7F7ChKDUIdiNItiSXrDpgQdM7sR0YKzpaC50,689
42
+ alembic/templates/async/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
43
43
  alembic/templates/generic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
44
- alembic/templates/generic/alembic.ini.mako,sha256=CqVaOZbWULb1NYjC6XTnLELPQ_TA9NPMOHKxJeG0vNY,4684
44
+ alembic/templates/generic/alembic.ini.mako,sha256=LCpLL02bi9Qr3KRTEj9NbQqAu0ckUmYBwPtrMtQkv-Y,4864
45
45
  alembic/templates/generic/env.py,sha256=TLRWOVW3Xpt_Tpf8JFzlnoPn_qoUu8UV77Y4o9XD6yI,2103
46
- alembic/templates/generic/script.py.mako,sha256=3qBrHBf7F7ChKDUIdiNItiSXrDpgQdM7sR0YKzpaC50,689
46
+ alembic/templates/generic/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
47
47
  alembic/templates/multidb/README,sha256=dWLDhnBgphA4Nzb7sNlMfCS3_06YqVbHhz-9O5JNqyI,606
48
- alembic/templates/multidb/alembic.ini.mako,sha256=V-1FL7zyxHX1K_tBe_6Ax7DmGB_TevQvB77eIUfWvwk,5010
48
+ alembic/templates/multidb/alembic.ini.mako,sha256=rIp1LTdE1xcoFT2G7X72KshzYjUTRrHTvnkvFL___-8,5190
49
49
  alembic/templates/multidb/env.py,sha256=6zNjnW8mXGUk7erTsAvrfhvqoczJ-gagjVq1Ypg2YIQ,4230
50
- alembic/templates/multidb/script.py.mako,sha256=d0Pl1Z57DASni61GtdV1jTiSJfIx6IwIjEQx2_DeHIU,1220
50
+ alembic/templates/multidb/script.py.mako,sha256=ZbCXMkI5Wj2dwNKcxuVGkKZ7Iav93BNx_bM4zbGi3c8,1235
51
51
  alembic/templates/pyproject/README,sha256=dMhIiFoeM7EdeaOXBs3mVQ6zXACMyGXDb_UBB6sGRA0,60
52
52
  alembic/templates/pyproject/alembic.ini.mako,sha256=bQnEoydnLOUgg9vNbTOys4r5MaW8lmwYFXSrlfdEEkw,782
53
53
  alembic/templates/pyproject/env.py,sha256=TLRWOVW3Xpt_Tpf8JFzlnoPn_qoUu8UV77Y4o9XD6yI,2103
54
- alembic/templates/pyproject/pyproject.toml.mako,sha256=9CzBcdamN6ylIiJ-oGCaw__E84XbonVkNkuET3J7LKI,2645
55
- alembic/templates/pyproject/script.py.mako,sha256=3qBrHBf7F7ChKDUIdiNItiSXrDpgQdM7sR0YKzpaC50,689
54
+ alembic/templates/pyproject/pyproject.toml.mako,sha256=Gf16ZR9OMG9zDlFO5PVQlfiL1DTKwSA--sTNzK7Lba0,2852
55
+ alembic/templates/pyproject/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
56
+ alembic/templates/pyproject_async/README,sha256=2Q5XcEouiqQ-TJssO9805LROkVUd0F6d74rTnuLrifA,45
57
+ alembic/templates/pyproject_async/alembic.ini.mako,sha256=bQnEoydnLOUgg9vNbTOys4r5MaW8lmwYFXSrlfdEEkw,782
58
+ alembic/templates/pyproject_async/env.py,sha256=zbOCf3Y7w2lg92hxSwmG1MM_7y56i_oRH4AKp0pQBYo,2389
59
+ alembic/templates/pyproject_async/pyproject.toml.mako,sha256=Gf16ZR9OMG9zDlFO5PVQlfiL1DTKwSA--sTNzK7Lba0,2852
60
+ alembic/templates/pyproject_async/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
56
61
  alembic/testing/__init__.py,sha256=JXvXAqIwFZB6-ep-BmeIqIH8xJ92XPt7DWCNkMDuJ-g,1249
57
62
  alembic/testing/assertions.py,sha256=qcqf3tRAUe-A12NzuK_yxlksuX9OZKRC5E8pKIdBnPg,5302
58
63
  alembic/testing/env.py,sha256=pka7fjwOC8hYL6X0XE4oPkJpy_1WX01bL7iP7gpO_4I,11551
@@ -78,11 +83,11 @@ alembic/util/editor.py,sha256=JIz6_BdgV8_oKtnheR6DZoB7qnrHrlRgWjx09AsTsUw,2546
78
83
  alembic/util/exc.py,sha256=ZBlTQ8g-Jkb1iYFhFHs9djilRz0SSQ0Foc5SSoENs5o,564
79
84
  alembic/util/langhelpers.py,sha256=LpOcovnhMnP45kTt8zNJ4BHpyQrlF40OL6yDXjqKtsE,10026
80
85
  alembic/util/messaging.py,sha256=3bEBoDy4EAXETXAvArlYjeMITXDTgPTu6ZoE3ytnzSw,3294
81
- alembic/util/pyfiles.py,sha256=ebkz9rQVPM3aMQ-_dtJ5ny4SFovCw4y6Ir1794Zu5C8,4609
82
- alembic/util/sqla_compat.py,sha256=SWAL4hJck4XLnUpe-oI3AGiH8w9kgDBe1_oakCfdT_Q,14785
83
- alembic-1.16.1.dist-info/licenses/LICENSE,sha256=NeqcNBmyYfrxvkSMT0fZJVKBv2s2tf_qVQUiJ9S6VN4,1059
84
- alembic-1.16.1.dist-info/METADATA,sha256=kgVKaGYM05A4pwv_3o1MEKjVVf8dQmJ76i-4A1mQzEw,7265
85
- alembic-1.16.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
86
- alembic-1.16.1.dist-info/entry_points.txt,sha256=aykM30soxwGN0pB7etLc1q0cHJbL9dy46RnK9VX4LLw,48
87
- alembic-1.16.1.dist-info/top_level.txt,sha256=FwKWd5VsPFC8iQjpu1u9Cn-JnK3-V1RhUCmWqz1cl-s,8
88
- alembic-1.16.1.dist-info/RECORD,,
86
+ alembic/util/pyfiles.py,sha256=kOBjZEytRkBKsQl0LAj2sbKJMQazjwQ_5UeMKSIvVFo,4730
87
+ alembic/util/sqla_compat.py,sha256=9OYPTf-GCultAIuv1PoiaqYXAApZQxUOqjrOaeJDAik,14790
88
+ alembic-1.16.3.dist-info/licenses/LICENSE,sha256=NeqcNBmyYfrxvkSMT0fZJVKBv2s2tf_qVQUiJ9S6VN4,1059
89
+ alembic-1.16.3.dist-info/METADATA,sha256=u9wcdrE8XuNQApucFObBCTof9u3nZu7_5a2LdxS62us,7265
90
+ alembic-1.16.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
+ alembic-1.16.3.dist-info/entry_points.txt,sha256=aykM30soxwGN0pB7etLc1q0cHJbL9dy46RnK9VX4LLw,48
92
+ alembic-1.16.3.dist-info/top_level.txt,sha256=FwKWd5VsPFC8iQjpu1u9Cn-JnK3-V1RhUCmWqz1cl-s,8
93
+ alembic-1.16.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5