Add pyproject.toml for consolidated project configuration and replace Black, isort, and Flake8 with Ruff

- Introduced `pyproject.toml` to centralize backend tool configurations (e.g., Ruff, mypy, coverage, pytest).
- Replaced Black, isort, and Flake8 with Ruff for linting, formatting, and import sorting.
- Updated `requirements.txt` to include Ruff and remove replaced tools.
- Added `Makefile` to streamline development workflows with commands for linting, formatting, type-checking, testing, and cleanup.
This commit is contained in:
2025-11-10 11:55:15 +01:00
parent a5c671c133
commit c589b565f0
86 changed files with 4572 additions and 3956 deletions

View File

@@ -5,6 +5,7 @@ Covers Pydantic validators for:
- Slug validation (lines 26, 28, 30, 32, 62-70)
- Name validation (lines 40, 77)
"""
import pytest
from pydantic import ValidationError
@@ -20,19 +21,13 @@ class TestOrganizationBaseValidators:
def test_valid_organization_base(self):
"""Test that valid data passes validation."""
org = OrganizationBase(
name="Test Organization",
slug="test-org"
)
org = OrganizationBase(name="Test Organization", slug="test-org")
assert org.name == "Test Organization"
assert org.slug == "test-org"
def test_slug_none_returns_none(self):
"""Test that None slug is allowed (covers line 26)."""
org = OrganizationBase(
name="Test Organization",
slug=None
)
org = OrganizationBase(name="Test Organization", slug=None)
assert org.slug is None
def test_slug_invalid_characters_rejected(self):
@@ -40,57 +35,46 @@ class TestOrganizationBaseValidators:
with pytest.raises(ValidationError) as exc_info:
OrganizationBase(
name="Test Organization",
slug="Test_Org!" # Uppercase and special chars
slug="Test_Org!", # Uppercase and special chars
)
errors = exc_info.value.errors()
assert any("lowercase letters, numbers, and hyphens" in str(e['msg']) for e in errors)
assert any(
"lowercase letters, numbers, and hyphens" in str(e["msg"]) for e in errors
)
def test_slug_starts_with_hyphen_rejected(self):
"""Test slug starting with hyphen is rejected (covers line 30)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationBase(
name="Test Organization",
slug="-test-org"
)
OrganizationBase(name="Test Organization", slug="-test-org")
errors = exc_info.value.errors()
assert any("cannot start or end with a hyphen" in str(e['msg']) for e in errors)
assert any("cannot start or end with a hyphen" in str(e["msg"]) for e in errors)
def test_slug_ends_with_hyphen_rejected(self):
"""Test slug ending with hyphen is rejected (covers line 30)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationBase(
name="Test Organization",
slug="test-org-"
)
OrganizationBase(name="Test Organization", slug="test-org-")
errors = exc_info.value.errors()
assert any("cannot start or end with a hyphen" in str(e['msg']) for e in errors)
assert any("cannot start or end with a hyphen" in str(e["msg"]) for e in errors)
def test_slug_consecutive_hyphens_rejected(self):
"""Test slug with consecutive hyphens is rejected (covers line 32)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationBase(
name="Test Organization",
slug="test--org"
)
OrganizationBase(name="Test Organization", slug="test--org")
errors = exc_info.value.errors()
assert any("cannot contain consecutive hyphens" in str(e['msg']) for e in errors)
assert any(
"cannot contain consecutive hyphens" in str(e["msg"]) for e in errors
)
def test_name_whitespace_only_rejected(self):
"""Test whitespace-only name is rejected (covers line 40)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationBase(
name=" ",
slug="test-org"
)
OrganizationBase(name=" ", slug="test-org")
errors = exc_info.value.errors()
assert any("name cannot be empty" in str(e['msg']) for e in errors)
assert any("name cannot be empty" in str(e["msg"]) for e in errors)
def test_name_trimmed(self):
"""Test that name is trimmed."""
org = OrganizationBase(
name=" Test Organization ",
slug="test-org"
)
org = OrganizationBase(name=" Test Organization ", slug="test-org")
assert org.name == "Test Organization"
@@ -99,22 +83,18 @@ class TestOrganizationCreateValidators:
def test_valid_organization_create(self):
"""Test that valid data passes validation."""
org = OrganizationCreate(
name="Test Organization",
slug="test-org"
)
org = OrganizationCreate(name="Test Organization", slug="test-org")
assert org.name == "Test Organization"
assert org.slug == "test-org"
def test_slug_validation_inherited(self):
"""Test that slug validation is inherited from base."""
with pytest.raises(ValidationError) as exc_info:
OrganizationCreate(
name="Test",
slug="Invalid_Slug!"
)
OrganizationCreate(name="Test", slug="Invalid_Slug!")
errors = exc_info.value.errors()
assert any("lowercase letters, numbers, and hyphens" in str(e['msg']) for e in errors)
assert any(
"lowercase letters, numbers, and hyphens" in str(e["msg"]) for e in errors
)
class TestOrganizationUpdateValidators:
@@ -122,10 +102,7 @@ class TestOrganizationUpdateValidators:
def test_valid_organization_update(self):
"""Test that valid update data passes validation."""
org = OrganizationUpdate(
name="Updated Name",
slug="updated-slug"
)
org = OrganizationUpdate(name="Updated Name", slug="updated-slug")
assert org.name == "Updated Name"
assert org.slug == "updated-slug"
@@ -139,35 +116,39 @@ class TestOrganizationUpdateValidators:
with pytest.raises(ValidationError) as exc_info:
OrganizationUpdate(slug="Test_Org!")
errors = exc_info.value.errors()
assert any("lowercase letters, numbers, and hyphens" in str(e['msg']) for e in errors)
assert any(
"lowercase letters, numbers, and hyphens" in str(e["msg"]) for e in errors
)
def test_update_slug_starts_with_hyphen_rejected(self):
"""Test update slug starting with hyphen is rejected (covers line 66)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationUpdate(slug="-test-org")
errors = exc_info.value.errors()
assert any("cannot start or end with a hyphen" in str(e['msg']) for e in errors)
assert any("cannot start or end with a hyphen" in str(e["msg"]) for e in errors)
def test_update_slug_ends_with_hyphen_rejected(self):
"""Test update slug ending with hyphen is rejected (covers line 66)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationUpdate(slug="test-org-")
errors = exc_info.value.errors()
assert any("cannot start or end with a hyphen" in str(e['msg']) for e in errors)
assert any("cannot start or end with a hyphen" in str(e["msg"]) for e in errors)
def test_update_slug_consecutive_hyphens_rejected(self):
"""Test update slug with consecutive hyphens is rejected (covers line 68)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationUpdate(slug="test--org")
errors = exc_info.value.errors()
assert any("cannot contain consecutive hyphens" in str(e['msg']) for e in errors)
assert any(
"cannot contain consecutive hyphens" in str(e["msg"]) for e in errors
)
def test_update_name_whitespace_only_rejected(self):
"""Test whitespace-only name in update is rejected (covers line 77)."""
with pytest.raises(ValidationError) as exc_info:
OrganizationUpdate(name=" ")
errors = exc_info.value.errors()
assert any("name cannot be empty" in str(e['msg']) for e in errors)
assert any("name cannot be empty" in str(e["msg"]) for e in errors)
def test_update_name_none_allowed(self):
"""Test that None name is allowed in update."""