Resolve linter contradictions: consolidate config, fix isort first-party, pylint 10/10

Agent-Logs-Url: https://github.com/christianlouis/dmarq/sessions/1e4a1f06-55b9-4040-853e-6aaf9ee574c8

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-29 11:31:15 +00:00
parent f2a015971d
commit 01d0331136
22 changed files with 88 additions and 88 deletions
+21
View File
@@ -0,0 +1,21 @@
[flake8]
# Keep in sync with black's line-length in pyproject.toml [tool.black]
max-line-length = 100
max-complexity = 10
exclude =
.git,
__pycache__,
.venv,
venv,
build,
dist,
*.egg-info,
migrations
# Ignored rules must not conflict with black:
# E203 whitespace before ':' (black formats slices this way)
# W503 line break before binary operator (black prefers this style)
# E501 line too long (black already enforces max-line-length; avoid double-reporting)
extend-ignore = E203, W503, E501
per-file-ignores =
# Allow unused imports in __init__.py (re-exports)
__init__.py: F401
+2 -2
View File
@@ -80,11 +80,11 @@ jobs:
- name: Run Flake8
run: |
flake8 backend/app --max-line-length=100 --extend-ignore=E203,W503,E501
flake8 backend/app
- name: Run Pylint
run: |
pylint backend/app --max-line-length=100 --disable=C0111,R0903
pylint backend/app
continue-on-error: true
docker:
+2 -1
View File
@@ -1,6 +1,7 @@
from app.api.api_v1.endpoints import domains, health, imap, reports, setup, stats
from fastapi import APIRouter
from app.api.api_v1.endpoints import domains, health, imap, reports, setup, stats
api_router = APIRouter()
# Include all endpoint routers
+2 -1
View File
@@ -2,10 +2,11 @@ import random # Used for mock data generation - TODO: Replace with actual histo
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional
from app.services.report_store import ReportStore
from fastapi import APIRouter, HTTPException, Path, Query, status
from pydantic import BaseModel
from app.services.report_store import ReportStore
router = APIRouter()
+2 -1
View File
@@ -1,6 +1,7 @@
from app.api.api_v1.endpoints.setup import setup_status
from fastapi import APIRouter
from app.api.api_v1.endpoints.setup import setup_status
router = APIRouter()
+3 -2
View File
@@ -2,11 +2,12 @@ import logging
from datetime import datetime
from typing import Any, Dict, Optional
from app.core.security import require_admin_auth
from app.services.imap_client import IMAPClient
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException
from pydantic import BaseModel
from app.core.security import require_admin_auth
from app.services.imap_client import IMAPClient
router = APIRouter()
logger = logging.getLogger(__name__)
+3 -2
View File
@@ -1,11 +1,12 @@
import logging
from typing import List
from fastapi import APIRouter, File, HTTPException, UploadFile, status
from pydantic import BaseModel
from app.services.dmarc_parser import DMARCParser
from app.services.report_store import ReportStore
from app.utils.domain_validator import DomainValidationError, validate_domain
from fastapi import APIRouter, File, HTTPException, UploadFile, status
from pydantic import BaseModel
logger = logging.getLogger(__name__)
+3 -2
View File
@@ -1,9 +1,10 @@
from typing import Any, Dict
from fastapi import APIRouter, Depends, Path, Query
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.utils.stats_summarizer import StatsSummarizer
from fastapi import APIRouter, Depends, Path, Query
from sqlalchemy.orm import Session
router = APIRouter()
+2 -2
View File
@@ -74,9 +74,9 @@ class Settings(BaseSettings):
return v
@validator("BACKEND_CORS_ORIGINS", pre=True)
def assemble_cors_origins(
def assemble_cors_origins( # pylint: disable=no-self-argument
cls, v: Union[str, List[str]]
) -> List[str]: # pylint: disable=no-self-argument
) -> List[str]:
if isinstance(v, str) and not v.startswith("["):
return [i.strip() for i in v.split(",")]
if isinstance(v, (list, str)):
+2 -1
View File
@@ -1,10 +1,11 @@
from typing import Generator
from app.core.config import get_settings
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from app.core.config import get_settings
settings = get_settings()
# Configure SQLAlchemy
+2 -1
View File
@@ -4,12 +4,13 @@ import secrets
from datetime import datetime, timedelta
from typing import Any, Optional, Union
from app.core.config import get_settings
from fastapi import HTTPException, Security, status
from fastapi.security import APIKeyHeader, HTTPAuthorizationCredentials, HTTPBearer
from jose import JWTError, jwt
from passlib.context import CryptContext
from app.core.config import get_settings
settings = get_settings()
logger = logging.getLogger(__name__)
+6 -5
View File
@@ -3,17 +3,18 @@ import logging
import os
from datetime import datetime
from fastapi import Depends, FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from app.api.api_v1.api import api_router
from app.core.config import get_settings
from app.core.security import add_api_key, generate_api_key, require_admin_auth
from app.middleware.security import SecurityHeadersMiddleware
from app.services.imap_client import IMAPClient
from app.services.report_store import ReportStore
from fastapi import Depends, FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
# Set up logging
logger = logging.getLogger(__name__)
+2 -1
View File
@@ -1,9 +1,10 @@
from datetime import datetime
from app.core.database import Base
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Index, Integer, String, Text
from sqlalchemy.orm import relationship
from app.core.database import Base
class Domain(Base):
"""Domain model representing a monitored domain"""
+2 -1
View File
@@ -1,9 +1,10 @@
from datetime import datetime
from app.core.database import Base
from sqlalchemy import Column, DateTime, ForeignKey, Index, Integer, String, Text
from sqlalchemy.orm import relationship
from app.core.database import Base
class DMARCReport(Base):
"""DMARC Aggregate Report model"""
+2 -1
View File
@@ -1,7 +1,8 @@
from app.core.database import Base
from sqlalchemy import Boolean, Column, Integer, String
from sqlalchemy.orm import relationship
from app.core.database import Base
class User(Base):
"""User model"""
+7 -6
View File
@@ -1,16 +1,17 @@
# Import all models so Base.metadata knows every table
import app.models.domain # noqa: F401 # pylint: disable=unused-import
import app.models.report # noqa: F401 # pylint: disable=unused-import
import app.models.user # noqa: F401 # pylint: disable=unused-import
import pytest
from app.core.database import Base, get_db
from app.main import create_app
from app.services.report_store import ReportStore
from fastapi import FastAPI
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import app.models.domain # noqa: F401 # pylint: disable=unused-import
import app.models.report # noqa: F401 # pylint: disable=unused-import
import app.models.user # noqa: F401 # pylint: disable=unused-import
from app.core.database import Base, get_db
from app.main import create_app
from app.services.report_store import ReportStore
@pytest.fixture()
def test_app() -> FastAPI:
+1
View File
@@ -2,6 +2,7 @@ import io
import zipfile
import pytest
from app.services.dmarc_parser import DMARCParser
from app.tests.test_data import SAMPLE_XML
+2 -1
View File
@@ -1,6 +1,7 @@
from sqlalchemy.orm import Session
from app.models.domain import Domain
from app.models.report import DMARCReport, ReportRecord
from sqlalchemy.orm import Session
class TestDomainModel:
+2 -1
View File
@@ -1,9 +1,10 @@
import io
import zipfile
from app.tests.test_data import SAMPLE_XML
from fastapi.testclient import TestClient
from app.tests.test_data import SAMPLE_XML
def _make_zip(xml_content: str) -> bytes:
"""Create a ZIP file containing the given XML content."""
+2 -1
View File
@@ -4,8 +4,9 @@ Security-focused tests for DMARQ application.
Covers API key management, domain validation, file upload limits, and XML parsing security.
"""
import app.services.dmarc_parser as parser_module
import pytest
import app.services.dmarc_parser as parser_module
from app.core.security import add_api_key, generate_api_key, verify_api_key
from app.services.dmarc_parser import DMARCParser
from app.utils.domain_validator import validate_domain, validate_domain_config
+18
View File
@@ -49,6 +49,24 @@ include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
known_first_party = ["app"]
skip = ["venv", ".venv", "migrations"]
[tool.pylint.main]
# Run from repo root: pylint backend/app
max-line-length = 100
[tool.pylint."messages control"]
disable = [
"C0111", # missing-docstring
"C0103", # invalid-name (e.g. SessionLocal, TestingSessionLocal)
"R0903", # too-few-public-methods
"R0913", # too-many-arguments
"W0212", # protected-access
]
[tool.pylint.basic]
good-names = ["i", "j", "k", "ex", "_", "id", "db"]
[tool.pytest.ini_options]
testpaths = ["backend/app/tests"]
-56
View File
@@ -31,59 +31,3 @@ skip_covered = False
[coverage:html]
directory = htmlcov
[flake8]
max-line-length = 100
exclude =
.git,
__pycache__,
.venv,
venv,
build,
dist,
*.egg-info,
migrations
extend-ignore = E203, W503, E501
per-file-ignores =
__init__.py:F401
max-complexity = 10
[mypy]
python_version = 3.10
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = False
disallow_incomplete_defs = False
check_untyped_defs = True
disallow_untyped_calls = False
disallow_any_generics = False
ignore_missing_imports = True
no_implicit_optional = True
warn_redundant_casts = True
warn_unused_ignores = True
warn_no_return = True
strict_optional = True
[isort]
profile = black
line_length = 100
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
skip = venv,.venv,migrations
[pylint]
max-line-length = 100
disable =
C0111, # missing-docstring
C0103, # invalid-name
R0903, # too-few-public-methods
R0913, # too-many-arguments
W0212, # protected-access
good-names = i,j,k,ex,_,id,db
[bandit]
exclude_dirs = /tests/,/venv/,.venv/
skips = B101,B601