alembic 1.12.1__py3-none-any.whl → 1.13.0__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.
alembic/ddl/postgresql.py CHANGED
@@ -21,10 +21,8 @@ from sqlalchemy.dialects.postgresql import BIGINT
21
21
  from sqlalchemy.dialects.postgresql import ExcludeConstraint
22
22
  from sqlalchemy.dialects.postgresql import INTEGER
23
23
  from sqlalchemy.schema import CreateIndex
24
- from sqlalchemy.sql import operators
25
24
  from sqlalchemy.sql.elements import ColumnClause
26
25
  from sqlalchemy.sql.elements import TextClause
27
- from sqlalchemy.sql.elements import UnaryExpression
28
26
  from sqlalchemy.sql.functions import FunctionElement
29
27
  from sqlalchemy.types import NULLTYPE
30
28
 
@@ -38,6 +36,7 @@ from .base import format_table_name
38
36
  from .base import format_type
39
37
  from .base import IdentityColumnDefault
40
38
  from .base import RenameTable
39
+ from .impl import ComparisonResult
41
40
  from .impl import DefaultImpl
42
41
  from .. import util
43
42
  from ..autogenerate import render
@@ -252,62 +251,60 @@ class PostgresqlImpl(DefaultImpl):
252
251
  if not sqla_compat.sqla_2:
253
252
  self._skip_functional_indexes(metadata_indexes, conn_indexes)
254
253
 
255
- def _cleanup_index_expr(
256
- self, index: Index, expr: str, remove_suffix: str
257
- ) -> str:
258
- # start = expr
254
+ # pg behavior regarding modifiers
255
+ # | # | compiled sql | returned sql | regexp. group is removed |
256
+ # | - | ---------------- | -----------------| ------------------------ |
257
+ # | 1 | nulls first | nulls first | - |
258
+ # | 2 | nulls last | | (?<! desc)( nulls last)$ |
259
+ # | 3 | asc | | ( asc)$ |
260
+ # | 4 | asc nulls first | nulls first | ( asc) nulls first$ |
261
+ # | 5 | asc nulls last | | ( asc nulls last)$ |
262
+ # | 6 | desc | desc | - |
263
+ # | 7 | desc nulls first | desc | desc( nulls first)$ |
264
+ # | 8 | desc nulls last | desc nulls last | - |
265
+ _default_modifiers_re = ( # order of case 2 and 5 matters
266
+ re.compile("( asc nulls last)$"), # case 5
267
+ re.compile("(?<! desc)( nulls last)$"), # case 2
268
+ re.compile("( asc)$"), # case 3
269
+ re.compile("( asc) nulls first$"), # case 4
270
+ re.compile(" desc( nulls first)$"), # case 7
271
+ )
272
+
273
+ def _cleanup_index_expr(self, index: Index, expr: str) -> str:
259
274
  expr = expr.lower().replace('"', "").replace("'", "")
260
275
  if index.table is not None:
261
276
  # should not be needed, since include_table=False is in compile
262
277
  expr = expr.replace(f"{index.table.name.lower()}.", "")
263
278
 
264
- while expr and expr[0] == "(" and expr[-1] == ")":
265
- expr = expr[1:-1]
266
279
  if "::" in expr:
267
280
  # strip :: cast. types can have spaces in them
268
281
  expr = re.sub(r"(::[\w ]+\w)", "", expr)
269
282
 
270
- if remove_suffix and expr.endswith(remove_suffix):
271
- expr = expr[: -len(remove_suffix)]
272
-
273
- # print(f"START: {start} END: {expr}")
274
- return expr
283
+ while expr and expr[0] == "(" and expr[-1] == ")":
284
+ expr = expr[1:-1]
275
285
 
276
- def _default_modifiers(self, exp: ClauseElement) -> str:
277
- to_remove = ""
278
- while isinstance(exp, UnaryExpression):
279
- if exp.modifier is None:
280
- exp = exp.element
281
- else:
282
- op = exp.modifier
283
- if isinstance(exp.element, UnaryExpression):
284
- inner_op = exp.element.modifier
285
- else:
286
- inner_op = None
287
- if inner_op is None:
288
- if op == operators.asc_op:
289
- # default is asc
290
- to_remove = " asc"
291
- elif op == operators.nullslast_op:
292
- # default is nulls last
293
- to_remove = " nulls last"
294
- else:
295
- if (
296
- inner_op == operators.asc_op
297
- and op == operators.nullslast_op
298
- ):
299
- # default is asc nulls last
300
- to_remove = " asc nulls last"
301
- elif (
302
- inner_op == operators.desc_op
303
- and op == operators.nullsfirst_op
304
- ):
305
- # default for desc is nulls first
306
- to_remove = " nulls first"
286
+ # NOTE: when parsing the connection expression this cleanup could
287
+ # be skipped
288
+ for rs in self._default_modifiers_re:
289
+ if match := rs.search(expr):
290
+ start, end = match.span(1)
291
+ expr = expr[:start] + expr[end:]
307
292
  break
308
- return to_remove
309
293
 
310
- def _dialect_sig(
294
+ while expr and expr[0] == "(" and expr[-1] == ")":
295
+ expr = expr[1:-1]
296
+
297
+ # strip casts
298
+ cast_re = re.compile(r"cast\s*\(")
299
+ if cast_re.match(expr):
300
+ expr = cast_re.sub("", expr)
301
+ # remove the as type
302
+ expr = re.sub(r"as\s+[^)]+\)", "", expr)
303
+ # remove spaces
304
+ expr = expr.replace(" ", "")
305
+ return expr
306
+
307
+ def _dialect_options(
311
308
  self, item: Union[Index, UniqueConstraint]
312
309
  ) -> Tuple[Any, ...]:
313
310
  # only the positive case is returned by sqlalchemy reflection so
@@ -316,25 +313,93 @@ class PostgresqlImpl(DefaultImpl):
316
313
  return ("nulls_not_distinct",)
317
314
  return ()
318
315
 
319
- def create_index_sig(self, index: Index) -> Tuple[Any, ...]:
320
- return tuple(
321
- self._cleanup_index_expr(
322
- index,
323
- *(
324
- (e, "")
325
- if isinstance(e, str)
326
- else (self._compile_element(e), self._default_modifiers(e))
327
- ),
316
+ def compare_indexes(
317
+ self,
318
+ metadata_index: Index,
319
+ reflected_index: Index,
320
+ ) -> ComparisonResult:
321
+ msg = []
322
+ unique_msg = self._compare_index_unique(
323
+ metadata_index, reflected_index
324
+ )
325
+ if unique_msg:
326
+ msg.append(unique_msg)
327
+ m_exprs = metadata_index.expressions
328
+ r_exprs = reflected_index.expressions
329
+ if len(m_exprs) != len(r_exprs):
330
+ msg.append(f"expression number {len(r_exprs)} to {len(m_exprs)}")
331
+ if msg:
332
+ # no point going further, return early
333
+ return ComparisonResult.Different(msg)
334
+ skip = []
335
+ for pos, (m_e, r_e) in enumerate(zip(m_exprs, r_exprs), 1):
336
+ m_compile = self._compile_element(m_e)
337
+ m_text = self._cleanup_index_expr(metadata_index, m_compile)
338
+ # print(f"META ORIG: {m_compile!r} CLEANUP: {m_text!r}")
339
+ r_compile = self._compile_element(r_e)
340
+ r_text = self._cleanup_index_expr(metadata_index, r_compile)
341
+ # print(f"CONN ORIG: {r_compile!r} CLEANUP: {r_text!r}")
342
+ if m_text == r_text:
343
+ continue # expressions these are equal
344
+ elif m_compile.strip().endswith("_ops") and (
345
+ " " in m_compile or ")" in m_compile # is an expression
346
+ ):
347
+ skip.append(
348
+ f"expression #{pos} {m_compile!r} detected "
349
+ "as including operator clause."
350
+ )
351
+ util.warn(
352
+ f"Expression #{pos} {m_compile!r} in index "
353
+ f"{reflected_index.name!r} detected to include "
354
+ "an operator clause. Expression compare cannot proceed. "
355
+ "Please move the operator clause to the "
356
+ "``postgresql_ops`` dict to enable proper compare "
357
+ "of the index expressions: "
358
+ "https://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#operator-classes", # noqa: E501
359
+ )
360
+ else:
361
+ msg.append(f"expression #{pos} {r_compile!r} to {m_compile!r}")
362
+
363
+ m_options = self._dialect_options(metadata_index)
364
+ r_options = self._dialect_options(reflected_index)
365
+ if m_options != r_options:
366
+ msg.extend(f"options {r_options} to {m_options}")
367
+
368
+ if msg:
369
+ return ComparisonResult.Different(msg)
370
+ elif skip:
371
+ # if there are other changes detected don't skip the index
372
+ return ComparisonResult.Skip(skip)
373
+ else:
374
+ return ComparisonResult.Equal()
375
+
376
+ def compare_unique_constraint(
377
+ self,
378
+ metadata_constraint: UniqueConstraint,
379
+ reflected_constraint: UniqueConstraint,
380
+ ) -> ComparisonResult:
381
+ metadata_tup = self._create_metadata_constraint_sig(
382
+ metadata_constraint
383
+ )
384
+ reflected_tup = self._create_reflected_constraint_sig(
385
+ reflected_constraint
386
+ )
387
+
388
+ meta_sig = metadata_tup.unnamed
389
+ conn_sig = reflected_tup.unnamed
390
+ if conn_sig != meta_sig:
391
+ return ComparisonResult.Different(
392
+ f"expression {conn_sig} to {meta_sig}"
328
393
  )
329
- for e in index.expressions
330
- ) + self._dialect_sig(index)
331
394
 
332
- def create_unique_constraint_sig(
333
- self, const: UniqueConstraint
334
- ) -> Tuple[Any, ...]:
335
- return tuple(
336
- sorted([col.name for col in const.columns])
337
- ) + self._dialect_sig(const)
395
+ metadata_do = self._dialect_options(metadata_tup.const)
396
+ conn_do = self._dialect_options(reflected_tup.const)
397
+ if metadata_do != conn_do:
398
+ return ComparisonResult.Different(
399
+ f"expression {conn_do} to {metadata_do}"
400
+ )
401
+
402
+ return ComparisonResult.Equal()
338
403
 
339
404
  def adjust_reflected_dialect_options(
340
405
  self, reflected_options: Dict[str, Any], kind: str
@@ -345,7 +410,9 @@ class PostgresqlImpl(DefaultImpl):
345
410
  options.pop("postgresql_include", None)
346
411
  return options
347
412
 
348
- def _compile_element(self, element: ClauseElement) -> str:
413
+ def _compile_element(self, element: Union[ClauseElement, str]) -> str:
414
+ if isinstance(element, str):
415
+ return element
349
416
  return element.compile(
350
417
  dialect=self.dialect,
351
418
  compile_kwargs={"literal_binds": True, "include_table": False},
alembic/operations/ops.py CHANGED
@@ -899,7 +899,7 @@ class CreateIndexOp(MigrateOperation):
899
899
  return cls(
900
900
  index.name, # type: ignore[arg-type]
901
901
  index.table.name,
902
- sqla_compat._get_index_expressions(index),
902
+ index.expressions,
903
903
  schema=index.table.schema,
904
904
  unique=index.unique,
905
905
  **index.kwargs,
@@ -5,7 +5,7 @@ from sqlalchemy import schema as sa_schema
5
5
  from . import ops
6
6
  from .base import Operations
7
7
  from ..util.sqla_compat import _copy
8
- from ..util.sqla_compat import sqla_2
8
+ from ..util.sqla_compat import sqla_14
9
9
 
10
10
  if TYPE_CHECKING:
11
11
  from sqlalchemy.sql.schema import Table
@@ -98,8 +98,8 @@ def create_index(
98
98
  idx = operation.to_index(operations.migration_context)
99
99
  kw = {}
100
100
  if operation.if_not_exists is not None:
101
- if not sqla_2:
102
- raise NotImplementedError("SQLAlchemy 2.0+ required")
101
+ if not sqla_14:
102
+ raise NotImplementedError("SQLAlchemy 1.4+ required")
103
103
 
104
104
  kw["if_not_exists"] = operation.if_not_exists
105
105
  operations.impl.create_index(idx, **kw)
@@ -109,8 +109,8 @@ def create_index(
109
109
  def drop_index(operations: "Operations", operation: "ops.DropIndexOp") -> None:
110
110
  kw = {}
111
111
  if operation.if_exists is not None:
112
- if not sqla_2:
113
- raise NotImplementedError("SQLAlchemy 2.0+ required")
112
+ if not sqla_14:
113
+ raise NotImplementedError("SQLAlchemy 1.4+ required")
114
114
 
115
115
  kw["if_exists"] = operation.if_exists
116
116
 
@@ -10,6 +10,7 @@ from typing import Mapping
10
10
  from typing import MutableMapping
11
11
  from typing import Optional
12
12
  from typing import overload
13
+ from typing import Sequence
13
14
  from typing import TextIO
14
15
  from typing import Tuple
15
16
  from typing import TYPE_CHECKING
@@ -416,7 +417,7 @@ class EnvironmentContext(util.ModuleClsProxy):
416
417
  tag: Optional[str] = None,
417
418
  template_args: Optional[Dict[str, Any]] = None,
418
419
  render_as_batch: bool = False,
419
- target_metadata: Optional[MetaData] = None,
420
+ target_metadata: Union[MetaData, Sequence[MetaData], None] = None,
420
421
  include_name: Optional[IncludeNameFn] = None,
421
422
  include_object: Optional[IncludeObjectFn] = None,
422
423
  include_schemas: bool = False,
alembic/script/base.py CHANGED
@@ -23,6 +23,7 @@ from . import revision
23
23
  from . import write_hooks
24
24
  from .. import util
25
25
  from ..runtime import migration
26
+ from ..util import compat
26
27
  from ..util import not_none
27
28
 
28
29
  if TYPE_CHECKING:
@@ -35,9 +36,14 @@ if TYPE_CHECKING:
35
36
  from ..runtime.migration import StampStep
36
37
 
37
38
  try:
38
- from dateutil import tz
39
+ if compat.py39:
40
+ from zoneinfo import ZoneInfo
41
+ from zoneinfo import ZoneInfoNotFoundError
42
+ else:
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
39
45
  except ImportError:
40
- tz = None # type: ignore[assignment]
46
+ ZoneInfo = None # type: ignore[assignment, misc]
41
47
 
42
48
  _sourceless_rev_file = re.compile(r"(?!\.\#|__init__)(.*\.py)(c|o)?$")
43
49
  _only_source_rev_file = re.compile(r"(?!\.\#|__init__)(.*\.py)$")
@@ -604,23 +610,26 @@ class ScriptDirectory:
604
610
 
605
611
  def _generate_create_date(self) -> datetime.datetime:
606
612
  if self.timezone is not None:
607
- if tz is None:
613
+ if ZoneInfo is None:
608
614
  raise util.CommandError(
609
- "The library 'python-dateutil' is required "
610
- "for timezone support"
615
+ "Python >= 3.9 is required for timezone support or"
616
+ "the 'backports.zoneinfo' package must be installed."
611
617
  )
612
618
  # First, assume correct capitalization
613
- tzinfo = tz.gettz(self.timezone)
614
- if tzinfo is None:
615
- # Fall back to uppercase
616
- tzinfo = tz.gettz(self.timezone.upper())
619
+ try:
620
+ tzinfo = ZoneInfo(self.timezone)
621
+ except ZoneInfoNotFoundError:
622
+ tzinfo = None
617
623
  if tzinfo is None:
618
- raise util.CommandError(
619
- "Can't locate timezone: %s" % self.timezone
620
- )
624
+ try:
625
+ tzinfo = ZoneInfo(self.timezone.upper())
626
+ except ZoneInfoNotFoundError:
627
+ raise util.CommandError(
628
+ "Can't locate timezone: %s" % self.timezone
629
+ ) from None
621
630
  create_date = (
622
631
  datetime.datetime.utcnow()
623
- .replace(tzinfo=tz.tzutc())
632
+ .replace(tzinfo=datetime.timezone.utc)
624
633
  .astimezone(tzinfo)
625
634
  )
626
635
  else:
@@ -14,9 +14,9 @@ prepend_sys_path = .
14
14
 
15
15
  # timezone to use when rendering the date within the migration file
16
16
  # as well as the filename.
17
- # If specified, requires the python-dateutil library that can be
18
- # installed by adding `alembic[tz]` to the pip requirements
19
- # string value is passed to dateutil.tz.gettz()
17
+ # If specified, requires the python>=3.9 or backports.zoneinfo library.
18
+ # Any required deps can installed by adding `alembic[tz]` to the pip requirements
19
+ # string value is passed to ZoneInfo()
20
20
  # leave blank for localtime
21
21
  # timezone =
22
22
 
@@ -16,9 +16,9 @@ prepend_sys_path = .
16
16
 
17
17
  # timezone to use when rendering the date within the migration file
18
18
  # as well as the filename.
19
- # If specified, requires the python-dateutil library that can be
20
- # installed by adding `alembic[tz]` to the pip requirements
21
- # string value is passed to dateutil.tz.gettz()
19
+ # If specified, requires the python>=3.9 or backports.zoneinfo library.
20
+ # Any required deps can installed by adding `alembic[tz]` to the pip requirements
21
+ # string value is passed to ZoneInfo()
22
22
  # leave blank for localtime
23
23
  # timezone =
24
24
 
@@ -16,9 +16,9 @@ prepend_sys_path = .
16
16
 
17
17
  # timezone to use when rendering the date within the migration file
18
18
  # as well as the filename.
19
- # If specified, requires the python-dateutil library that can be
20
- # installed by adding `alembic[tz]` to the pip requirements
21
- # string value is passed to dateutil.tz.gettz()
19
+ # If specified, requires the python>=3.9 or backports.zoneinfo library.
20
+ # Any required deps can installed by adding `alembic[tz]` to the pip requirements
21
+ # string value is passed to ZoneInfo()
22
22
  # leave blank for localtime
23
23
  # timezone =
24
24
 
@@ -95,6 +95,18 @@ class SuiteRequirements(Requirements):
95
95
  "SQLAlchemy 2.x test",
96
96
  )
97
97
 
98
+ @property
99
+ def asyncio(self):
100
+ def go(config):
101
+ try:
102
+ import greenlet # noqa: F401
103
+ except ImportError:
104
+ return False
105
+ else:
106
+ return True
107
+
108
+ return self.sqlalchemy_14 + exclusions.only_if(go)
109
+
98
110
  @property
99
111
  def comments(self):
100
112
  return exclusions.only_if(
@@ -1,6 +1,7 @@
1
1
  from itertools import zip_longest
2
2
 
3
3
  from sqlalchemy import schema
4
+ from sqlalchemy.sql.elements import ClauseList
4
5
 
5
6
 
6
7
  class CompareTable:
@@ -60,6 +61,14 @@ class CompareIndex:
60
61
  def __ne__(self, other):
61
62
  return not self.__eq__(other)
62
63
 
64
+ def __repr__(self):
65
+ expr = ClauseList(*self.index.expressions)
66
+ try:
67
+ expr_str = expr.compile().string
68
+ except Exception:
69
+ expr_str = str(expr)
70
+ return f"<CompareIndex {self.index.name}({expr_str})>"
71
+
63
72
 
64
73
  class CompareCheckConstraint:
65
74
  def __init__(self, constraint):
alembic/util/compat.py CHANGED
@@ -16,7 +16,6 @@ is_posix = os.name == "posix"
16
16
  py311 = sys.version_info >= (3, 11)
17
17
  py310 = sys.version_info >= (3, 10)
18
18
  py39 = sys.version_info >= (3, 9)
19
- py38 = sys.version_info >= (3, 8)
20
19
 
21
20
 
22
21
  # produce a wrapper that allows encoded text to stream
@@ -524,14 +524,6 @@ def _render_literal_bindparam(
524
524
  return compiler.render_literal_bindparam(element, **kw)
525
525
 
526
526
 
527
- def _get_index_expressions(idx):
528
- return list(idx.expressions)
529
-
530
-
531
- def _get_index_column_names(idx):
532
- return [getattr(exp, "name", None) for exp in _get_index_expressions(idx)]
533
-
534
-
535
527
  def _column_kwargs(col: Column) -> Mapping:
536
528
  if sqla_13:
537
529
  return col.kwargs
@@ -630,10 +622,15 @@ else:
630
622
 
631
623
 
632
624
  def is_expression_index(index: Index) -> bool:
633
- expr: Any
634
625
  for expr in index.expressions:
635
- while isinstance(expr, UnaryExpression):
636
- expr = expr.element
637
- if not isinstance(expr, ColumnClause) or expr.is_literal:
626
+ if is_expression(expr):
638
627
  return True
639
628
  return False
629
+
630
+
631
+ def is_expression(expr: Any) -> bool:
632
+ while isinstance(expr, UnaryExpression):
633
+ expr = expr.element
634
+ if not isinstance(expr, ColumnClause) or expr.is_literal:
635
+ return True
636
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: alembic
3
- Version: 1.12.1
3
+ Version: 1.13.0
4
4
  Summary: A database migration tool for SQLAlchemy.
5
5
  Home-page: https://alembic.sqlalchemy.org
6
6
  Author: Mike Bayer
@@ -17,14 +17,15 @@ Classifier: License :: OSI Approved :: MIT License
17
17
  Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python
19
19
  Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.7
21
20
  Classifier: Programming Language :: Python :: 3.8
22
21
  Classifier: Programming Language :: Python :: 3.9
23
22
  Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
24
25
  Classifier: Programming Language :: Python :: Implementation :: CPython
25
26
  Classifier: Programming Language :: Python :: Implementation :: PyPy
26
27
  Classifier: Topic :: Database :: Front-Ends
27
- Requires-Python: >=3.7
28
+ Requires-Python: >=3.8
28
29
  Description-Content-Type: text/x-rst
29
30
  License-File: LICENSE
30
31
  Requires-Dist: SQLAlchemy >=1.3.0
@@ -33,7 +34,7 @@ Requires-Dist: typing-extensions >=4
33
34
  Requires-Dist: importlib-metadata ; python_version < "3.9"
34
35
  Requires-Dist: importlib-resources ; python_version < "3.9"
35
36
  Provides-Extra: tz
36
- Requires-Dist: python-dateutil ; extra == 'tz'
37
+ Requires-Dist: backports.zoneinfo ; (python_version < "3.9") and extra == 'tz'
37
38
 
38
39
  Alembic is a database migrations tool written by the author
39
40
  of `SQLAlchemy <http://www.sqlalchemy.org>`_. A migrations tool
@@ -1,58 +1,59 @@
1
- alembic/__init__.py,sha256=gczqgDgBRw3aV70aNeH6WGu0WdASQf_YiChV12qCRRI,75
1
+ alembic/__init__.py,sha256=Lc3Y-2KqkUQxaG2kXWDKmrLZnxw1EsfEZHOkz0oYmUE,63
2
2
  alembic/__main__.py,sha256=373m7-TBh72JqrSMYviGrxCHZo-cnweM8AGF8A22PmY,78
3
- alembic/command.py,sha256=ze4pYvKpB-FtF8rduY6F6n3XHqeA-15iXaaEDeNHVzI,21588
3
+ alembic/command.py,sha256=lLQoMaMC1ltzo2j2WgY2yl9vA9chqYqHWbYuNe_UKqA,21655
4
4
  alembic/config.py,sha256=68e1nmYU5Nfh0bNRqRWUygSilDl1p0G_U1zZ8ifgmD8,21931
5
5
  alembic/context.py,sha256=hK1AJOQXJ29Bhn276GYcosxeG7pC5aZRT5E8c4bMJ4Q,195
6
- alembic/context.pyi,sha256=FLsT0be_vO_ozlC05EJkWR5olDPoTVq-7tgtoM5wSAw,31463
6
+ alembic/context.pyi,sha256=E3O9N14_HQ9MCQAtyGm8WX7QHV6VwA3ft9TLJspUWdo,31514
7
7
  alembic/environment.py,sha256=MM5lPayGT04H3aeng1H7GQ8HEAs3VGX5yy6mDLCPLT4,43
8
8
  alembic/migration.py,sha256=MV6Fju6rZtn2fTREKzXrCZM6aIBGII4OMZFix0X-GLs,41
9
9
  alembic/op.py,sha256=flHtcsVqOD-ZgZKK2pv-CJ5Cwh-KJ7puMUNXzishxLw,167
10
10
  alembic/op.pyi,sha256=ldQBwAfzm_-ZsC3nizMuGoD34hjMKb4V_-Q1rR8q8LI,48591
11
11
  alembic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  alembic/autogenerate/__init__.py,sha256=4IHgWH89pForRq-yCDZhGjjVtsfGX5ECWNPuUs8nGUk,351
13
- alembic/autogenerate/api.py,sha256=MNn0Xtmj44aMFjfiR0LMkbxOynHyiyaRBnrj5EkImm4,21967
14
- alembic/autogenerate/compare.py,sha256=gSCjxrkQAl0rJD6o9Ln8wNxGVNU6FrWzKZYVkH5Tmac,47042
15
- alembic/autogenerate/render.py,sha256=Fik2aPZEIxOlTCrBd0UiPxnX5SFG__CvfXqMWoJr6lw,34475
13
+ alembic/autogenerate/api.py,sha256=SJMr8csBNv_4n9cYVLDjUNbukcVxjpLsQ4ctrDGpnR0,22012
14
+ alembic/autogenerate/compare.py,sha256=t1r0q6vXNmmrgGs7yhFP0-YqOBXmn2_EMnYJWsvezxk,44826
15
+ alembic/autogenerate/render.py,sha256=HXfwRPaaoFUXylebeN-CdGvKg4OkRV7hdc_vv3qLsa0,34942
16
16
  alembic/autogenerate/rewriter.py,sha256=Osba8GFVeqiX1ypGJW7Axt0ui2EROlaFtVZdMFbhzZ0,7384
17
17
  alembic/ddl/__init__.py,sha256=xXr1W6PePe0gCLwR42ude0E6iru9miUFc1fCeQN4YP8,137
18
+ alembic/ddl/_autogen.py,sha256=8HBUiYpLwi6iCGU7rmEVsPaCGeBLmEI2AcpqYkOpG9k,9086
18
19
  alembic/ddl/base.py,sha256=cCY3NldMRggrKd9bZ0mFRBE9GNDaAy0UJcM3ey4Utgw,9638
19
- alembic/ddl/impl.py,sha256=Z3GpNM2KwBpfl1UCam1YsYbSd0mQzRigOKQhUCLIPgE,25564
20
+ alembic/ddl/impl.py,sha256=NoYq6CGTzavYUajjy_47LZx4di_d7Z8Niu8p0SKDn84,28620
20
21
  alembic/ddl/mssql.py,sha256=0k26xnUSZNj3qCHEMzRFbaWgUzKcV07I3_-Ns47VhO0,14105
21
- alembic/ddl/mysql.py,sha256=ff8OE0zQ8YYjAgltBbtjQkDR-g9z65DNeFjEMm4sX6c,16675
22
+ alembic/ddl/mysql.py,sha256=mb0oHqTmJHQXxl3gocwK-tIkCh-H1-Mb7rFYTNbk37s,16715
22
23
  alembic/ddl/oracle.py,sha256=E0VaZaUM_5mwqNiJVA3zOAK-cuHVVIv_-NmUbH1JuGQ,6097
23
- alembic/ddl/postgresql.py,sha256=aO8pcVN5ycw1wG2m1RRt8dQUD1KgRa6T4rSzg9FPCkU,26457
24
+ alembic/ddl/postgresql.py,sha256=VTxqqMpdzW-yaJ1_J85GhnZSWq1vwuDbOrzJ4OtlxPo,29656
24
25
  alembic/ddl/sqlite.py,sha256=9q7NAxyeFwn9kWwQSc9RLeMFSos8waM7x9lnXdByh44,7613
25
26
  alembic/operations/__init__.py,sha256=e0KQSZAgLpTWvyvreB7DWg7RJV_MWSOPVDgCqsd2FzY,318
26
27
  alembic/operations/base.py,sha256=2so4KisDNuOLw0CRiZqorIHrhuenpVoFbn3B0sNvDic,72471
27
28
  alembic/operations/batch.py,sha256=uMvGJDlcTs0GSHasg4Gsdv1YcXeLOK_1lkRl3jk1ezY,26954
28
- alembic/operations/ops.py,sha256=aP9Uz36k98O_Y-njKIAifyvyhi0g2zU6_igKMos91_s,93539
29
+ alembic/operations/ops.py,sha256=fkdAxh9PEOw7SluJDVEUx1sMuH8LqAnM-vCOk0pw4NU,93515
29
30
  alembic/operations/schemaobj.py,sha256=-tWad8pgWUNWucbpTnPuFK_EEl913C0RADJhlBnrjhc,9393
30
- alembic/operations/toimpl.py,sha256=K8nUmojtL94tyLSWdDD-e94IbghZ19k55iBIMvzMm5E,6993
31
+ alembic/operations/toimpl.py,sha256=ZFdLsEITqOdJRuqq0DuiiLsexaN_AJou1F18rPpXLqI,6996
31
32
  alembic/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- alembic/runtime/environment.py,sha256=qaerrw5jB7zYliNnCvIziaju4-tvQ451MuGW8PHnfvw,41019
33
+ alembic/runtime/environment.py,sha256=kFTxvNhhmJRBXal-8AEnKr3hhL4rKLvJFfTGulp6uqY,41070
33
34
  alembic/runtime/migration.py,sha256=5UtTI_T0JtYzt6ZpeUhannMZOvXWiEymKFOpeCefaPY,49407
34
35
  alembic/script/__init__.py,sha256=lSj06O391Iy5avWAiq8SPs6N8RBgxkSPjP8wpXcNDGg,100
35
- alembic/script/base.py,sha256=90SpT8wyTMTUuS0Svsy5YIoqJSrR-6CtYSzStmRvFT0,37174
36
+ alembic/script/base.py,sha256=qvlqkGZnAhN_npeciaPiMoo_QEhETnQqueHuUte3MnQ,37693
36
37
  alembic/script/revision.py,sha256=DE0nwvDOzdFo843brvnhs1DfP0jRC5EVQHrNihC7PUQ,61471
37
38
  alembic/script/write_hooks.py,sha256=Nqj4zz3sm97kAPOpK1m-i2znJchiybO_TWT50oljlJw,4917
38
39
  alembic/templates/async/README,sha256=ISVtAOvqvKk_5ThM5ioJE-lMkvf9IbknFUFVU_vPma4,58
39
- alembic/templates/async/alembic.ini.mako,sha256=k3IyGDG15Rp1JDweC0TiDauaKYNvj3clrGfhw6oV6MI,3505
40
+ alembic/templates/async/alembic.ini.mako,sha256=uuhJETLWQuiYcs_jAOXHEjshEJ7VslEc1q4RRj0HWbE,3525
40
41
  alembic/templates/async/env.py,sha256=zbOCf3Y7w2lg92hxSwmG1MM_7y56i_oRH4AKp0pQBYo,2389
41
42
  alembic/templates/async/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
42
43
  alembic/templates/generic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
43
- alembic/templates/generic/alembic.ini.mako,sha256=gZWFmH2A9sP0i7cxEDhJFkjGtTKUXaVna8QAbIaRqxk,3614
44
+ alembic/templates/generic/alembic.ini.mako,sha256=sT7F852yN3c8X1-GKFlhuWExXxw9hY1eb1ZZ9flFSzc,3634
44
45
  alembic/templates/generic/env.py,sha256=TLRWOVW3Xpt_Tpf8JFzlnoPn_qoUu8UV77Y4o9XD6yI,2103
45
46
  alembic/templates/generic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
46
47
  alembic/templates/multidb/README,sha256=dWLDhnBgphA4Nzb7sNlMfCS3_06YqVbHhz-9O5JNqyI,606
47
- alembic/templates/multidb/alembic.ini.mako,sha256=j_Y0yuZVoHy7sTPgSPd8DmbT2ItvAdWs7trYZSOmFnw,3708
48
+ alembic/templates/multidb/alembic.ini.mako,sha256=mPh8JFJfWiGs6tMtL8_HAQ-Dz1QOoJgE5Vm76nIMqgU,3728
48
49
  alembic/templates/multidb/env.py,sha256=6zNjnW8mXGUk7erTsAvrfhvqoczJ-gagjVq1Ypg2YIQ,4230
49
50
  alembic/templates/multidb/script.py.mako,sha256=N06nMtNSwHkgl0EBXDyMt8njp9tlOesR583gfq21nbY,1090
50
51
  alembic/testing/__init__.py,sha256=kOxOh5nwmui9d-_CCq9WA4Udwy7ITjm453w74CTLZDo,1159
51
52
  alembic/testing/assertions.py,sha256=1CbJk8c8-WO9eJ0XJ0jJvMsNRLUrXV41NOeIJUAlOBk,5015
52
53
  alembic/testing/env.py,sha256=zJacVb_z6uLs2U1TtkmnFH9P3_F-3IfYbVv4UEPOvfo,10754
53
54
  alembic/testing/fixtures.py,sha256=NyP4wE_dFN9ZzSGiBagRu1cdzkka03nwJYJYHYrrkSY,9112
54
- alembic/testing/requirements.py,sha256=WByOiJxn2crazIXPq6-0cfqV95cfd9vP_ZQ1Cf2l8hY,4841
55
- alembic/testing/schemacompare.py,sha256=7_4_0Y4UvuMiZ66pz1RC_P8Z1kYOP-R4Y5qUcNmcMKA,4535
55
+ alembic/testing/requirements.py,sha256=dKeAO1l5TwBqXarJN-IPORlCqCJv-41Dj6oXoEikxHQ,5133
56
+ alembic/testing/schemacompare.py,sha256=N5UqSNCOJetIKC4vKhpYzQEpj08XkdgIoqBmEPQ3tlc,4838
56
57
  alembic/testing/util.py,sha256=CQrcQDA8fs_7ME85z5ydb-Bt70soIIID-qNY1vbR2dg,3350
57
58
  alembic/testing/warnings.py,sha256=RxA7x_8GseANgw07Us8JN_1iGbANxaw6_VitX2ZGQH4,1078
58
59
  alembic/testing/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -67,16 +68,16 @@ alembic/testing/suite/test_autogen_identity.py,sha256=kcuqngG7qXAKPJDX4U8sRzPKHE
67
68
  alembic/testing/suite/test_environment.py,sha256=w9F0xnLEbALeR8k6_-Tz6JHvy91IqiTSypNasVzXfZQ,11877
68
69
  alembic/testing/suite/test_op.py,sha256=2XQCdm_NmnPxHGuGj7hmxMzIhKxXNotUsKdACXzE1mM,1343
69
70
  alembic/util/__init__.py,sha256=cPF_jjFx7YRBByHHDqW3wxCIHsqnGfncEr_i238aduY,1202
70
- alembic/util/compat.py,sha256=WN8jPPFB9ri_uuEM1HEaN1ak3RJc_H3x8NqvtFkoXuM,2279
71
+ alembic/util/compat.py,sha256=qKZ2A1o-iAfAZlr2QZGbFYC-bRyzwnIvXk9FmNXVEAU,2245
71
72
  alembic/util/editor.py,sha256=JIz6_BdgV8_oKtnheR6DZoB7qnrHrlRgWjx09AsTsUw,2546
72
73
  alembic/util/exc.py,sha256=KQTru4zcgAmN4IxLMwLFS56XToUewaXB7oOLcPNjPwg,98
73
74
  alembic/util/langhelpers.py,sha256=ZFGyGygHRbztOeajpajppyhd-Gp4PB5slMuvCFVrnmg,8591
74
75
  alembic/util/messaging.py,sha256=B6T-loMhIOY3OTbG47Ywp1Df9LZn18PgjwpwLrD1VNg,3042
75
76
  alembic/util/pyfiles.py,sha256=95J01FChN0j2uP3p72mjaOQvh5wC6XbdGtTDK8oEzsQ,3373
76
- alembic/util/sqla_compat.py,sha256=94MHlkj43y-QQySz5dCUiJUNOPr3BF9TQ_BrP6ey-8w,18906
77
- alembic-1.12.1.dist-info/LICENSE,sha256=soUmiob0QW6vTQWyrjiAwVb3xZqPk1pAK8BW6vszrwg,1058
78
- alembic-1.12.1.dist-info/METADATA,sha256=D9-LeKL0unLPg2JKmlFMB5NAxt9N9y-8oVEGOUHbQnU,7306
79
- alembic-1.12.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
80
- alembic-1.12.1.dist-info/entry_points.txt,sha256=aykM30soxwGN0pB7etLc1q0cHJbL9dy46RnK9VX4LLw,48
81
- alembic-1.12.1.dist-info/top_level.txt,sha256=FwKWd5VsPFC8iQjpu1u9Cn-JnK3-V1RhUCmWqz1cl-s,8
82
- alembic-1.12.1.dist-info/RECORD,,
77
+ alembic/util/sqla_compat.py,sha256=UDLxFKx2EGXjPg9JM_r3RkElRxJL50qGuHC868P_nbo,18806
78
+ alembic-1.13.0.dist-info/LICENSE,sha256=soUmiob0QW6vTQWyrjiAwVb3xZqPk1pAK8BW6vszrwg,1058
79
+ alembic-1.13.0.dist-info/METADATA,sha256=JsSQBNQNfhDiHpeIjCEu99_l6QC0MsB1tnGLqVhzUlk,7390
80
+ alembic-1.13.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
81
+ alembic-1.13.0.dist-info/entry_points.txt,sha256=aykM30soxwGN0pB7etLc1q0cHJbL9dy46RnK9VX4LLw,48
82
+ alembic-1.13.0.dist-info/top_level.txt,sha256=FwKWd5VsPFC8iQjpu1u9Cn-JnK3-V1RhUCmWqz1cl-s,8
83
+ alembic-1.13.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5