Skip to content

Commit

Permalink
fix: change file type for graph file from pickle to JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
browniebroke committed Oct 13, 2023
1 parent fa61feb commit 5153293
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 11 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,6 @@ dmypy.json

# Cython debug symbols
cython_debug/

# Some files that might be generated in tests
tests/graph.json
22 changes: 11 additions & 11 deletions src/remake_migrations/management/commands/remakemigrations.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from __future__ import annotations

import datetime as dt
import pickle
import json
from collections import defaultdict
from importlib import import_module
from pathlib import Path

from django.apps import AppConfig, apps
Expand All @@ -28,7 +29,7 @@ class Command(BaseCommand):
- makemigrations: should not detect any differences
"""

graph_file = Path(settings.BASE_DIR) / "graph.pickle"
graph_file = Path(settings.BASE_DIR) / "graph.json"

def add_arguments(self, parser: CommandParser) -> None:
"""Add the option to run a specific step of the process."""
Expand All @@ -38,8 +39,6 @@ def add_arguments(self, parser: CommandParser) -> None:
def handle(self, step: int, *args: str, **options: str) -> None:
"""Execute one step after another to avoid side effects between steps."""
if step == 1:
# First, make sure we have applied all migrations
call_command("migrate")
# Remove old migration files
self.clear_old_migrations()
if step == 2:
Expand All @@ -53,14 +52,12 @@ def handle(self, step: int, *args: str, **options: str) -> None:
@property
def old_migrations(self) -> dict[str, list[str]]:
"""Load old migrations from a pickle file."""
with self.graph_file.open("rb") as fh:
return pickle.load(fh) # noqa S301
return json.loads(self.graph_file.read_text())

@old_migrations.setter
def old_migrations(self, value: dict[str, list[str]]) -> None:
"""Save old migrations in a pickle file."""
with self.graph_file.open("wb") as fh:
pickle.dump(value, fh)
"""Save old migrations graph in a file."""
self.graph_file.write_text(json.dumps(value, indent=2))

def clear_old_migrations(self) -> None:
"""Remove all pre-existing migration files in first party apps."""
Expand All @@ -84,8 +81,11 @@ def _is_first_party(app_config: AppConfig) -> bool:
@staticmethod
def remove_migration_file(app_label: str, migration_name: str) -> None:
"""Remove file from the disk for the specified migration."""
app_config = apps.get_app_config(app_label)
migration_file = Path(app_config.path) / "migrations" / f"{migration_name}.py"
app_migrations_module_name, _ = MigrationLoader.migrations_module(app_label)
migration_module = import_module(
f"{app_migrations_module_name}.{migration_name}"
)
migration_file = Path(migration_module.__file__) # type: ignore[arg-type]
migration_file.unlink()

def update_new_migrations(self) -> None:
Expand Down
58 changes: 58 additions & 0 deletions tests/test_remakemigrations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from __future__ import annotations

import sys
import time
from pathlib import Path
from textwrap import dedent

import pytest
from django.test import TestCase, override_settings

from tests.utils import EMPTY_MIGRATION, run_command


class RemakeMigrationsTests(TestCase):
@pytest.fixture(autouse=True)
def tmp_path_fixture(self, tmp_path):
migrations_module_name = "migrations" + str(time.time()).replace(".", "")
self.migrations_dir = tmp_path / migrations_module_name
self.migrations_dir.mkdir()
sys.path.insert(0, str(tmp_path))
try:
with override_settings(
MIGRATION_MODULES={"testapp": migrations_module_name}
):
yield
finally:
sys.path.pop(0)

def test_success_step_1(self):
(self.migrations_dir / "__init__.py").touch()
initial_0001 = self.migrations_dir / "0001_initial.py"
initial_0001.write_text(EMPTY_MIGRATION)
migration_0002 = self.migrations_dir / "0002_something.py"
migration_0002.write_text(
dedent(
"""\
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('testapp', '0001_initial'),
]
operations = []
"""
)
)

out, err, returncode = run_command("remakemigrations", "--step", "1")

assert out == ""
assert err == ""
assert returncode == 0

assert not initial_0001.exists()
assert not migration_0002.exists()

graph_json = Path(__file__).parent / "graph.json"
assert graph_json.exists()
26 changes: 26 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from __future__ import annotations

from io import StringIO
from textwrap import dedent

from django.core.management import call_command


def run_command(*args, **kwargs):
out = StringIO()
err = StringIO()
return_code: int | str | None = 0
try:
call_command(*args, stdout=out, stderr=err, **kwargs)
except SystemExit as exc: # pragma: no cover
return_code = exc.code
return out.getvalue(), err.getvalue(), return_code


EMPTY_MIGRATION = dedent(
"""\
from django.db import migrations
class Migration(migrations.Migration):
pass
"""
)

0 comments on commit 5153293

Please sign in to comment.