chore(): switched all fields in contract to snake_case and linting improvements

This commit is contained in:
ITQ
2026-02-12 22:17:55 +03:00
parent 102f425259
commit 362398d56b
32 changed files with 401 additions and 353 deletions
+4
View File
@@ -1,3 +1,5 @@
from typing import override
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
@@ -34,11 +36,13 @@ class ReviewSettingsAdmin(admin.ModelAdmin):
),
)
@override
def has_add_permission(self, request) -> bool:
if ReviewSettings.objects.exists():
return False
return super().has_add_permission(request)
@override
def has_delete_permission(self, request, obj=None) -> bool:
return False
@@ -0,0 +1,18 @@
# Generated by Django 5.2.11 on 2026-02-12 18:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('reviews', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='reviewsettings',
name='allow_any_approver',
field=models.BooleanField(default=False, help_text='When True, any user with the Approver role can approve experiments that have no explicit approver group. When False, experiments without an approver group cannot proceed to review.', verbose_name='allow any approver'),
),
]
+6 -2
View File
@@ -1,4 +1,4 @@
from typing import Any
from typing import Any, override
from django.conf import settings
from django.core.validators import MinValueValidator
@@ -40,12 +40,14 @@ class ReviewSettings(BaseModel):
verbose_name = _("review settings")
verbose_name_plural = _("review settings")
@override
def __str__(self) -> str:
return (
f"ReviewSettings(min_approvals={self.default_min_approvals}, "
f"allow_any_approver={self.allow_any_approver})"
)
@override
def save(self, *args, **kwargs) -> None:
existing: ReviewSettings | None = ReviewSettings.objects.first()
if existing and existing.pk != self.pk:
@@ -77,7 +79,8 @@ class ApproverGroup(BaseModel):
limit_choices_to={"role": "approver"},
verbose_name=_("approvers"),
help_text=_(
"Approver-role users who may approve this experimenter's experiments."
"Approver-role users who may approve this "
"experimenter's experiments."
),
)
min_approvals: models.PositiveIntegerField[Any, Any] = (
@@ -104,6 +107,7 @@ class ApproverGroup(BaseModel):
verbose_name = _("approver group")
verbose_name_plural = _("approver groups")
@override
def __str__(self) -> str:
return (
f"ApproverGroup(experimenter={self.experimenter.pk}, "
@@ -1,40 +1,34 @@
from apps.users.models import User, UserRole
from apps.users.tests._helpers import _make_user
from apps.users.tests.helpers import make_user
def _make_experimenter(suffix="") -> User:
return _make_user(
def make_experimenter(suffix="") -> User:
return make_user(
username=f"exp{suffix}",
email=f"exp{suffix}@lotty.local",
role=UserRole.EXPERIMENTER,
)
def _make_approver(suffix="") -> User:
return _make_user(
def make_approver(suffix="") -> User:
return make_user(
username=f"appr{suffix}",
email=f"appr{suffix}@lotty.local",
role=UserRole.APPROVER,
)
def _make_admin(suffix="") -> User:
return _make_user(
def make_admin(suffix="") -> User:
return make_user(
username=f"admin{suffix}",
email=f"admin{suffix}@lotty.local",
role=UserRole.ADMIN,
)
def _make_viewer(suffix="") -> User:
return _make_user(
def make_viewer(suffix="") -> User:
return make_user(
username=f"viewer{suffix}",
email=f"viewer{suffix}@lotty.local",
role=UserRole.VIEWER,
)
def _get(data, camel_key, snake_key):
if camel_key in data:
return data[camel_key]
return data[snake_key]
@@ -1,5 +1,5 @@
import uuid
from typing import Any
from typing import Any, override
from django.core.exceptions import ValidationError
from django.db.models import QuerySet
@@ -22,18 +22,19 @@ from apps.reviews.services import (
)
from apps.users.models import User
from ._helpers import (
_make_admin,
_make_approver,
_make_experimenter,
_make_viewer,
from .helpers import (
make_admin,
make_approver,
make_experimenter,
make_viewer,
)
class ApproverGroupModelTest(TestCase):
@override
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_model")
self.approver: User = _make_approver("_model")
self.experimenter: User = make_experimenter("_model")
self.approver: User = make_approver("_model")
def test_create_group(self) -> None:
group: ApproverGroup = approver_group_create(
@@ -63,7 +64,7 @@ class ApproverGroupModelTest(TestCase):
self.assertTrue(group.can_approve(self.approver))
def test_can_approve_false_not_in_group(self) -> None:
other_approver: User = _make_approver("_other")
other_approver: User = make_approver("_other")
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver.pk)],
@@ -80,10 +81,11 @@ class ApproverGroupModelTest(TestCase):
class ApproverGroupCreateServiceTest(TestCase):
@override
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_create")
self.approver1: User = _make_approver("_create1")
self.approver2: User = _make_approver("_create2")
self.experimenter: User = make_experimenter("_create")
self.approver1: User = make_approver("_create1")
self.approver2: User = make_approver("_create2")
def test_create_with_approvers(self) -> None:
group: ApproverGroup = approver_group_create(
@@ -109,17 +111,17 @@ class ApproverGroupCreateServiceTest(TestCase):
self.assertEqual(group.min_approvals, 1)
def test_create_rejects_non_experimenter_user(self) -> None:
admin: User = _make_admin("_cre_admin")
admin: User = make_admin("_cre_admin")
with self.assertRaises(ValidationError):
approver_group_create(experimenter=admin)
def test_create_rejects_viewer_as_experimenter(self) -> None:
viewer: User = _make_viewer("_cre_viewer")
viewer: User = make_viewer("_cre_viewer")
with self.assertRaises(ValidationError):
approver_group_create(experimenter=viewer)
def test_create_rejects_approver_as_experimenter(self) -> None:
approver: User = _make_approver("_cre_as_exp")
approver: User = make_approver("_cre_as_exp")
with self.assertRaises(ValidationError):
approver_group_create(experimenter=approver)
@@ -130,7 +132,7 @@ class ApproverGroupCreateServiceTest(TestCase):
approver_group_create(experimenter=self.experimenter)
def test_create_rejects_non_approver_in_approver_list(self) -> None:
viewer: User = _make_viewer("_cre_bad_appr")
viewer: User = make_viewer("_cre_bad_appr")
with self.assertRaises(ValidationError):
approver_group_create(
experimenter=self.experimenter,
@@ -166,11 +168,12 @@ class ApproverGroupCreateServiceTest(TestCase):
class ApproverGroupUpdateServiceTest(TestCase):
@override
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_upd")
self.approver1: User = _make_approver("_upd1")
self.approver2: User = _make_approver("_upd2")
self.approver3: User = _make_approver("_upd3")
self.experimenter: User = make_experimenter("_upd")
self.approver1: User = make_approver("_upd1")
self.approver2: User = make_approver("_upd2")
self.approver3: User = make_approver("_upd3")
self.group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver1.pk), str(self.approver2.pk)],
@@ -225,7 +228,7 @@ class ApproverGroupUpdateServiceTest(TestCase):
approver_group_update(group=self.group, min_approvals=10)
def test_update_rejects_non_approver_role(self) -> None:
viewer: User = _make_viewer("_upd_bad")
viewer: User = make_viewer("_upd_bad")
with self.assertRaises(ValidationError):
approver_group_update(
group=self.group,
@@ -242,14 +245,14 @@ class ApproverGroupUpdateServiceTest(TestCase):
class ApproverGroupDeleteServiceTest(TestCase):
def test_delete_removes_group(self) -> None:
exp: User = _make_experimenter("_del")
exp: User = make_experimenter("_del")
group: ApproverGroup = approver_group_create(experimenter=exp)
pk = group.pk
approver_group_delete(group=group)
self.assertFalse(ApproverGroup.objects.filter(pk=pk).exists())
def test_delete_allows_recreating_group(self) -> None:
exp: User = _make_experimenter("_del2")
exp: User = make_experimenter("_del2")
group: ApproverGroup = approver_group_create(experimenter=exp)
approver_group_delete(group=group)
new_group: ApproverGroup = approver_group_create(experimenter=exp)
@@ -257,10 +260,11 @@ class ApproverGroupDeleteServiceTest(TestCase):
class ApproverGroupAddRemoveServiceTest(TestCase):
@override
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_ar")
self.approver1: User = _make_approver("_ar1")
self.approver2: User = _make_approver("_ar2")
self.experimenter: User = make_experimenter("_ar")
self.approver1: User = make_approver("_ar1")
self.approver2: User = make_approver("_ar2")
self.group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver1.pk)],
@@ -275,7 +279,7 @@ class ApproverGroupAddRemoveServiceTest(TestCase):
)
def test_add_approver_rejects_non_approver_role(self) -> None:
viewer: User = _make_viewer("_ar_bad")
viewer: User = make_viewer("_ar_bad")
with self.assertRaises(ValidationError):
approver_group_add_approver(group=self.group, approver=viewer)
@@ -309,11 +313,12 @@ class ApproverGroupAddRemoveServiceTest(TestCase):
class ApproverGroupSelectorsTest(TestCase):
@override
def setUp(self) -> None:
self.exp1: User = _make_experimenter("_sel1")
self.exp2: User = _make_experimenter("_sel2")
self.appr1: User = _make_approver("_sel1")
self.appr2: User = _make_approver("_sel2")
self.exp1: User = make_experimenter("_sel1")
self.exp2: User = make_experimenter("_sel2")
self.appr1: User = make_approver("_sel1")
self.appr2: User = make_approver("_sel2")
self.group1: ApproverGroup = approver_group_create(
experimenter=self.exp1,
approver_ids=[str(self.appr1.pk)],
@@ -344,7 +349,7 @@ class ApproverGroupSelectorsTest(TestCase):
self.assertEqual(found, self.group1)
def test_get_by_experimenter_no_group(self) -> None:
exp3: User = _make_experimenter("_sel3")
exp3: User = make_experimenter("_sel3")
self.assertIsNone(approver_group_get_by_experimenter(exp3))
def test_get_by_experimenter_id(self) -> None:
@@ -1,3 +1,5 @@
from typing import override
from django.test import TestCase
from apps.reviews.models import ApproverGroup
@@ -9,15 +11,16 @@ from apps.reviews.selectors import (
from apps.reviews.services import approver_group_create, review_settings_update
from apps.users.models import User
from ._helpers import _make_admin, _make_approver, _make_experimenter
from .helpers import make_admin, make_approver, make_experimenter
class EffectiveReviewPolicyTest(TestCase):
@override
def setUp(self) -> None:
self.exp_with_group: User = _make_experimenter("_eff1")
self.exp_without_group: User = _make_experimenter("_eff2")
self.appr1: User = _make_approver("_eff1")
self.appr2: User = _make_approver("_eff2")
self.exp_with_group: User = make_experimenter("_eff1")
self.exp_without_group: User = make_experimenter("_eff2")
self.appr1: User = make_approver("_eff1")
self.appr2: User = make_approver("_eff2")
self.group: ApproverGroup = approver_group_create(
experimenter=self.exp_with_group,
approver_ids=[str(self.appr1.pk)],
@@ -63,10 +66,11 @@ class EffectiveReviewPolicyTest(TestCase):
class CanUserApproveTest(TestCase):
@override
def setUp(self) -> None:
self.exp: User = _make_experimenter("_can")
self.appr_in: User = _make_approver("_can_in")
self.appr_out: User = _make_approver("_can_out")
self.exp: User = make_experimenter("_can")
self.appr_in: User = make_approver("_can_in")
self.appr_out: User = make_approver("_can_out")
self.group: ApproverGroup = approver_group_create(
experimenter=self.exp,
approver_ids=[str(self.appr_in.pk)],
@@ -81,7 +85,7 @@ class CanUserApproveTest(TestCase):
)
def test_non_approver_role_cannot_approve(self) -> None:
admin: User = _make_admin("_can_a")
admin: User = make_admin("_can_a")
self.assertFalse(can_user_approve_experimenter(admin, self.exp))
def test_inactive_approver_cannot_approve(self) -> None:
@@ -90,11 +94,11 @@ class CanUserApproveTest(TestCase):
self.assertFalse(can_user_approve_experimenter(self.appr_in, self.exp))
def test_fallback_any_approver_can_approve(self) -> None:
exp2: User = _make_experimenter("_can2")
exp2: User = make_experimenter("_can2")
review_settings_update(allow_any_approver=True)
self.assertTrue(can_user_approve_experimenter(self.appr_out, exp2))
def test_fallback_deny_blocks_approval(self) -> None:
exp2: User = _make_experimenter("_can3")
exp2: User = make_experimenter("_can3")
review_settings_update(allow_any_approver=False)
self.assertFalse(can_user_approve_experimenter(self.appr_out, exp2))
+2 -1
View File
@@ -1,7 +1,7 @@
import logging
from collections.abc import Callable
from functools import wraps
from typing import Any
from typing import Any, override
from django.http import HttpRequest
from ninja.security import HttpBearer
@@ -14,6 +14,7 @@ logger: logging.Logger = logging.getLogger("lotty")
class JWTBearer(HttpBearer):
@override
def authenticate(
self,
request: HttpRequest,
@@ -1,3 +1,5 @@
from typing import override
from django.core.management.base import BaseCommand, CommandParser
from apps.users.models import User, UserRole
@@ -59,6 +61,7 @@ class Command(BaseCommand):
"(admin, experimenter, approver, viewer)."
)
@override
def add_arguments(self, parser: CommandParser) -> None:
parser.add_argument(
"--password",
@@ -79,6 +82,7 @@ class Command(BaseCommand):
),
)
@override
def handle(self, *args, **options) -> None:
password: str = options["password"]
force: bool = options["force"]
@@ -0,0 +1,18 @@
# Generated by Django 5.2.11 on 2026-02-12 18:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='user',
name='role',
field=models.CharField(choices=[('admin', 'Admin'), ('experimenter', 'Experimenter'), ('approver', 'Approver'), ('viewer', 'Viewer')], db_index=True, default='viewer', help_text='Platform role that defines user permissions', max_length=20, verbose_name='role'),
),
]
@@ -3,7 +3,7 @@ from apps.users.models import User, UserRole
from apps.users.services import user_create
def _make_user(
def make_user(
username="testuser",
email="test@lotty.local",
password="testpass123", # noqa: S107
@@ -19,6 +19,6 @@ def _make_user(
)
def _auth_header(user) -> str:
def auth_header(user) -> str:
token: str = create_access_token(user.pk, user.role)
return f"Bearer {token}"
+5 -3
View File
@@ -1,6 +1,6 @@
import uuid
from datetime import timedelta
from typing import Any
from typing import Any, override
from django.core.handlers.wsgi import WSGIRequest
from django.test import RequestFactory, TestCase
@@ -17,7 +17,7 @@ from apps.users.auth.jwt import (
)
from apps.users.models import User, UserRole
from ._helpers import _make_user
from .helpers import make_user
class JWTCreateTest(TestCase):
@@ -37,6 +37,7 @@ class JWTCreateTest(TestCase):
class JWTDecodeTest(TestCase):
@override
def setUp(self) -> None:
self.uid: uuid.UUID = uuid.uuid4()
@@ -78,9 +79,10 @@ class JWTDecodeTest(TestCase):
class JWTBearerTest(TestCase):
@override
def setUp(self) -> None:
self.bearer = JWTBearer()
self.user: User = _make_user(
self.user: User = make_user(
username="bearer_user",
email="bearer@x.com",
role=UserRole.ADMIN,
+8 -8
View File
@@ -4,7 +4,7 @@ from django.test import TestCase
from apps.users.models import User, UserRole
from ._helpers import _make_user
from .helpers import make_user
class UserRoleChoicesTest(TestCase):
@@ -20,11 +20,11 @@ class UserRoleChoicesTest(TestCase):
class UserModelTest(TestCase):
def test_default_role_is_viewer(self) -> None:
user: User = _make_user()
user: User = make_user()
self.assertEqual(user.role, UserRole.VIEWER)
def test_role_properties(self) -> None:
admin: User = _make_user(
admin: User = make_user(
username="a", email="a@x.com", role=UserRole.ADMIN
)
self.assertTrue(admin.is_admin_role)
@@ -32,25 +32,25 @@ class UserModelTest(TestCase):
self.assertFalse(admin.is_approver)
self.assertFalse(admin.is_viewer)
exp: User = _make_user(
exp: User = make_user(
username="e", email="e@x.com", role=UserRole.EXPERIMENTER
)
self.assertTrue(exp.is_experimenter)
appr: User = _make_user(
appr: User = make_user(
username="ap", email="ap@x.com", role=UserRole.APPROVER
)
self.assertTrue(appr.is_approver)
viewer: User = _make_user(
viewer: User = make_user(
username="v", email="v@x.com", role=UserRole.VIEWER
)
self.assertTrue(viewer.is_viewer)
def test_uuid_primary_key(self) -> None:
user: User = _make_user()
user: User = make_user()
self.assertIsInstance(user.pk, uuid.UUID)
def test_str_representation(self) -> None:
user: User = _make_user(username="hello")
user: User = make_user(username="hello")
self.assertEqual(str(user), "hello")
@@ -1,3 +1,5 @@
from typing import override
from django.core.handlers.wsgi import WSGIRequest
from django.test import RequestFactory, TestCase
@@ -5,15 +7,16 @@ from apps.users.auth.bearer import require_admin, require_roles
from apps.users.models import User, UserRole
from config.errors import ForbiddenError
from ._helpers import _make_user
from .helpers import make_user
class RequireRolesTest(TestCase):
@override
def setUp(self) -> None:
self.admin: User = _make_user(
self.admin: User = make_user(
username="rr_admin", email="rr_admin@x.com", role=UserRole.ADMIN
)
self.viewer: User = _make_user(
self.viewer: User = make_user(
username="rr_viewer", email="rr_viewer@x.com", role=UserRole.VIEWER
)
@@ -1,4 +1,5 @@
import uuid
from typing import override
from django.db.models import QuerySet
from django.test import TestCase
@@ -18,27 +19,28 @@ from apps.users.selectors import (
user_list_viewers,
)
from ._helpers import _make_user
from .helpers import make_user
class UserSelectorsTest(TestCase):
@override
def setUp(self) -> None:
self.admin: User = _make_user(
self.admin: User = make_user(
username="sel_admin",
email="sel_admin@x.com",
role=UserRole.ADMIN,
)
self.exp: User = _make_user(
self.exp: User = make_user(
username="sel_exp",
email="sel_exp@x.com",
role=UserRole.EXPERIMENTER,
)
self.appr: User = _make_user(
self.appr: User = make_user(
username="sel_appr",
email="sel_appr@x.com",
role=UserRole.APPROVER,
)
self.viewer: User = _make_user(
self.viewer: User = make_user(
username="sel_viewer",
email="sel_viewer@x.com",
role=UserRole.VIEWER,
+10 -5
View File
@@ -1,3 +1,5 @@
from typing import override
from django.core.exceptions import ValidationError
from django.test import TestCase
@@ -11,7 +13,7 @@ from apps.users.services import (
user_update,
)
from ._helpers import _make_user
from .helpers import make_user
class UserCreateServiceTest(TestCase):
@@ -54,8 +56,9 @@ class UserCreateServiceTest(TestCase):
class UserUpdateServiceTest(TestCase):
@override
def setUp(self) -> None:
self.user: User = _make_user()
self.user: User = make_user()
def test_update_username(self) -> None:
updated: User = user_update(user=self.user, username="newname")
@@ -91,8 +94,9 @@ class UserUpdateServiceTest(TestCase):
class UserAssignRoleServiceTest(TestCase):
@override
def setUp(self) -> None:
self.user: User = _make_user()
self.user: User = make_user()
def test_assign_valid_role(self) -> None:
updated: User = user_assign_role(
@@ -107,15 +111,16 @@ class UserAssignRoleServiceTest(TestCase):
class UserDeleteServiceTest(TestCase):
def test_hard_delete(self) -> None:
user: User = _make_user()
user: User = make_user()
pk = user.pk
user_delete(user=user)
self.assertFalse(User.objects.filter(pk=pk).exists())
class UserActivateDeactivateServiceTest(TestCase):
@override
def setUp(self) -> None:
self.user: User = _make_user()
self.user: User = make_user()
def test_deactivate(self) -> None:
updated: User = user_deactivate(user=self.user)