sqlacodegen 4.0.1__tar.gz → 4.0.2__tar.gz

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 (37) hide show
  1. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/CHANGES.rst +10 -0
  2. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/PKG-INFO +1 -1
  3. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen/generators.py +104 -23
  4. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen.egg-info/PKG-INFO +1 -1
  5. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/tests/test_generator_declarative.py +106 -0
  6. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/tests/test_generator_sqlmodel.py +103 -0
  7. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/tests/test_generator_tables.py +28 -0
  8. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/FUNDING.yml +0 -0
  9. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  10. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  11. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/ISSUE_TEMPLATE/features_request.yaml +0 -0
  12. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/dependabot.yml +0 -0
  13. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/pull_request_template.md +0 -0
  14. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/workflows/publish.yml +0 -0
  15. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.github/workflows/test.yml +0 -0
  16. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.gitignore +0 -0
  17. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/.pre-commit-config.yaml +0 -0
  18. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/CONTRIBUTING.rst +0 -0
  19. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/LICENSE +0 -0
  20. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/README.rst +0 -0
  21. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/pyproject.toml +0 -0
  22. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/setup.cfg +0 -0
  23. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen/__init__.py +0 -0
  24. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen/__main__.py +0 -0
  25. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen/cli.py +0 -0
  26. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen/models.py +0 -0
  27. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen/py.typed +0 -0
  28. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen/utils.py +0 -0
  29. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen.egg-info/SOURCES.txt +0 -0
  30. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen.egg-info/dependency_links.txt +0 -0
  31. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen.egg-info/entry_points.txt +0 -0
  32. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen.egg-info/requires.txt +0 -0
  33. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/src/sqlacodegen.egg-info/top_level.txt +0 -0
  34. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/tests/__init__.py +0 -0
  35. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/tests/conftest.py +0 -0
  36. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/tests/test_cli.py +0 -0
  37. {sqlacodegen-4.0.1 → sqlacodegen-4.0.2}/tests/test_generator_dataclass.py +0 -0
@@ -1,6 +1,16 @@
1
1
  Version history
2
2
  ===============
3
3
 
4
+ **4.0.2**
5
+
6
+ - Fixed rendering of inherited keyword arguments for dialect-specific types that use
7
+ ``**kwargs`` in their initializers (such as MySQL ``CHAR`` with ``collation``) while
8
+ preserving existing ``*args`` rendering behavior (PR by @hyoj0942)
9
+ - Fixed missing metadata argument when rendering plain tables with the SQLModel
10
+ - Added support for self-referential tables in the SQLModel generator (PR by @sheinbergon)
11
+ - Fixed empty dialect kwargs (e.g. ``postgresql_include=[]``) being included in
12
+ rendered indexes, tables, and columns (PR by @sheinbergon)
13
+
4
14
  **4.0.1**
5
15
 
6
16
  - Fix enum column definitions to explicitly include schema and name if reflected
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlacodegen
3
- Version: 4.0.1
3
+ Version: 4.0.2
4
4
  Summary: Automatic model code generator for SQLAlchemy
5
5
  Author-email: Alex Grönholm <alex.gronholm@nextday.fi>
6
6
  Maintainer-email: Idan Sheinberg <ishinberg0@gmail.com>
@@ -427,6 +427,7 @@ class TablesGenerator(CodeGenerator):
427
427
  kwargs = {
428
428
  key: repr(value) if isinstance(value, str) else value
429
429
  for key, value in sorted(index.kwargs.items(), key=lambda item: item[0])
430
+ if value not in ([], {})
430
431
  }
431
432
  if index.unique:
432
433
  kwargs["unique"] = True
@@ -541,6 +542,77 @@ class TablesGenerator(CodeGenerator):
541
542
  else:
542
543
  return render_callable("mapped_column", *args, kwargs=kwargs)
543
544
 
545
+ def _render_column_type_value(self, value: Any) -> str:
546
+ if isinstance(value, (JSONB, JSON)):
547
+ # Remove astext_type if it's the default
548
+ if isinstance(value.astext_type, Text) and value.astext_type.length is None:
549
+ value.astext_type = None # type: ignore[assignment]
550
+ else:
551
+ self.add_import(Text)
552
+
553
+ if isinstance(value, TextClause):
554
+ self.add_literal_import("sqlalchemy", "text")
555
+ return render_callable("text", repr(value.text))
556
+
557
+ return repr(value)
558
+
559
+ def _collect_inherited_init_kwargs(
560
+ self,
561
+ column_type: Any,
562
+ init_sig: inspect.Signature,
563
+ seen_param_names: set[str],
564
+ missing: object,
565
+ ) -> dict[str, str]:
566
+ has_var_keyword = any(
567
+ param.kind is Parameter.VAR_KEYWORD
568
+ for param in init_sig.parameters.values()
569
+ )
570
+ has_var_positional = any(
571
+ param.kind is Parameter.VAR_POSITIONAL
572
+ for param in init_sig.parameters.values()
573
+ )
574
+ if not has_var_keyword or has_var_positional:
575
+ return {}
576
+
577
+ inherited_kwargs: dict[str, str] = {}
578
+ for supercls in column_type.__class__.__mro__[1:]:
579
+ if supercls is object:
580
+ break
581
+
582
+ try:
583
+ super_sig = inspect.signature(supercls.__init__)
584
+ except (TypeError, ValueError):
585
+ continue
586
+
587
+ for super_param in list(super_sig.parameters.values())[1:]:
588
+ if super_param.name.startswith("_"):
589
+ continue
590
+
591
+ if super_param.kind in (
592
+ Parameter.POSITIONAL_ONLY,
593
+ Parameter.VAR_POSITIONAL,
594
+ Parameter.VAR_KEYWORD,
595
+ ):
596
+ continue
597
+
598
+ if super_param.name in seen_param_names:
599
+ continue
600
+
601
+ seen_param_names.add(super_param.name)
602
+ value = getattr(column_type, super_param.name, missing)
603
+ if value is missing:
604
+ continue
605
+
606
+ default = super_param.default
607
+ if default is not Parameter.empty and value == default:
608
+ continue
609
+
610
+ inherited_kwargs[super_param.name] = self._render_column_type_value(
611
+ value
612
+ )
613
+
614
+ return inherited_kwargs
615
+
544
616
  def render_column_type(self, column: Column[Any]) -> str:
545
617
  column_type = column.type
546
618
  # Check if this is an enum column with a Python enum class
@@ -586,6 +658,8 @@ class TablesGenerator(CodeGenerator):
586
658
  defaults = {param.name: param.default for param in sig.parameters.values()}
587
659
  missing = object()
588
660
  use_kwargs = False
661
+ seen_param_names: set[str] = set()
662
+
589
663
  for param in list(sig.parameters.values())[1:]:
590
664
  # Remove annoyances like _warn_on_bytestring
591
665
  if param.name.startswith("_"):
@@ -594,32 +668,25 @@ class TablesGenerator(CodeGenerator):
594
668
  use_kwargs = True
595
669
  continue
596
670
 
671
+ seen_param_names.add(param.name)
597
672
  value = getattr(column_type, param.name, missing)
598
-
599
- if isinstance(value, (JSONB, JSON)):
600
- # Remove astext_type if it's the default
601
- if (
602
- isinstance(value.astext_type, Text)
603
- and value.astext_type.length is None
604
- ):
605
- value.astext_type = None # type: ignore[assignment]
606
- else:
607
- self.add_import(Text)
608
-
609
673
  default = defaults.get(param.name, missing)
610
- if isinstance(value, TextClause):
611
- self.add_literal_import("sqlalchemy", "text")
612
- rendered_value = render_callable("text", repr(value.text))
613
- else:
614
- rendered_value = repr(value)
615
-
616
674
  if value is missing or value == default:
617
675
  use_kwargs = True
618
- elif use_kwargs:
676
+ continue
677
+
678
+ rendered_value = self._render_column_type_value(value)
679
+ if use_kwargs:
619
680
  kwargs[param.name] = rendered_value
620
681
  else:
621
682
  args.append(rendered_value)
622
683
 
684
+ kwargs.update(
685
+ self._collect_inherited_init_kwargs(
686
+ column_type, sig, seen_param_names, missing
687
+ )
688
+ )
689
+
623
690
  vararg = next(
624
691
  (
625
692
  param.name
@@ -712,6 +779,9 @@ class TablesGenerator(CodeGenerator):
712
779
  except Exception:
713
780
  continue
714
781
 
782
+ if isinstance(value, list | dict) and not value:
783
+ continue
784
+
715
785
  # Render values:
716
786
  # - callable context (values_for_dict=False): produce a string expression.
717
787
  # primitives use repr(value); custom objects stringify then repr().
@@ -1671,13 +1741,16 @@ class DeclarativeGenerator(TablesGenerator):
1671
1741
  ) -> Mapping[str, Any]:
1672
1742
  def render_column_attrs(column_attrs: list[ColumnAttribute]) -> str:
1673
1743
  rendered = []
1744
+ render_as_string = False
1674
1745
  for attr in column_attrs:
1675
- if attr.model is relationship.source:
1746
+ if not self.explicit_foreign_keys and attr.model is relationship.source:
1676
1747
  rendered.append(attr.name)
1677
1748
  else:
1678
- rendered.append(repr(f"{attr.model.name}.{attr.name}"))
1749
+ rendered.append(f"{attr.model.name}.{attr.name}")
1750
+ render_as_string = True
1679
1751
 
1680
- return "[" + ", ".join(rendered) + "]"
1752
+ joined = "[" + ", ".join(rendered) + "]"
1753
+ return repr(joined) if render_as_string else joined
1681
1754
 
1682
1755
  def render_foreign_keys(column_attrs: list[ColumnAttribute]) -> str:
1683
1756
  rendered = []
@@ -1806,19 +1879,27 @@ class SQLModelGenerator(DeclarativeGenerator):
1806
1879
  self.add_import(Column)
1807
1880
  return render_callable("Column", *args, kwargs=kwargs)
1808
1881
 
1882
+ def render_table(self, table: Table) -> str:
1883
+ # Hack to fix #465 without breaking backwards compatibility
1884
+ self.base.metadata_ref = "SQLModel.metadata"
1885
+
1886
+ return super().render_table(table)
1887
+
1809
1888
  def generate_base(self) -> None:
1810
1889
  self.base = Base(
1811
1890
  literal_imports=[],
1812
1891
  declarations=[],
1813
- metadata_ref="",
1892
+ metadata_ref="SQLModel.metadata",
1814
1893
  )
1815
1894
 
1816
1895
  def collect_imports(self, models: Iterable[Model]) -> None:
1817
1896
  super(DeclarativeGenerator, self).collect_imports(models)
1818
1897
  if any(isinstance(model, ModelClass) for model in models):
1898
+ self.add_literal_import("sqlmodel", "Field")
1899
+
1900
+ if models:
1819
1901
  self.remove_literal_import("sqlalchemy", "MetaData")
1820
1902
  self.add_literal_import("sqlmodel", "SQLModel")
1821
- self.add_literal_import("sqlmodel", "Field")
1822
1903
 
1823
1904
  def collect_imports_for_model(self, model: Model) -> None:
1824
1905
  super(DeclarativeGenerator, self).collect_imports_for_model(model)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlacodegen
3
- Version: 4.0.1
3
+ Version: 4.0.2
4
4
  Summary: Automatic model code generator for SQLAlchemy
5
5
  Author-email: Alex Grönholm <alex.gronholm@nextday.fi>
6
6
  Maintainer-email: Idan Sheinberg <ishinberg0@gmail.com>
@@ -321,6 +321,40 @@ class Num2(Base):
321
321
  )
322
322
 
323
323
 
324
+ @pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"])
325
+ @pytest.mark.parametrize("generator", [["keep_dialect_types"]], indirect=True)
326
+ def test_keep_dialect_types_keeps_mysql_char_collation(
327
+ generator: CodeGenerator,
328
+ ) -> None:
329
+ from sqlalchemy.dialects.mysql import CHAR as MYSQL_CHAR
330
+ from sqlalchemy.dialects.mysql import INTEGER as MYSQL_INTEGER
331
+
332
+ Table(
333
+ "result_logs",
334
+ generator.metadata,
335
+ Column("id", MYSQL_INTEGER, primary_key=True),
336
+ Column("result_code", MYSQL_CHAR(1, collation="utf8mb3_bin"), nullable=False),
337
+ )
338
+
339
+ validate_code(
340
+ generator.generate(),
341
+ """\
342
+ from sqlalchemy.dialects.mysql import CHAR, INTEGER
343
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
344
+
345
+ class Base(DeclarativeBase):
346
+ pass
347
+
348
+
349
+ class ResultLogs(Base):
350
+ __tablename__ = 'result_logs'
351
+
352
+ id: Mapped[int] = mapped_column(INTEGER, primary_key=True)
353
+ result_code: Mapped[str] = mapped_column(CHAR(1, collation='utf8mb3_bin'), nullable=False)
354
+ """,
355
+ )
356
+
357
+
324
358
  def test_onetomany(generator: CodeGenerator) -> None:
325
359
  Table(
326
360
  "simple_items",
@@ -3127,3 +3161,75 @@ def test_array_enum_named_with_schema(generator: CodeGenerator) -> None:
3127
3161
  tags: Mapped[list[TagEnum]] = mapped_column(ARRAY(Enum(TagEnum, values_callable=lambda cls: [member.value for member in cls], name='tag_enum', schema='custom_schema')), nullable=False)
3128
3162
  """,
3129
3163
  )
3164
+
3165
+
3166
+ def test_index_with_empty_kwargs(generator: CodeGenerator) -> None:
3167
+ simple_items = Table(
3168
+ "simple_items",
3169
+ generator.metadata,
3170
+ Column("id", INTEGER, primary_key=True),
3171
+ Column("name", VARCHAR),
3172
+ )
3173
+ simple_items.indexes.add(
3174
+ Index(
3175
+ "idx_name",
3176
+ simple_items.c.name,
3177
+ postgresql_using="gist",
3178
+ postgresql_include=[],
3179
+ )
3180
+ )
3181
+
3182
+ validate_code(
3183
+ generator.generate(),
3184
+ """\
3185
+ from typing import Optional
3186
+
3187
+ from sqlalchemy import Index, Integer, String
3188
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
3189
+
3190
+ class Base(DeclarativeBase):
3191
+ pass
3192
+
3193
+
3194
+ class SimpleItems(Base):
3195
+ __tablename__ = 'simple_items'
3196
+ __table_args__ = (
3197
+ Index('idx_name', 'name', postgresql_using='gist'),
3198
+ )
3199
+
3200
+ id: Mapped[int] = mapped_column(Integer, primary_key=True)
3201
+ name: Mapped[Optional[str]] = mapped_column(String)
3202
+ """,
3203
+ )
3204
+
3205
+
3206
+ @pytest.mark.parametrize("generator", [["include_dialect_options"]], indirect=True)
3207
+ def test_include_dialect_options_empty_values_skipped(
3208
+ generator: CodeGenerator,
3209
+ ) -> None:
3210
+ Table(
3211
+ "t_opts3",
3212
+ generator.metadata,
3213
+ Column("id", INTEGER, primary_key=True),
3214
+ mysql_engine="InnoDB",
3215
+ mysql_partition_by=[],
3216
+ mysql_PROPERTIES={},
3217
+ )
3218
+
3219
+ validate_code(
3220
+ generator.generate(),
3221
+ """\
3222
+ from sqlalchemy import Integer
3223
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
3224
+
3225
+ class Base(DeclarativeBase):
3226
+ pass
3227
+
3228
+
3229
+ class TOpts3(Base):
3230
+ __tablename__ = 't_opts3'
3231
+ __table_args__ = {'mysql_engine': 'InnoDB'}
3232
+
3233
+ id: Mapped[int] = mapped_column(Integer, primary_key=True)
3234
+ """,
3235
+ )
@@ -366,3 +366,106 @@ def test_array_enum_named_with_schema(generator: CodeGenerator) -> None:
366
366
  tags: list[TagEnum] = Field(sa_column=Column('tags', ARRAY(Enum(TagEnum, values_callable=lambda cls: [member.value for member in cls], name='tag_enum', schema='custom_schema')), nullable=False))
367
367
  """,
368
368
  )
369
+
370
+
371
+ def test_fallback_table(generator: CodeGenerator) -> None:
372
+ Table(
373
+ "simple_fallback",
374
+ generator.metadata,
375
+ Column("field", VARCHAR(20), nullable=False),
376
+ )
377
+
378
+ validate_code(
379
+ generator.generate(),
380
+ """\
381
+ from sqlalchemy import Column, String, Table
382
+ from sqlmodel import SQLModel
383
+
384
+ t_simple_fallback = Table(
385
+ 'simple_fallback', SQLModel.metadata,
386
+ Column('field', String(20), nullable=False)
387
+ )
388
+ """,
389
+ )
390
+
391
+
392
+ def test_onetomany_selfref(generator: CodeGenerator) -> None:
393
+ Table(
394
+ "simple_items",
395
+ generator.metadata,
396
+ Column("id", INTEGER, primary_key=True),
397
+ Column("parent_item_id", INTEGER),
398
+ ForeignKeyConstraint(["parent_item_id"], ["simple_items.id"]),
399
+ )
400
+
401
+ validate_code(
402
+ generator.generate(),
403
+ """\
404
+ from typing import Optional
405
+
406
+ from sqlalchemy import Column, ForeignKey, Integer
407
+ from sqlmodel import Field, Relationship, SQLModel
408
+
409
+ class SimpleItems(SQLModel, table=True):
410
+ __tablename__ = 'simple_items'
411
+
412
+ id: int = Field(sa_column=Column('id', Integer, primary_key=True))
413
+ parent_item_id: Optional[int] = Field(default=None, sa_column=Column(\
414
+ 'parent_item_id', ForeignKey('simple_items.id')))
415
+
416
+ parent_item: Optional['SimpleItems'] = Relationship(\
417
+ back_populates='parent_item_reverse', sa_relationship_kwargs={\
418
+ 'remote_side': '[SimpleItems.id]'})
419
+ parent_item_reverse: list['SimpleItems'] = Relationship(\
420
+ back_populates='parent_item', sa_relationship_kwargs={\
421
+ 'remote_side': '[SimpleItems.parent_item_id]'})
422
+ """,
423
+ )
424
+
425
+
426
+ def test_onetomany_selfref_multi(generator: CodeGenerator) -> None:
427
+ Table(
428
+ "simple_items_selfref",
429
+ generator.metadata,
430
+ Column("id", INTEGER, primary_key=True),
431
+ Column("parent_item_id", INTEGER),
432
+ Column("top_item_id", INTEGER),
433
+ ForeignKeyConstraint(["parent_item_id"], ["simple_items_selfref.id"]),
434
+ ForeignKeyConstraint(["top_item_id"], ["simple_items_selfref.id"]),
435
+ )
436
+
437
+ validate_code(
438
+ generator.generate(),
439
+ """\
440
+ from typing import Optional
441
+
442
+ from sqlalchemy import Column, ForeignKey, Integer
443
+ from sqlmodel import Field, Relationship, SQLModel
444
+
445
+ class SimpleItemsSelfref(SQLModel, table=True):
446
+ __tablename__ = 'simple_items_selfref'
447
+
448
+ id: int = Field(sa_column=Column('id', Integer, primary_key=True))
449
+ parent_item_id: Optional[int] = Field(default=None, sa_column=Column(\
450
+ 'parent_item_id', ForeignKey('simple_items_selfref.id')))
451
+ top_item_id: Optional[int] = Field(default=None, sa_column=Column(\
452
+ 'top_item_id', ForeignKey('simple_items_selfref.id')))
453
+
454
+ parent_item: Optional['SimpleItemsSelfref'] = Relationship(\
455
+ back_populates='parent_item_reverse', sa_relationship_kwargs={\
456
+ 'remote_side': '[SimpleItemsSelfref.id]', \
457
+ 'foreign_keys': '[SimpleItemsSelfref.parent_item_id]'})
458
+ parent_item_reverse: list['SimpleItemsSelfref'] = Relationship(\
459
+ back_populates='parent_item', sa_relationship_kwargs={\
460
+ 'remote_side': '[SimpleItemsSelfref.parent_item_id]', \
461
+ 'foreign_keys': '[SimpleItemsSelfref.parent_item_id]'})
462
+ top_item: Optional['SimpleItemsSelfref'] = Relationship(\
463
+ back_populates='top_item_reverse', sa_relationship_kwargs={\
464
+ 'remote_side': '[SimpleItemsSelfref.id]', \
465
+ 'foreign_keys': '[SimpleItemsSelfref.top_item_id]'})
466
+ top_item_reverse: list['SimpleItemsSelfref'] = Relationship(\
467
+ back_populates='top_item', sa_relationship_kwargs={\
468
+ 'remote_side': '[SimpleItemsSelfref.top_item_id]', \
469
+ 'foreign_keys': '[SimpleItemsSelfref.top_item_id]'})
470
+ """,
471
+ )
@@ -603,6 +603,34 @@ def test_mysql_column_types(generator: CodeGenerator) -> None:
603
603
  )
604
604
 
605
605
 
606
+ @pytest.mark.parametrize("engine", ["mysql"], indirect=["engine"])
607
+ @pytest.mark.parametrize("generator", [["keep_dialect_types"]], indirect=True)
608
+ def test_mysql_char_collation_keep_dialect_types(generator: CodeGenerator) -> None:
609
+ Table(
610
+ "simple_items",
611
+ generator.metadata,
612
+ Column("id", mysql.INTEGER, primary_key=True),
613
+ Column("result_code", mysql.CHAR(1, collation="utf8mb3_bin"), nullable=False),
614
+ )
615
+
616
+ validate_code(
617
+ generator.generate(),
618
+ """\
619
+ from sqlalchemy import Column, MetaData, Table
620
+ from sqlalchemy.dialects.mysql import CHAR, INTEGER
621
+
622
+ metadata = MetaData()
623
+
624
+
625
+ t_simple_items = Table(
626
+ 'simple_items', metadata,
627
+ Column('id', INTEGER, primary_key=True),
628
+ Column('result_code', CHAR(1, collation='utf8mb3_bin'), nullable=False)
629
+ )
630
+ """,
631
+ )
632
+
633
+
606
634
  def test_constraints(generator: CodeGenerator) -> None:
607
635
  Table(
608
636
  "simple_items",
File without changes
File without changes
File without changes
File without changes
File without changes