From 593bdf173652742d4f738fe8beba49d4440ab29a Mon Sep 17 00:00:00 2001 From: henkhogan Date: Sat, 4 Jan 2025 22:37:58 +0100 Subject: [PATCH 1/2] Allow to opt out from special naming when fieldname ends with _id --- README.rst | 2 ++ src/sqlacodegen/generators.py | 3 +- tests/test_generator_declarative.py | 53 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index cd94205e..a91bec14 100644 --- a/README.rst +++ b/README.rst @@ -103,6 +103,8 @@ values must be delimited by commas, e.g. ``--options noconstraints,nobidi``): * ``noconstraints``: ignore constraints (foreign key, unique etc.) * ``nocomments``: ignore table/column comments * ``noindexes``: ignore indexes + * ``noidsuffix``: prevent the special naming logic for single column many-to-one + and one-to-one relationships (see `Relationship naming logic`_ for details) * ``declarative`` diff --git a/src/sqlacodegen/generators.py b/src/sqlacodegen/generators.py index 862c2338..f4efd7da 100644 --- a/src/sqlacodegen/generators.py +++ b/src/sqlacodegen/generators.py @@ -725,6 +725,7 @@ class DeclarativeGenerator(TablesGenerator): "use_inflect", "nojoined", "nobidi", + "noidsuffix", } def __init__( @@ -1061,7 +1062,7 @@ def generate_relationship_name( # If there's a constraint with a single column that ends with "_id", use the # preceding part as the relationship name - if relationship.constraint: + if relationship.constraint and "noidsuffix" not in self.options: is_source = relationship.source.table is relationship.constraint.table if is_source or relationship.type not in ( RelationshipType.ONE_TO_ONE, diff --git a/tests/test_generator_declarative.py b/tests/test_generator_declarative.py index 6bdee3d8..bd9062a9 100644 --- a/tests/test_generator_declarative.py +++ b/tests/test_generator_declarative.py @@ -1470,6 +1470,59 @@ class SimpleItems(Base): ) +@pytest.mark.parametrize("generator", [["noidsuffix"]], indirect=True) +def test_named_foreign_key_constraints_with_noidsuffix(generator: CodeGenerator) -> None: + Table( + "simple_items", + generator.metadata, + Column("id", INTEGER, primary_key=True), + Column("container_id", INTEGER), + ForeignKeyConstraint( + ["container_id"], ["simple_containers.id"], name="foreignkeytest" + ), + ) + Table( + "simple_containers", + generator.metadata, + Column("id", INTEGER, primary_key=True), + ) + + validate_code( + generator.generate(), + """\ +from typing import List, Optional + +from sqlalchemy import ForeignKeyConstraint, Integer +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + +class Base(DeclarativeBase): + pass + + +class SimpleContainers(Base): + __tablename__ = 'simple_containers' + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + + simple_items: Mapped[List['SimpleItems']] = relationship('SimpleItems', \ +back_populates='simple_containers') + + +class SimpleItems(Base): + __tablename__ = 'simple_items' + __table_args__ = ( + ForeignKeyConstraint(['container_id'], ['simple_containers.id'], \ +name='foreignkeytest'), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + container_id: Mapped[Optional[int]] = mapped_column(Integer) + + simple_containers: Mapped['SimpleContainers'] = relationship('SimpleContainers', \ +back_populates='simple_items') +""", + ) + # @pytest.mark.xfail(strict=True) def test_colname_import_conflict(generator: CodeGenerator) -> None: Table( From 20b22836ed4f8b54be8f96f93ccc5b9ade5e70eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 4 Jan 2025 21:39:15 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_generator_declarative.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_generator_declarative.py b/tests/test_generator_declarative.py index bd9062a9..49aa4375 100644 --- a/tests/test_generator_declarative.py +++ b/tests/test_generator_declarative.py @@ -1471,7 +1471,9 @@ class SimpleItems(Base): @pytest.mark.parametrize("generator", [["noidsuffix"]], indirect=True) -def test_named_foreign_key_constraints_with_noidsuffix(generator: CodeGenerator) -> None: +def test_named_foreign_key_constraints_with_noidsuffix( + generator: CodeGenerator, +) -> None: Table( "simple_items", generator.metadata, @@ -1523,6 +1525,7 @@ class SimpleItems(Base): """, ) + # @pytest.mark.xfail(strict=True) def test_colname_import_conflict(generator: CodeGenerator) -> None: Table(