Support partial function inspection in data migrations

This commit is contained in:
Caspar Wylie authored and David Wobrock committed 2023-07-03 21:02:14 +02:00
1 parent 97a1f5c6c9
commit 2d15ea84f9
4 files changed
+50 -5

No files matched your search

+1
View File
@@ -9,6 +9,7 @@ Features:
- Fixed `RunPython` model import check when using a `through` object like `MyModel.many_to_many.through.objects.filter(...)` (issue #218)
- Mark the `IgnoreMigration` operation as `elidable=True`
- Handle `functools.partial` functions in RunPython data migrations
Bug:
+14 -5
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import functools
import hashlib
import inspect
import logging
@@ -473,10 +474,16 @@ class MigrationLinter:
return errors, ignored, warnings
@staticmethod
def discover_function(function):
if isinstance(function, functools.partial):
return function.func
return function
def lint_runpython(
self, runpython: RunPython
) -> tuple[list[Issue], list[Issue], list[Issue]]:
function_name = runpython.code.__name__
function_name = self.discover_function(runpython.code).__name__
error = []
ignored = []
warning = []
@@ -551,8 +558,9 @@ class MigrationLinter:
def get_runpython_model_import_issues(code: Callable) -> list[Issue]:
model_object_regex = re.compile(r"[^a-zA-Z0-9._]?([a-zA-Z0-9._]+?)\.objects")
function_name = code.__name__
source_code = inspect.getsource(code)
function = MigrationLinter.discover_function(code)
function_name = function.__name__
source_code = inspect.getsource(function)
called_models = model_object_regex.findall(source_code)
issues = []
@@ -582,8 +590,9 @@ class MigrationLinter:
def get_runpython_model_variable_naming_issues(code: Callable) -> list[Issue]:
model_object_regex = re.compile(r"[^a-zA-Z]?([a-zA-Z0-9]+?)\.objects")
function_name = code.__name__
source_code = inspect.getsource(code)
function = MigrationLinter.discover_function(code)
function_name = function.__name__
source_code = inspect.getsource(function)
called_models = model_object_regex.findall(source_code)
issues = []
+9
View File
@@ -104,6 +104,15 @@ class DataMigrationDetectionTestCase(unittest.TestCase):
self.assertEqual(0, self.linter.nb_erroneous)
self.assertFalse(self.linter.has_errors)
def test_partial_function(self):
reverse_migration = self.linter.migration_loader.disk_migrations[
("app_data_migrations", "0004_partial_function")
]
self.linter.lint_migration(reverse_migration)
self.assertEqual(1, self.linter.nb_warnings)
self.assertFalse(self.linter.has_errors)
class DataMigrationModelImportTestCase(unittest.TestCase):
def test_missing_get_model_import(self):
@@ -0,0 +1,26 @@
# Generated by Django 2.2 on 2020-01-27 17:47
from __future__ import annotations
import functools
from django.db import migrations
def backward_op(c, david, test):
pass
def forward_op(const, arg1, arg2):
pass
class Migration(migrations.Migration):
dependencies = [("app_data_migrations", "0003_incorrect_arguments")]
operations = [
migrations.RunPython(
functools.partial(forward_op, "constant"),
functools.partial(backward_op, "constant"),
)
]