Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ Changelog
1.1
===

1.1.5
-----

Fixed
^^^^^
- ``makemigrations`` no longer crashes with ``AttributeError: 'tuple' object has no attribute 'deconstruct'`` when generating a fresh ``CreateModel`` migration for models using tuple-style ``Meta.indexes`` (e.g. ``indexes = [("field_a", "field_b")]``). Tuple entries are now normalised to ``Index`` objects before rendering.

1.1.4
-----

Expand Down
2 changes: 1 addition & 1 deletion tests/contrib/test_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def test_basic_example_script(db) -> None:
r = subprocess.run( # nosec
[sys.executable, "examples/basic.py"], capture_output=True, text=True, env=env
)
assert not r.stderr, f"Script had errors: {r.stderr}"
assert r.returncode == 0, f"Script failed (rc={r.returncode}): {r.stderr}"
output = r.stdout
s = "[{'id': 1, 'name': 'Updated name'}, {'id': 2, 'name': 'Test 2'}]"
assert s in output
Expand Down
30 changes: 30 additions & 0 deletions tests/migrations/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,36 @@ class Migration(migrations.Migration):
_write_migration(tmp_path, monkeypatch, "0003_options", operations, expected)


def test_writer_handles_tuple_indexes_in_options(tmp_path: Path, monkeypatch) -> None:
"""Tuple-style indexes in options should be normalised to Index objects without crashing."""
operations = [
CreateModel(
name="Token",
fields=[
("id", fields.IntField(primary_key=True)),
("user_id", fields.IntField()),
("revoked_at", fields.DatetimeField(null=True)),
],
options={
"indexes": [
("user_id", "revoked_at"),
],
},
),
]
module_path = _prepare_migration_package(tmp_path, "app")
monkeypatch.syspath_prepend(str(tmp_path))
writer = MigrationWriter(
"0001_initial",
"app",
operations,
migrations_module=module_path,
)
content = writer.as_string()
assert "Index(fields=['user_id', 'revoked_at'])" in content
assert "from tortoise.indexes import Index" in content


def test_writer_renders_fk_field(tmp_path: Path, monkeypatch) -> None:
operations = [
CreateModel(
Expand Down
2 changes: 1 addition & 1 deletion tests/test_relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ async def test_reverse_relation_create_fk_errors_for_unsaved_instance(db):
async def test_recursive(db) -> None:
file = "examples/relations_recursive.py"
r = subprocess.run([sys.executable, file], capture_output=True, text=True) # nosec
assert not r.stderr, f"Script had errors: {r.stderr}"
assert r.returncode == 0, f"Script failed (rc={r.returncode}): {r.stderr}"
output = r.stdout
s = "2.1. Second H2 (to: ) (from: 2.2. Third H2, Loose, 1.1. First H2)"
assert s in output
2 changes: 1 addition & 1 deletion tortoise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ async def main() -> None:
portal.call(main)


__version__ = "1.1.4"
__version__ = "1.1.5"

__all__ = [
"BackwardFKRelation",
Expand Down
6 changes: 5 additions & 1 deletion tortoise/migrations/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from pypika_tortoise.context import DEFAULT_SQL_CONTEXT

from tortoise.indexes import Index
from tortoise.migrations.constraints import CheckConstraint, UniqueConstraint
from tortoise.migrations.operations import (
AddConstraint,
Expand Down Expand Up @@ -455,8 +456,11 @@ def _render_model_options(self, options: dict[str, Any], imports: ImportManager)
rendered: dict[str, str] = {}
for key, value in options.items():
if key == "indexes":
normalized = [
item if isinstance(item, Index) else Index(fields=tuple(item)) for item in value
]
rendered[key] = (
"[" + ", ".join(self._render_index(item, imports) for item in value) + "]"
"[" + ", ".join(self._render_index(item, imports) for item in normalized) + "]"
)
continue
if key == "constraints":
Expand Down