fix: resolve CI failures — SQLite incompatibility and ruff lint errors #3
@@ -34,4 +34,4 @@ def upgrade() -> None:
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_constraint("uq_users_email_inbound_token", "users", type_="unique")
|
||||
op.drop_column("users", "email_inbound_token")
|
||||
op.drop_column("users", "email_inbound_token")
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from pydantic import model_validator
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
_PLACEHOLDER_VALUES = {"change-me-in-production"}
|
||||
|
||||
|
||||
@@ -40,7 +39,8 @@ class ReceiptWitnessSettings(BaseSettings):
|
||||
if not self.session_encryption_key or self.session_encryption_key in _PLACEHOLDER_VALUES:
|
||||
errors.append(
|
||||
"RW_SESSION_ENCRYPTION_KEY must be set to a secure value. "
|
||||
'Generate one with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"'
|
||||
"Generate one with: python -c \"from cryptography.fernet import Fernet; "
|
||||
'print(Fernet.generate_key().decode())"'
|
||||
)
|
||||
if self.notifications_enabled and not self.resend_api_key:
|
||||
errors.append(
|
||||
|
||||
@@ -7,12 +7,12 @@ from datetime import UTC, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
import redis.asyncio as aioredis
|
||||
from receiptwitness.shared.database import get_async_session_factory
|
||||
from receiptwitness.shared.models import User
|
||||
from sqlalchemy import select
|
||||
|
||||
from receiptwitness.config import settings
|
||||
from receiptwitness.notifications.email import send_receipt_notification
|
||||
from receiptwitness.shared.database import get_async_session_factory
|
||||
from receiptwitness.shared.models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -7,9 +7,6 @@ and batch matching for purchase ingestion.
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
|
||||
from receiptwitness.shared.constants import MatchConfidence
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
from receiptwitness.shared.schemas import PurchaseItemCreate
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from receiptwitness.pipeline.normalization import (
|
||||
@@ -18,6 +15,9 @@ from receiptwitness.pipeline.normalization import (
|
||||
extract_size_info,
|
||||
normalize_product,
|
||||
)
|
||||
from receiptwitness.shared.constants import MatchConfidence
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
from receiptwitness.shared.schemas import PurchaseItemCreate
|
||||
|
||||
# Re-export for convenience
|
||||
ConfidenceLevel = MatchConfidence
|
||||
|
||||
@@ -10,11 +10,12 @@ import re
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
from sqlalchemy import cast, func, select, String
|
||||
from sqlalchemy import String, cast, func, select
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
|
||||
|
||||
class MatchMethod(StrEnum):
|
||||
"""How a product match was determined."""
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
from receiptwitness.shared.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
|
||||
from receiptwitness.shared.models.product import NormalizedProduct
|
||||
from receiptwitness.shared.models.user import User, UserStoreAccount
|
||||
from receiptwitness.shared.models.stub_purchase import Purchase, PurchaseItem
|
||||
|
||||
# Stub models — needed for relationship resolution but not directly used by receiptwitness.
|
||||
# Full definitions live in cartsnitch/common.
|
||||
from receiptwitness.shared.models.stub_store import Store, StoreLocation
|
||||
from receiptwitness.shared.models.stub_purchase import Purchase, PurchaseItem
|
||||
from receiptwitness.shared.models.user import User, UserStoreAccount
|
||||
|
||||
__all__ = [
|
||||
"Base",
|
||||
|
||||
@@ -8,12 +8,26 @@ UserStoreAccount. The canonical definitions live in cartsnitch/common.
|
||||
import uuid
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import JSON, Date, DateTime, ForeignKey, Index, Numeric, String, UniqueConstraint, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from sqlalchemy import (
|
||||
JSON,
|
||||
Date,
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
Index,
|
||||
Numeric,
|
||||
String,
|
||||
UniqueConstraint,
|
||||
func,
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from receiptwitness.shared.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from receiptwitness.shared.models.user import User
|
||||
|
||||
|
||||
class Purchase(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
"""Stub: a shopping trip/receipt. Full definition in cartsnitch/common."""
|
||||
@@ -37,6 +51,9 @@ class Purchase(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
# Relationships (stubs — canonical definitions in cartsnitch/common)
|
||||
user: Mapped["User"] = relationship(back_populates="purchases")
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_purchases_user_store", "user_id", "store_id"),
|
||||
UniqueConstraint("user_id", "store_id", "receipt_id", name="uq_purchase_receipt"),
|
||||
|
||||
@@ -6,6 +6,7 @@ UserStoreAccount. The canonical definitions live in cartsnitch/common.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Float, ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
@@ -13,6 +14,9 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from receiptwitness.shared.constants import StoreSlug
|
||||
from receiptwitness.shared.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from receiptwitness.shared.models.user import UserStoreAccount
|
||||
|
||||
|
||||
class Store(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
"""Stub: canonical retailer. Full definition in cartsnitch/common."""
|
||||
@@ -24,6 +28,9 @@ class Store(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
logo_url: Mapped[str | None] = mapped_column(String(500))
|
||||
website_url: Mapped[str | None] = mapped_column(String(500))
|
||||
|
||||
# Relationships (stubs — canonical definitions in cartsnitch/common)
|
||||
user_accounts: Mapped[list["UserStoreAccount"]] = relationship(back_populates="store")
|
||||
|
||||
|
||||
class StoreLocation(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
"""Stub: physical store location. Full definition in cartsnitch/common."""
|
||||
|
||||
@@ -5,7 +5,7 @@ import uuid
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, String, Text, UniqueConstraint, text
|
||||
from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, String, Text, UniqueConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from receiptwitness.shared.constants import AccountStatus
|
||||
@@ -27,9 +27,6 @@ class User(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
||||
nullable=False,
|
||||
unique=True,
|
||||
default=lambda: secrets.token_urlsafe(16),
|
||||
server_default=text(
|
||||
"replace(replace(trim(trailing '=' from encode(gen_random_bytes(16), 'base64')), '+', '-'), '/', '_')"
|
||||
),
|
||||
)
|
||||
hashed_password: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
display_name: Mapped[str | None] = mapped_column(String(100))
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from receiptwitness.shared.database import get_async_session_factory
|
||||
from receiptwitness.shared.models import User
|
||||
from sqlalchemy import select
|
||||
|
||||
from receiptwitness.config import settings
|
||||
@@ -15,6 +13,8 @@ from receiptwitness.parsers.email.kroger import KrogerEmailParser
|
||||
from receiptwitness.parsers.email.meijer import MeijerEmailParser
|
||||
from receiptwitness.parsers.email.target import TargetEmailParser
|
||||
from receiptwitness.queue.email import ack_email, consume_emails, get_redis
|
||||
from receiptwitness.shared.database import get_async_session_factory
|
||||
from receiptwitness.shared.models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import pytest
|
||||
|
||||
from receiptwitness.config import ReceiptWitnessSettings
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"""Shared test fixtures for pipeline tests."""
|
||||
|
||||
import pytest
|
||||
from receiptwitness.shared.models import Base
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from receiptwitness.shared.models import Base
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def engine():
|
||||
|
||||
@@ -4,16 +4,15 @@ import uuid
|
||||
from datetime import UTC, datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from receiptwitness.shared.constants import MatchConfidence
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
from receiptwitness.shared.schemas import PurchaseItemCreate
|
||||
|
||||
from receiptwitness.pipeline.matching import (
|
||||
ProductMatcher,
|
||||
classify_confidence,
|
||||
match_purchase_item,
|
||||
)
|
||||
from receiptwitness.pipeline.normalization import MatchMethod
|
||||
from receiptwitness.shared.constants import MatchConfidence
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
from receiptwitness.shared.schemas import PurchaseItemCreate
|
||||
|
||||
|
||||
class TestClassifyConfidence:
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
import uuid
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
|
||||
from receiptwitness.pipeline.normalization import (
|
||||
MatchMethod,
|
||||
clean_name,
|
||||
@@ -14,6 +12,7 @@ from receiptwitness.pipeline.normalization import (
|
||||
match_by_upc,
|
||||
normalize_product,
|
||||
)
|
||||
from receiptwitness.shared.models import NormalizedProduct
|
||||
|
||||
|
||||
class TestCleanName:
|
||||
|
||||
Reference in New Issue
Block a user