Skip to content

Commit

Permalink
run linter against all files
Browse files Browse the repository at this point in the history
  • Loading branch information
BezBartek committed May 8, 2024
1 parent a3469bb commit a49fea1
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 82 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
branches:
- master

env:
PY_COLORS: 1

jobs:
linters:
runs-on: ubuntu-latest
Expand Down
15 changes: 10 additions & 5 deletions django_db_views/db_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@
class DBViewModelBase(ModelBase):
def __new__(cls, *args, **kwargs):
new_class = super().__new__(cls, *args, **kwargs)
assert new_class._meta.managed is False, "For DB View managed must be se to false"
assert (
new_class._meta.managed is False
), "For DB View managed must be se to false"
DBViewsRegistry[new_class._meta.db_table] = new_class
return new_class


class DBView(models.Model, metaclass=DBViewModelBase):
"""
Children should define:
view_definition - define the view, can be callable or attribute (string)
view definition can be per db engine.
Children should define:
view_definition - define the view, can be callable or attribute (string)
view definition can be per db engine.
"""

view_definition: Union[Callable, str, dict]

class Meta:
Expand All @@ -40,6 +43,8 @@ def refresh(cls, using=None, concurrently=False):
using = using or DEFAULT_DB_ALIAS
with connections[using].cursor() as cursor:
if concurrently:
cursor.execute("REFRESH MATERIALIZED VIEW CONCURRENTLY %s;" % cls._meta.db_table)
cursor.execute(
"REFRESH MATERIALIZED VIEW CONCURRENTLY %s;" % cls._meta.db_table
)
else:
cursor.execute("REFRESH MATERIALIZED VIEW %s;" % cls._meta.db_table)
30 changes: 24 additions & 6 deletions django_db_views/migration_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,33 @@ def __init__(self, view_definition: str, table_name: str, engine=None):
class ForwardViewMigrationBase(ViewMigration):
def __call__(self, apps, schema_editor):
if self.view_definition:
if self.view_engine is None or self.view_engine == schema_editor.connection.settings_dict['ENGINE']:
if (
self.view_engine is None
or self.view_engine == schema_editor.connection.settings_dict["ENGINE"]
):
schema_editor.execute(self.DROP_COMMAND_TEMPLATE % self.table_name)
schema_editor.execute(self.CREATE_COMMAND_TEMPLATE % (self.table_name, self.view_definition))
schema_editor.execute(
self.CREATE_COMMAND_TEMPLATE
% (self.table_name, self.view_definition)
)


class BackwardViewMigrationBase(ViewMigration):
def __call__(self, apps, schema_editor):
if self.view_engine is None or self.view_engine == schema_editor.connection.settings_dict['ENGINE']:
if (
self.view_engine is None
or self.view_engine == schema_editor.connection.settings_dict["ENGINE"]
):
schema_editor.execute(self.DROP_COMMAND_TEMPLATE % self.table_name)
if self.view_definition:
if self.view_engine is None or self.view_engine == schema_editor.connection.settings_dict['ENGINE']:
schema_editor.execute(self.CREATE_COMMAND_TEMPLATE % (self.table_name, self.view_definition))
if (
self.view_engine is None
or self.view_engine == schema_editor.connection.settings_dict["ENGINE"]
):
schema_editor.execute(
self.CREATE_COMMAND_TEMPLATE
% (self.table_name, self.view_definition)
)


@deconstructible
Expand Down Expand Up @@ -62,7 +77,10 @@ def __init__(self, table_name: str, engine=None):
self.view_engine = engine

def __call__(self, apps, schema_editor):
if self.view_engine is None or self.view_engine == schema_editor.connection.settings_dict['ENGINE']:
if (
self.view_engine is None
or self.view_engine == schema_editor.connection.settings_dict["ENGINE"]
):
schema_editor.execute(self.DROP_COMMAND_TEMPLATE % self.table_name)


Expand Down
33 changes: 20 additions & 13 deletions django_db_views/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

from django_db_views.context_manager import VIEW_MIGRATION_CONTEXT
from django_db_views.db_view import DBView, DBMaterializedView
from django_db_views.migration_functions import ForwardMaterializedViewMigration, ForwardViewMigration
from django_db_views.migration_functions import (
ForwardMaterializedViewMigration,
ForwardViewMigration,
)


def get_table_engine_name_hash(table_name, engine):
Expand All @@ -12,13 +15,14 @@ def get_table_engine_name_hash(table_name, engine):

class DBViewModelState(ModelState):
def __init__(
self, *args,
# Not required cus migrate also load state using clone method that do not provide required by us fields.
view_engine: str = None,
view_definition: str = None,
table_name: str = None,
base_class=None,
**kwargs
self,
*args,
# Not required cus migrate also load state using clone method that do not provide required by us fields.
view_engine: str = None,
view_definition: str = None,
table_name: str = None,
base_class=None,
**kwargs,
):
super().__init__(*args, **kwargs)
if VIEW_MIGRATION_CONTEXT["is_view_migration"]:
Expand All @@ -29,7 +33,6 @@ def __init__(


class ViewRunPython(operations.RunPython):

def state_forwards(self, app_label, state):
if VIEW_MIGRATION_CONTEXT["is_view_migration"]:
if isinstance(self.code, ForwardMaterializedViewMigration):
Expand All @@ -42,7 +45,9 @@ def state_forwards(self, app_label, state):
DBViewModelState(
app_label,
# Hash table_name_engine_name to add state model per migration, which are added per engine.
get_table_engine_name_hash(self.code.table_name, self.code.view_engine),
get_table_engine_name_hash(
self.code.table_name, self.code.view_engine
),
list(),
dict(),
# we do not use django bases (they initialize model using that, and broke ViewRegistry),
Expand All @@ -52,13 +57,15 @@ def state_forwards(self, app_label, state):
view_engine=self.code.view_engine,
view_definition=self.code.view_definition,
base_class=model,
table_name=self.code.table_name
table_name=self.code.table_name,
)
)


class ViewDropRunPython(operations.RunPython):

def state_forwards(self, app_label, state):
if VIEW_MIGRATION_CONTEXT["is_view_migration"]:
state.remove_model(app_label, get_table_engine_name_hash(self.code.table_name, self.code.view_engine))
state.remove_model(
app_label,
get_table_engine_name_hash(self.code.table_name, self.code.view_engine),
)
8 changes: 5 additions & 3 deletions tests/asserts_utils.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from django.db import connections


def is_table_exists(table_name: str, using: str = 'default') -> bool:
def is_table_exists(table_name: str, using: str = "default") -> bool:
with connections[using].cursor() as cursor:
return table_name in connections[using].introspection.table_names(cursor)


def is_view_exists(view_name: str, using: str = 'default') -> bool:
def is_view_exists(view_name: str, using: str = "default") -> bool:
with connections[using].cursor() as cursor:
views = [
table.name for table in connections[using].introspection.get_table_list(cursor) if table.type == 'v'
table.name
for table in connections[using].introspection.get_table_list(cursor)
if table.type == "v"
]
return view_name in views
8 changes: 7 additions & 1 deletion tests/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,11 @@ def decorated_test(*args, **kwargs):
try:
test_function(*args, **kwargs)
finally:
call_command("migrate", "test_app", "zero", database=kwargs.get("database", "default"))
call_command(
"migrate",
"test_app",
"zero",
database=kwargs.get("database", "default"),
)

return decorated_test
37 changes: 27 additions & 10 deletions tests/dynamic_models_fixtures.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import pytest
from django.db import models

from tests.test_app.models import QuestionTemplate, SimpleViewWithoutDependenciesTemplate, ChoiceTemplate, \
RawViewQuestionStatTemplate, QueryViewQuestionStatTemplate, MultipleDBRawViewTemplate, \
MultipleDBQueryViewQuestionStatTemplate, SimpleMaterializedViewWithoutDependenciesTemplate, \
SimpleMaterializedViewWithIndexTemplate, SecondSimpleViewWithoutDependenciesTemplate
from tests.test_app.models import (
QuestionTemplate,
SimpleViewWithoutDependenciesTemplate,
ChoiceTemplate,
RawViewQuestionStatTemplate,
QueryViewQuestionStatTemplate,
MultipleDBRawViewTemplate,
MultipleDBQueryViewQuestionStatTemplate,
SimpleMaterializedViewWithoutDependenciesTemplate,
SimpleMaterializedViewWithIndexTemplate,
SecondSimpleViewWithoutDependenciesTemplate,
)


def define_model(template_class, parent):
attributes = get_declared_class_attributes(template_class)
attrs = {
**attributes,
'__module__': 'tests.test_app.models'
}
attrs = {**attributes, "__module__": "tests.test_app.models"}
return type(template_class.__name__.replace("Template", ""), (parent,), attrs)


def get_declared_class_attributes(cls) -> dict:
return {key: value for key, value in cls.__dict__.items() if not key.startswith('__')}
return {
key: value for key, value in cls.__dict__.items() if not key.startswith("__")
}


@pytest.fixture
Expand All @@ -33,46 +40,56 @@ def Choice():
@pytest.fixture
def SimpleViewWithoutDependencies():
from django_db_views.db_view import DBView

return define_model(SimpleViewWithoutDependenciesTemplate, DBView)


@pytest.fixture
def SecondSimpleViewWithoutDependencies():
from django_db_views.db_view import DBView

return define_model(SecondSimpleViewWithoutDependenciesTemplate, DBView)


@pytest.fixture
def RawViewQuestionStat():
from django_db_views.db_view import DBView

return define_model(RawViewQuestionStatTemplate, DBView)


@pytest.fixture
def QueryViewQuestionStat():
from django_db_views.db_view import DBView

return define_model(QueryViewQuestionStatTemplate, DBView)


@pytest.fixture
def MultipleDBRawView():
from django_db_views.db_view import DBView

return define_model(MultipleDBRawViewTemplate, DBView)


@pytest.fixture
def MultipleDBQueryViewQuestionStat():
from django_db_views.db_view import DBView

return define_model(MultipleDBQueryViewQuestionStatTemplate, DBView)


@pytest.fixture
def SimpleMaterializedViewWithoutDependencies():
from django_db_views.db_view import DBMaterializedView
return define_model(SimpleMaterializedViewWithoutDependenciesTemplate, DBMaterializedView)

return define_model(
SimpleMaterializedViewWithoutDependenciesTemplate, DBMaterializedView
)


@pytest.fixture
def SimpleMaterializedViewWithIndex():
from django_db_views.db_view import DBMaterializedView

return define_model(SimpleMaterializedViewWithIndexTemplate, DBMaterializedView)
28 changes: 15 additions & 13 deletions tests/fixturies.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,39 @@
from django.apps import apps


@pytest.fixture(autouse=True, scope='function')
@pytest.fixture(autouse=True, scope="function")
def temp_migrations_dir(settings, tmpdir, mocker):
migrations_dir = tmpdir.mkdir("migrations")
init_file = (migrations_dir / "__init__.py")
init_file = migrations_dir / "__init__.py"
init_file.write_text("", encoding="utf-8")
mocker.patch("django.db.migrations.writer.MigrationWriter.basedir", migrations_dir.strpath)
mocker.patch(
"django.db.migrations.writer.MigrationWriter.basedir", migrations_dir.strpath
)

def new_module_import(module_name):
if module_name == 'tests.test_app.migrations':
if module_name == "tests.test_app.migrations":
spec = importlib.util.spec_from_file_location(module_name, init_file)
return importlib.util.module_from_spec(spec)
elif 'tests.test_app.migrations' in module_name:
spec = importlib.util.spec_from_file_location(module_name, migrations_dir / f"{module_name.split('.')[-1]}.py")
elif "tests.test_app.migrations" in module_name:
spec = importlib.util.spec_from_file_location(
module_name, migrations_dir / f"{module_name.split('.')[-1]}.py"
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
return importlib.import_module(module_name)
mocker.patch(
"django.db.migrations.loader.import_module",
new_module_import
)

mocker.patch("django.db.migrations.loader.import_module", new_module_import)
return migrations_dir


@pytest.fixture(autouse=True, scope='function')
@pytest.fixture(autouse=True, scope="function")
def dynamic_models_cleanup():
try:
yield None
finally:
# We delete all dynamically created models
test_app_models = list(apps.all_models['test_app'].keys())
test_app_models = list(apps.all_models["test_app"].keys())
for model_name in test_app_models:
del apps.all_models['test_app'][model_name]
del apps.all_models["test_app"][model_name]
apps.clear_cache()
Loading

0 comments on commit a49fea1

Please sign in to comment.