Skip to content

Commit

Permalink
Refs kiwitcms/Kiwi#1774 New linter: warn about missing backwards migr…
Browse files Browse the repository at this point in the history
…ations
  • Loading branch information
brymut committed Jul 8, 2020
1 parent 4d606f6 commit fd814a5
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 11 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@
* [psrb](https://github.com/psrb)
* [WayneLambert](https://github.com/WayneLambert)
* [alejandro-angulo](https://github.com/alejandro-angulo)
* [brymut](https://github.com/brymut)

2 changes: 2 additions & 0 deletions pylint_django/checkers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pylint_django.checkers.models import ModelChecker
from pylint_django.checkers.json_response import JsonResponseChecker
from pylint_django.checkers.forms import FormChecker
from pylint_django.checkers.migrations import MissingBackwardsMigrationChecker


def register_checkers(linter):
Expand All @@ -11,3 +12,4 @@ def register_checkers(linter):
linter.register_checker(DjangoInstalledChecker(linter))
linter.register_checker(JsonResponseChecker(linter))
linter.register_checker(FormChecker(linter))
linter.register_checker(MissingBackwardsMigrationChecker(linter))
13 changes: 3 additions & 10 deletions pylint_django/checkers/db_performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from pylint.checkers import utils
from pylint_django.__pkginfo__ import BASE_ID
from pylint_django import compat

from pylint_django.utils import is_migrations_module

def _is_addfield_with_default(call):
if not isinstance(call.func, astroid.Attribute):
Expand All @@ -37,13 +37,6 @@ def _is_addfield_with_default(call):
return False


def _is_migrations_module(node):
if not isinstance(node, astroid.Module):
return False

return 'migrations' in node.path[0] and not node.path[0].endswith('__init__.py')


class NewDbFieldWithDefaultChecker(checkers.BaseChecker):
"""
Looks for migrations which add new model fields and these fields have a
Expand All @@ -69,7 +62,7 @@ class NewDbFieldWithDefaultChecker(checkers.BaseChecker):
_possible_offences = {}

def visit_module(self, node):
if _is_migrations_module(node):
if is_migrations_module(node):
self._migration_modules.append(node)

def visit_call(self, node):
Expand All @@ -78,7 +71,7 @@ def visit_call(self, node):
except: # noqa: E722, pylint: disable=bare-except
return

if not _is_migrations_module(module):
if not is_migrations_module(module):
return

if _is_addfield_with_default(node):
Expand Down
35 changes: 35 additions & 0 deletions pylint_django/checkers/migrations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from pylint import interfaces
from pylint.checkers import utils, BaseChecker
from pylint_django.__pkginfo__ import BASE_ID
from pylint_django.utils import is_migrations_module


class MissingBackwardsMigrationChecker(BaseChecker):
__implements__ = (interfaces.IAstroidChecker,)

name = 'missing-backwards-migration-checker'

msgs = {'W%s05' % BASE_ID: ('Always include backwards migration callable',
'missing-backwards-migration-callable',
'Always include a backwards/reverse callable counterpart'
' so that the migration is not irreversable.')}

def visit_call(self, node):
try:
module = node.frame().parent
except: # noqa: E722, pylint: disable=bare-except
return

if not is_migrations_module(module):
return

if node.func.as_string().endswith('RunPython') and len(node.args) < 2:
if node.keywords:
for keyword in node.keywords:
if keyword.arg == 'reverse_code':
return
self.add_message('missing-backwards-migration-callable',
node=node)
else:
self.add_message('missing-backwards-migration-callable',
node=node)
13 changes: 13 additions & 0 deletions pylint_django/tests/input/migrations/0003_without_backwards.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# pylint: disable=missing-docstring
from django.db import migrations


def forwards_test(apps, schema_editor):
pass


class Migration(migrations.Migration):

operations = [
migrations.RunPython(forwards_test)
]
17 changes: 17 additions & 0 deletions pylint_django/tests/input/migrations/0004_with_backwards.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# pylint: disable=missing-docstring
from django.db import migrations


def forwards_test(apps, schema_editor):
pass


def backwards_test(apps, schema_editor):
pass


class Migration(migrations.Migration):

operations = [
migrations.RunPython(forwards_test, backwards_test)
]
8 changes: 7 additions & 1 deletion pylint_django/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Utils."""
import sys
import sys, astroid

from astroid.bases import Instance
from astroid.exceptions import InferenceError
Expand Down Expand Up @@ -30,3 +30,9 @@ def node_is_subclass(cls, *subclass_names):
continue

return False

def is_migrations_module(node):
if not isinstance(node, astroid.Module):
return False

return 'migrations' in node.path[0] and not node.path[0].endswith('__init__.py')

0 comments on commit fd814a5

Please sign in to comment.