feat(validators): add noqa suppression support to security and performance validators
All checks were successful
All checks were successful
- Add centralized _is_noqa_suppressed() to BaseValidator with normalization (accepts both SEC001 and SEC-001 formats for ruff compatibility) - Wire noqa support into all 21 security and 18 performance check functions - Add ruff external config for SEC/PERF/MOD/EXC codes in pyproject.toml - Convert all 280 Python noqa comments to dashless format (ruff-compatible) - Add site/ to IGNORE_PATTERNS (excludes mkdocs build output) - Suppress 152 false positive findings (test passwords, seed data, validator self-references, Apple Wallet SHA1, etc.) - Security: 79 errors → 0, 60 warnings → 0 - Performance: 80 warnings → 77 (3 test script suppressions) - Add proposal doc with noqa inventory and remaining findings recommendations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ from app.exceptions.base import (
|
||||
)
|
||||
|
||||
|
||||
class ReportGenerationException(BusinessLogicException): # noqa: MOD-025
|
||||
class ReportGenerationException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when report generation fails."""
|
||||
|
||||
def __init__(self, report_type: str, reason: str):
|
||||
@@ -21,7 +21,7 @@ class ReportGenerationException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class InvalidDateRangeException(ValidationException): # noqa: MOD-025
|
||||
class InvalidDateRangeException(ValidationException): # noqa: MOD025
|
||||
"""Raised when an invalid date range is provided."""
|
||||
|
||||
def __init__(self, start_date: str, end_date: str):
|
||||
|
||||
@@ -90,7 +90,7 @@ class SubscriptionNotCancelledException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class SubscriptionAlreadyCancelledException(BusinessLogicException): # noqa: MOD-025
|
||||
class SubscriptionAlreadyCancelledException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to cancel an already cancelled subscription."""
|
||||
|
||||
def __init__(self):
|
||||
@@ -170,7 +170,7 @@ class StripePriceNotConfiguredException(BusinessLogicException):
|
||||
self.tier_code = tier_code
|
||||
|
||||
|
||||
class PaymentFailedException(BillingException): # noqa: MOD-025
|
||||
class PaymentFailedException(BillingException): # noqa: MOD025
|
||||
"""Raised when a payment fails."""
|
||||
|
||||
def __init__(self, message: str, stripe_error: str | None = None):
|
||||
|
||||
@@ -542,7 +542,7 @@ class BillingService:
|
||||
if stripe_service.is_configured and store_addon.stripe_subscription_item_id:
|
||||
try:
|
||||
stripe_service.cancel_subscription_item(store_addon.stripe_subscription_item_id)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.warning(f"Failed to cancel addon in Stripe: {e}")
|
||||
|
||||
# Mark as cancelled
|
||||
|
||||
@@ -488,7 +488,7 @@ class TestBillingServiceCheckout:
|
||||
|
||||
with pytest.raises(PaymentSystemNotConfiguredException):
|
||||
self.service.create_checkout_session(
|
||||
db, 1, 1, "essential", False, "http://ok", "http://cancel"
|
||||
db, 1, 1, "essential", False, "http://ok", "http://cancel" # noqa: SEC034
|
||||
)
|
||||
|
||||
def test_checkout_nonexistent_tier_raises(self, db):
|
||||
@@ -500,7 +500,7 @@ class TestBillingServiceCheckout:
|
||||
|
||||
with pytest.raises(TierNotFoundException):
|
||||
self.service.create_checkout_session(
|
||||
db, 1, 1, "nonexistent", False, "http://ok", "http://cancel"
|
||||
db, 1, 1, "nonexistent", False, "http://ok", "http://cancel" # noqa: SEC034
|
||||
)
|
||||
|
||||
|
||||
@@ -525,7 +525,7 @@ class TestBillingServicePortal:
|
||||
mock_stripe.is_configured = False
|
||||
|
||||
with pytest.raises(PaymentSystemNotConfiguredException):
|
||||
self.service.create_portal_session(db, 1, 1, "http://return")
|
||||
self.service.create_portal_session(db, 1, 1, "http://return") # noqa: SEC034
|
||||
|
||||
def test_portal_no_subscription_raises(self, db):
|
||||
"""Raises NoActiveSubscriptionException when no subscription found."""
|
||||
@@ -535,7 +535,7 @@ class TestBillingServicePortal:
|
||||
mock_stripe.is_configured = True
|
||||
|
||||
with pytest.raises(NoActiveSubscriptionException):
|
||||
self.service.create_portal_session(db, 99999, 99999, "http://return")
|
||||
self.service.create_portal_session(db, 99999, 99999, "http://return") # noqa: SEC034
|
||||
|
||||
def test_portal_no_customer_id_raises(self, db, bs_subscription):
|
||||
"""Raises when subscription has no stripe_customer_id."""
|
||||
@@ -549,7 +549,7 @@ class TestBillingServicePortal:
|
||||
db,
|
||||
bs_subscription.merchant_id,
|
||||
bs_subscription.platform_id,
|
||||
"http://return",
|
||||
"http://return", # noqa: SEC034
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class CartItemNotFoundException(ResourceNotFoundException):
|
||||
self.details.update({"product_id": product_id, "session_id": session_id})
|
||||
|
||||
|
||||
class EmptyCartException(ValidationException): # noqa: MOD-025
|
||||
class EmptyCartException(ValidationException): # noqa: MOD025
|
||||
"""Raised when trying to perform operations on an empty cart."""
|
||||
|
||||
def __init__(self, session_id: str):
|
||||
@@ -45,7 +45,7 @@ class EmptyCartException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "CART_EMPTY"
|
||||
|
||||
|
||||
class CartValidationException(ValidationException): # noqa: MOD-025
|
||||
class CartValidationException(ValidationException): # noqa: MOD025
|
||||
"""Raised when cart data validation fails."""
|
||||
|
||||
def __init__(
|
||||
@@ -113,7 +113,7 @@ class InvalidCartQuantityException(ValidationException):
|
||||
self.error_code = "INVALID_CART_QUANTITY"
|
||||
|
||||
|
||||
class ProductNotAvailableForCartException(BusinessLogicException): # noqa: MOD-025
|
||||
class ProductNotAvailableForCartException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when product is not available for adding to cart."""
|
||||
|
||||
def __init__(self, product_id: int, reason: str):
|
||||
|
||||
@@ -63,7 +63,7 @@ class ProductAlreadyExistsException(ConflictException):
|
||||
)
|
||||
|
||||
|
||||
class ProductNotInCatalogException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class ProductNotInCatalogException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when trying to access a product that's not in store's catalog."""
|
||||
|
||||
def __init__(self, product_id: int, store_id: int):
|
||||
@@ -129,7 +129,7 @@ class ProductValidationException(ValidationException):
|
||||
self.error_code = "PRODUCT_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class CannotDeleteProductException(BusinessLogicException): # noqa: MOD-025
|
||||
class CannotDeleteProductException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when a product cannot be deleted due to dependencies."""
|
||||
|
||||
def __init__(self, product_id: int, reason: str, details: dict | None = None):
|
||||
@@ -140,7 +140,7 @@ class CannotDeleteProductException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class CannotDeleteProductWithInventoryException(BusinessLogicException): # noqa: MOD-025
|
||||
class CannotDeleteProductWithInventoryException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to delete a product that has inventory."""
|
||||
|
||||
def __init__(self, product_id: int, inventory_count: int):
|
||||
@@ -154,7 +154,7 @@ class CannotDeleteProductWithInventoryException(BusinessLogicException): # noqa
|
||||
)
|
||||
|
||||
|
||||
class CannotDeleteProductWithOrdersException(BusinessLogicException): # noqa: MOD-025
|
||||
class CannotDeleteProductWithOrdersException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to delete a product that has been ordered."""
|
||||
|
||||
def __init__(self, product_id: int, order_count: int):
|
||||
|
||||
@@ -10,7 +10,7 @@ from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
from app.modules.inventory.schemas import InventoryLocationResponse # noqa: IMPORT-002
|
||||
from app.modules.inventory.schemas import InventoryLocationResponse # noqa: IMPORT002
|
||||
from app.modules.marketplace.schemas import MarketplaceProductResponse # IMPORT-002
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from app.modules.inventory.schemas import InventoryLocationResponse # noqa: IMPORT-002
|
||||
from app.modules.inventory.schemas import InventoryLocationResponse # noqa: IMPORT002
|
||||
from app.modules.marketplace.schemas import MarketplaceProductResponse # IMPORT-002
|
||||
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ class TestProductInventoryProperties:
|
||||
|
||||
def test_physical_product_with_inventory(self, db, test_store):
|
||||
"""Test physical product calculates inventory from entries."""
|
||||
from app.modules.inventory.models import Inventory # noqa: IMPORT-002
|
||||
from app.modules.inventory.models import Inventory # noqa: IMPORT002
|
||||
|
||||
product = Product(
|
||||
store_id=test_store.id,
|
||||
@@ -364,7 +364,7 @@ class TestProductInventoryProperties:
|
||||
|
||||
def test_digital_product_ignores_inventory_entries(self, db, test_store):
|
||||
"""Test digital product returns unlimited even with inventory entries."""
|
||||
from app.modules.inventory.models import Inventory # noqa: IMPORT-002
|
||||
from app.modules.inventory.models import Inventory # noqa: IMPORT002
|
||||
|
||||
product = Product(
|
||||
store_id=test_store.id,
|
||||
|
||||
@@ -12,7 +12,7 @@ from app.exceptions.base import (
|
||||
)
|
||||
|
||||
|
||||
class CheckoutValidationException(ValidationException): # noqa: MOD-025
|
||||
class CheckoutValidationException(ValidationException): # noqa: MOD025
|
||||
"""Raised when checkout data validation fails."""
|
||||
|
||||
def __init__(
|
||||
@@ -29,7 +29,7 @@ class CheckoutValidationException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "CHECKOUT_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class CheckoutSessionNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class CheckoutSessionNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when checkout session is not found."""
|
||||
|
||||
def __init__(self, session_id: str):
|
||||
@@ -41,7 +41,7 @@ class CheckoutSessionNotFoundException(ResourceNotFoundException): # noqa: MOD-
|
||||
)
|
||||
|
||||
|
||||
class CheckoutSessionExpiredException(BusinessLogicException): # noqa: MOD-025
|
||||
class CheckoutSessionExpiredException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when checkout session has expired."""
|
||||
|
||||
def __init__(self, session_id: str):
|
||||
@@ -52,7 +52,7 @@ class CheckoutSessionExpiredException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class EmptyCheckoutException(ValidationException): # noqa: MOD-025
|
||||
class EmptyCheckoutException(ValidationException): # noqa: MOD025
|
||||
"""Raised when trying to checkout with empty cart."""
|
||||
|
||||
def __init__(self):
|
||||
@@ -63,7 +63,7 @@ class EmptyCheckoutException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "EMPTY_CHECKOUT"
|
||||
|
||||
|
||||
class PaymentRequiredException(BusinessLogicException): # noqa: MOD-025
|
||||
class PaymentRequiredException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when payment is required but not provided."""
|
||||
|
||||
def __init__(self, order_total: float):
|
||||
@@ -74,7 +74,7 @@ class PaymentRequiredException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class PaymentFailedException(BusinessLogicException): # noqa: MOD-025
|
||||
class PaymentFailedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when payment processing fails."""
|
||||
|
||||
def __init__(self, reason: str, details: dict | None = None):
|
||||
@@ -85,7 +85,7 @@ class PaymentFailedException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class InvalidShippingAddressException(ValidationException): # noqa: MOD-025
|
||||
class InvalidShippingAddressException(ValidationException): # noqa: MOD025
|
||||
"""Raised when shipping address is invalid or missing."""
|
||||
|
||||
def __init__(self, message: str = "Invalid shipping address", details: dict | None = None):
|
||||
@@ -97,7 +97,7 @@ class InvalidShippingAddressException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "INVALID_SHIPPING_ADDRESS"
|
||||
|
||||
|
||||
class ShippingMethodNotAvailableException(BusinessLogicException): # noqa: MOD-025
|
||||
class ShippingMethodNotAvailableException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when selected shipping method is not available."""
|
||||
|
||||
def __init__(self, shipping_method: str, reason: str | None = None):
|
||||
@@ -111,7 +111,7 @@ class ShippingMethodNotAvailableException(BusinessLogicException): # noqa: MOD-
|
||||
)
|
||||
|
||||
|
||||
class CheckoutInventoryException(BusinessLogicException): # noqa: MOD-025
|
||||
class CheckoutInventoryException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when inventory check fails during checkout."""
|
||||
|
||||
def __init__(self, product_id: int, available: int, requested: int):
|
||||
|
||||
@@ -69,7 +69,7 @@ class ContentPageNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class ContentPageAlreadyExistsException(ConflictException): # noqa: MOD-025
|
||||
class ContentPageAlreadyExistsException(ConflictException): # noqa: MOD025
|
||||
"""Raised when a content page with the same slug already exists."""
|
||||
|
||||
def __init__(self, slug: str, store_id: int | None = None):
|
||||
@@ -84,7 +84,7 @@ class ContentPageAlreadyExistsException(ConflictException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class ContentPageSlugReservedException(ValidationException): # noqa: MOD-025
|
||||
class ContentPageSlugReservedException(ValidationException): # noqa: MOD025
|
||||
"""Raised when trying to use a reserved slug."""
|
||||
|
||||
def __init__(self, slug: str):
|
||||
@@ -96,7 +96,7 @@ class ContentPageSlugReservedException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "CONTENT_PAGE_SLUG_RESERVED"
|
||||
|
||||
|
||||
class ContentPageNotPublishedException(BusinessLogicException): # noqa: MOD-025
|
||||
class ContentPageNotPublishedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to access an unpublished content page."""
|
||||
|
||||
def __init__(self, slug: str):
|
||||
@@ -118,7 +118,7 @@ class UnauthorizedContentPageAccessException(AuthorizationException):
|
||||
)
|
||||
|
||||
|
||||
class StoreNotAssociatedException(AuthorizationException): # noqa: MOD-025
|
||||
class StoreNotAssociatedException(AuthorizationException): # noqa: MOD025
|
||||
"""Raised when a user is not associated with a store."""
|
||||
|
||||
def __init__(self):
|
||||
@@ -143,7 +143,7 @@ class NoPlatformSubscriptionException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class ContentPageValidationException(ValidationException): # noqa: MOD-025
|
||||
class ContentPageValidationException(ValidationException): # noqa: MOD025
|
||||
"""Raised when content page data validation fails."""
|
||||
|
||||
def __init__(self, field: str, message: str, value: str | None = None):
|
||||
@@ -175,7 +175,7 @@ class MediaNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class MediaUploadException(BusinessLogicException): # noqa: MOD-025
|
||||
class MediaUploadException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when media upload fails."""
|
||||
|
||||
def __init__(self, message: str = "Media upload failed", details: dict[str, Any] | None = None):
|
||||
@@ -241,7 +241,7 @@ class MediaOptimizationException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class MediaDeleteException(BusinessLogicException): # noqa: MOD-025
|
||||
class MediaDeleteException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when media deletion fails."""
|
||||
|
||||
def __init__(self, message: str, details: dict[str, Any] | None = None):
|
||||
@@ -269,7 +269,7 @@ class StoreThemeNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class InvalidThemeDataException(ValidationException): # noqa: MOD-025
|
||||
class InvalidThemeDataException(ValidationException): # noqa: MOD025
|
||||
"""Raised when theme data is invalid."""
|
||||
|
||||
def __init__(
|
||||
@@ -321,7 +321,7 @@ class ThemeValidationException(ValidationException):
|
||||
self.error_code = "THEME_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class ThemePresetAlreadyAppliedException(BusinessLogicException): # noqa: MOD-025
|
||||
class ThemePresetAlreadyAppliedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to apply the same preset that's already active."""
|
||||
|
||||
def __init__(self, preset_name: str, store_code: str):
|
||||
|
||||
@@ -234,7 +234,7 @@ function contentPageEditor(pageId) {
|
||||
|
||||
const quill = quillContainer.__quill;
|
||||
if (this.form.content && quill.root.innerHTML !== this.form.content) {
|
||||
quill.root.innerHTML = this.form.content;
|
||||
quill.root.innerHTML = this.form.content; // # noqa: SEC-015
|
||||
contentPageEditLog.debug('Synced Quill content after page load');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<div class="w-16 h-16 mx-auto mb-4 rounded-full gradient-primary flex items-center justify-center">
|
||||
{# Support for icon names - rendered via Alpine $icon helper or direct SVG #}
|
||||
{% if feature.icon.startswith('<svg') %}
|
||||
{{ feature.icon | safe }}
|
||||
{{ feature.icon | safe }} <!-- noqa: SEC-015 -->
|
||||
{% else %}
|
||||
<span x-html="typeof $icon !== 'undefined' ? $icon('{{ feature.icon }}', 'w-8 h-8 text-white') : ''"></span>
|
||||
{% endif %}
|
||||
|
||||
@@ -10,12 +10,12 @@ Exceptions for core platform functionality including:
|
||||
from app.exceptions import OrionException
|
||||
|
||||
|
||||
class CoreException(OrionException): # noqa: MOD-025
|
||||
class CoreException(OrionException): # noqa: MOD025
|
||||
"""Base exception for core module."""
|
||||
|
||||
|
||||
|
||||
class MenuConfigurationError(CoreException): # noqa: MOD-025
|
||||
class MenuConfigurationError(CoreException): # noqa: MOD025
|
||||
"""Error in menu configuration."""
|
||||
|
||||
|
||||
@@ -25,5 +25,5 @@ class SettingsError(CoreException):
|
||||
|
||||
|
||||
|
||||
class DashboardError(CoreException): # noqa: MOD-025
|
||||
class DashboardError(CoreException): # noqa: MOD025
|
||||
"""Error in dashboard operations."""
|
||||
|
||||
@@ -197,8 +197,7 @@ function shopLayoutData() {
|
||||
info: 'bg-blue-500'
|
||||
};
|
||||
|
||||
// noqa: SEC-015 - message is application-controlled
|
||||
toast.innerHTML = `
|
||||
toast.innerHTML /* # noqa: SEC-015 */ = `
|
||||
<div class="${colors[type]} text-white px-6 py-3 rounded-lg shadow-lg flex items-center space-x-3">
|
||||
<span>${message}</span>
|
||||
<button onclick="this.parentElement.parentElement.remove()"
|
||||
@@ -292,4 +291,4 @@ function languageSelector(currentLang, enabledLanguages) {
|
||||
|
||||
window.languageSelector = languageSelector;
|
||||
|
||||
shopLog.info('Shop layout module loaded');
|
||||
shopLog.info('Shop layout module loaded');
|
||||
|
||||
@@ -53,7 +53,7 @@ class CustomerNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class CustomerAlreadyExistsException(ConflictException): # noqa: MOD-025
|
||||
class CustomerAlreadyExistsException(ConflictException): # noqa: MOD025
|
||||
"""Raised when trying to create a customer that already exists."""
|
||||
|
||||
def __init__(self, email: str):
|
||||
@@ -109,7 +109,7 @@ class CustomerValidationException(ValidationException):
|
||||
self.error_code = "CUSTOMER_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class CustomerAuthorizationException(BusinessLogicException): # noqa: MOD-025
|
||||
class CustomerAuthorizationException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when customer is not authorized for operation."""
|
||||
|
||||
def __init__(self, customer_email: str, operation: str):
|
||||
@@ -170,7 +170,7 @@ class AddressLimitExceededException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class InvalidAddressTypeException(BusinessLogicException): # noqa: MOD-025
|
||||
class InvalidAddressTypeException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when an invalid address type is provided."""
|
||||
|
||||
def __init__(self, address_type: str):
|
||||
|
||||
@@ -317,7 +317,7 @@ def forgot_password(request: Request, email: str, db: Session = Depends(get_db))
|
||||
)
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Failed to send password reset email: {e}") # noqa: SEC-021
|
||||
logger.error(f"Failed to send password reset email: {e}") # noqa: SEC021
|
||||
else:
|
||||
logger.info(
|
||||
f"Password reset requested for non-existent email {email} (store: {store.subdomain})"
|
||||
|
||||
@@ -570,7 +570,7 @@ class CustomerService:
|
||||
# Mark token as used
|
||||
token_record.mark_used(db)
|
||||
|
||||
logger.info(f"Password reset completed for customer {customer.id}") # noqa: SEC-021
|
||||
logger.info(f"Password reset completed for customer {customer.id}") # noqa: SEC021
|
||||
|
||||
return customer
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ def multiple_customers(db, test_store):
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email=f"customer{i}@example.com",
|
||||
hashed_password="hashed_password_placeholder", # noqa: SEC-001
|
||||
hashed_password="hashed_password_placeholder", # noqa: SEC001
|
||||
first_name=f"First{i}",
|
||||
last_name=f"Last{i}",
|
||||
customer_number=f"CUST-00{i}",
|
||||
|
||||
@@ -16,7 +16,7 @@ class TestCustomerModel:
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="customer@example.com",
|
||||
hashed_password="hashed_password", # noqa: SEC-001
|
||||
hashed_password="hashed_password", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
customer_number="CUST001",
|
||||
@@ -40,7 +40,7 @@ class TestCustomerModel:
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="defaults@example.com",
|
||||
hashed_password="hash", # noqa: SEC-001
|
||||
hashed_password="hash", # noqa: SEC001
|
||||
customer_number="CUST_DEFAULTS",
|
||||
)
|
||||
db.add(customer)
|
||||
@@ -57,7 +57,7 @@ class TestCustomerModel:
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="fullname@example.com",
|
||||
hashed_password="hash", # noqa: SEC-001
|
||||
hashed_password="hash", # noqa: SEC001
|
||||
customer_number="CUST_FULLNAME",
|
||||
first_name="Jane",
|
||||
last_name="Smith",
|
||||
@@ -73,7 +73,7 @@ class TestCustomerModel:
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="noname@example.com",
|
||||
hashed_password="hash", # noqa: SEC-001
|
||||
hashed_password="hash", # noqa: SEC001
|
||||
customer_number="CUST_NONAME",
|
||||
)
|
||||
db.add(customer)
|
||||
@@ -87,7 +87,7 @@ class TestCustomerModel:
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="optional@example.com",
|
||||
hashed_password="hash", # noqa: SEC-001
|
||||
hashed_password="hash", # noqa: SEC001
|
||||
customer_number="CUST_OPT",
|
||||
phone="+352123456789",
|
||||
preferences={"language": "en", "currency": "EUR"},
|
||||
@@ -106,7 +106,7 @@ class TestCustomerModel:
|
||||
customer = Customer(
|
||||
store_id=test_store.id,
|
||||
email="relationship@example.com",
|
||||
hashed_password="hash", # noqa: SEC-001
|
||||
hashed_password="hash", # noqa: SEC001
|
||||
customer_number="CUST_REL",
|
||||
)
|
||||
db.add(customer)
|
||||
|
||||
@@ -24,7 +24,7 @@ class TestCustomerRegisterSchema:
|
||||
"""Test valid registration data."""
|
||||
customer = CustomerRegister(
|
||||
email="customer@example.com",
|
||||
password="Password123", # noqa: SEC-001
|
||||
password="Password123", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -36,7 +36,7 @@ class TestCustomerRegisterSchema:
|
||||
"""Test email is normalized to lowercase."""
|
||||
customer = CustomerRegister(
|
||||
email="Customer@Example.COM",
|
||||
password="Password123", # noqa: SEC-001
|
||||
password="Password123", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -47,7 +47,7 @@ class TestCustomerRegisterSchema:
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CustomerRegister(
|
||||
email="not-an-email",
|
||||
password="Password123", # noqa: SEC-001
|
||||
password="Password123", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -58,7 +58,7 @@ class TestCustomerRegisterSchema:
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CustomerRegister(
|
||||
email="customer@example.com",
|
||||
password="Pass1", # noqa: SEC-001
|
||||
password="Pass1", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -69,7 +69,7 @@ class TestCustomerRegisterSchema:
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CustomerRegister(
|
||||
email="customer@example.com",
|
||||
password="Password", # noqa: SEC-001
|
||||
password="Password", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -80,7 +80,7 @@ class TestCustomerRegisterSchema:
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CustomerRegister(
|
||||
email="customer@example.com",
|
||||
password="12345678", # noqa: SEC-001
|
||||
password="12345678", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -91,7 +91,7 @@ class TestCustomerRegisterSchema:
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
CustomerRegister(
|
||||
email="customer@example.com",
|
||||
password="Password123", # noqa: SEC-001
|
||||
password="Password123", # noqa: SEC001
|
||||
last_name="Doe",
|
||||
)
|
||||
assert "first_name" in str(exc_info.value).lower()
|
||||
@@ -100,7 +100,7 @@ class TestCustomerRegisterSchema:
|
||||
"""Test marketing_consent defaults to False."""
|
||||
customer = CustomerRegister(
|
||||
email="customer@example.com",
|
||||
password="Password123", # noqa: SEC-001
|
||||
password="Password123", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -110,7 +110,7 @@ class TestCustomerRegisterSchema:
|
||||
"""Test optional phone field."""
|
||||
customer = CustomerRegister(
|
||||
email="customer@example.com",
|
||||
password="Password123", # noqa: SEC-001
|
||||
password="Password123", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
phone="+352 123 456",
|
||||
|
||||
@@ -28,7 +28,7 @@ from app.modules.monitoring.exceptions import (
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TestRunNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class TestRunNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a test run is not found."""
|
||||
|
||||
def __init__(self, run_id: int):
|
||||
@@ -39,7 +39,7 @@ class TestRunNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class TestExecutionException(ExternalServiceException): # noqa: MOD-025
|
||||
class TestExecutionException(ExternalServiceException): # noqa: MOD025
|
||||
"""Raised when test execution fails."""
|
||||
|
||||
def __init__(self, reason: str):
|
||||
@@ -50,7 +50,7 @@ class TestExecutionException(ExternalServiceException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class TestTimeoutException(ExternalServiceException): # noqa: MOD-025
|
||||
class TestTimeoutException(ExternalServiceException): # noqa: MOD025
|
||||
"""Raised when test execution times out."""
|
||||
|
||||
def __init__(self, timeout_seconds: int = 3600):
|
||||
|
||||
@@ -186,7 +186,7 @@ class CodeQualityService:
|
||||
try:
|
||||
scan = self.run_scan(db, triggered_by, validator_type)
|
||||
results.append(scan)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to run {validator_type} scan: {e}")
|
||||
# Continue with other validators even if one fails
|
||||
return results
|
||||
|
||||
@@ -113,7 +113,7 @@ class InventoryValidationException(ValidationException):
|
||||
self.error_code = "INVENTORY_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class NegativeInventoryException(BusinessLogicException): # noqa: MOD-025
|
||||
class NegativeInventoryException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when inventory quantity would become negative."""
|
||||
|
||||
def __init__(self, gtin: str, location: str, resulting_quantity: int):
|
||||
@@ -142,7 +142,7 @@ class InvalidQuantityException(ValidationException):
|
||||
self.error_code = "INVALID_QUANTITY"
|
||||
|
||||
|
||||
class LocationNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class LocationNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when inventory location is not found."""
|
||||
|
||||
def __init__(self, location: str):
|
||||
|
||||
@@ -336,7 +336,7 @@ class OrderReferenceRequiredException(LoyaltyException):
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class LoyaltyValidationException(ValidationException): # noqa: MOD-025
|
||||
class LoyaltyValidationException(ValidationException): # noqa: MOD025
|
||||
"""Raised when loyalty data validation fails."""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -167,7 +167,7 @@ class AppleWalletService:
|
||||
"""
|
||||
try:
|
||||
self.register_device(db, card, device_id, push_token)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to register device: {e}")
|
||||
raise DeviceRegistrationException(device_id, "register")
|
||||
|
||||
@@ -190,7 +190,7 @@ class AppleWalletService:
|
||||
"""
|
||||
try:
|
||||
self.unregister_device(db, card, device_id)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to unregister device: {e}")
|
||||
raise DeviceRegistrationException(device_id, "unregister")
|
||||
|
||||
@@ -244,7 +244,7 @@ class AppleWalletService:
|
||||
# Create manifest
|
||||
manifest = {}
|
||||
for filename, content in pass_files.items():
|
||||
manifest[filename] = hashlib.sha1(content).hexdigest()
|
||||
manifest[filename] = hashlib.sha1(content).hexdigest() # noqa: SEC041
|
||||
pass_files["manifest.json"] = json.dumps(manifest).encode("utf-8")
|
||||
|
||||
# Sign the manifest
|
||||
@@ -521,7 +521,7 @@ class AppleWalletService:
|
||||
for registration in registrations:
|
||||
try:
|
||||
self._send_push(registration.push_token)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.warning(
|
||||
f"Failed to send push to device {registration.device_library_identifier[:8]}...: {e}"
|
||||
)
|
||||
|
||||
@@ -70,7 +70,7 @@ class GoogleWalletService:
|
||||
credentials = self._get_credentials()
|
||||
self._http_client = AuthorizedSession(credentials)
|
||||
return self._http_client
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to create Google HTTP client: {e}")
|
||||
raise WalletIntegrationException("google", str(e))
|
||||
|
||||
@@ -146,7 +146,7 @@ class GoogleWalletService:
|
||||
)
|
||||
except WalletIntegrationException:
|
||||
raise
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to create Google Wallet class: {e}")
|
||||
raise WalletIntegrationException("google", str(e))
|
||||
|
||||
@@ -177,7 +177,7 @@ class GoogleWalletService:
|
||||
f"Failed to update Google Wallet class {program.google_class_id}: "
|
||||
f"{response.status_code}"
|
||||
)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to update Google Wallet class: {e}")
|
||||
|
||||
# =========================================================================
|
||||
@@ -233,7 +233,7 @@ class GoogleWalletService:
|
||||
)
|
||||
except WalletIntegrationException:
|
||||
raise
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to create Google Wallet object: {e}")
|
||||
raise WalletIntegrationException("google", str(e))
|
||||
|
||||
@@ -258,7 +258,7 @@ class GoogleWalletService:
|
||||
f"Failed to update Google Wallet object {card.google_object_id}: "
|
||||
f"{response.status_code}"
|
||||
)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to update Google Wallet object: {e}")
|
||||
|
||||
def _build_object_data(self, card: LoyaltyCard, object_id: str) -> dict[str, Any]:
|
||||
@@ -356,7 +356,7 @@ class GoogleWalletService:
|
||||
db.commit()
|
||||
|
||||
return f"https://pay.google.com/gp/v/save/{token}"
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to generate Google Wallet save URL: {e}")
|
||||
raise WalletIntegrationException("google", str(e))
|
||||
|
||||
|
||||
@@ -51,14 +51,14 @@ class WalletService:
|
||||
if program.google_issuer_id or program.google_class_id:
|
||||
try:
|
||||
urls["google_wallet_url"] = google_wallet_service.get_save_url(db, card)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.warning(f"Failed to get Google Wallet URL for card {card.id}: {e}")
|
||||
|
||||
# Apple Wallet
|
||||
if program.apple_pass_type_id:
|
||||
try:
|
||||
urls["apple_wallet_url"] = apple_wallet_service.get_pass_url(card)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.warning(f"Failed to get Apple Wallet URL for card {card.id}: {e}")
|
||||
|
||||
return urls
|
||||
@@ -94,7 +94,7 @@ class WalletService:
|
||||
try:
|
||||
google_wallet_service.update_object(db, card)
|
||||
results["google_wallet"] = True
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to sync card {card.id} to Google Wallet: {e}")
|
||||
|
||||
# Sync to Apple Wallet (via push notification)
|
||||
@@ -102,7 +102,7 @@ class WalletService:
|
||||
try:
|
||||
apple_wallet_service.send_push_updates(db, card)
|
||||
results["apple_wallet"] = True
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to send Apple Wallet push for card {card.id}: {e}")
|
||||
|
||||
return results
|
||||
@@ -136,7 +136,7 @@ class WalletService:
|
||||
try:
|
||||
google_wallet_service.create_object(db, card)
|
||||
results["google_wallet"] = True
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Failed to create Google Wallet object for card {card.id}: {e}")
|
||||
|
||||
# Apple Wallet objects are created on-demand when user downloads pass
|
||||
|
||||
@@ -110,7 +110,7 @@ class LetzshopClientError(MarketplaceException):
|
||||
self.response = response
|
||||
|
||||
|
||||
class LetzshopAuthenticationError(LetzshopClientError): # noqa: MOD-025
|
||||
class LetzshopAuthenticationError(LetzshopClientError): # noqa: MOD025
|
||||
"""Raised when Letzshop authentication fails."""
|
||||
|
||||
def __init__(self, message: str = "Letzshop authentication failed"):
|
||||
@@ -118,7 +118,7 @@ class LetzshopAuthenticationError(LetzshopClientError): # noqa: MOD-025
|
||||
self.error_code = "LETZSHOP_AUTHENTICATION_FAILED"
|
||||
|
||||
|
||||
class LetzshopCredentialsNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class LetzshopCredentialsNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when Letzshop credentials not found for store."""
|
||||
|
||||
def __init__(self, store_id: int):
|
||||
@@ -130,7 +130,7 @@ class LetzshopCredentialsNotFoundException(ResourceNotFoundException): # noqa:
|
||||
self.store_id = store_id
|
||||
|
||||
|
||||
class LetzshopConnectionFailedException(BusinessLogicException): # noqa: MOD-025
|
||||
class LetzshopConnectionFailedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when Letzshop API connection test fails."""
|
||||
|
||||
def __init__(self, error_message: str):
|
||||
@@ -158,7 +158,7 @@ class ImportJobNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class HistoricalImportJobNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class HistoricalImportJobNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a historical import job is not found."""
|
||||
|
||||
def __init__(self, job_id: int):
|
||||
@@ -184,7 +184,7 @@ class ImportJobNotOwnedException(AuthorizationException):
|
||||
)
|
||||
|
||||
|
||||
class ImportJobCannotBeCancelledException(BusinessLogicException): # noqa: MOD-025
|
||||
class ImportJobCannotBeCancelledException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to cancel job that cannot be cancelled."""
|
||||
|
||||
def __init__(self, job_id: int, current_status: str):
|
||||
@@ -198,7 +198,7 @@ class ImportJobCannotBeCancelledException(BusinessLogicException): # noqa: MOD-
|
||||
)
|
||||
|
||||
|
||||
class ImportJobCannotBeDeletedException(BusinessLogicException): # noqa: MOD-025
|
||||
class ImportJobCannotBeDeletedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to delete job that cannot be deleted."""
|
||||
|
||||
def __init__(self, job_id: int, current_status: str):
|
||||
@@ -212,7 +212,7 @@ class ImportJobCannotBeDeletedException(BusinessLogicException): # noqa: MOD-02
|
||||
)
|
||||
|
||||
|
||||
class ImportJobAlreadyProcessingException(BusinessLogicException): # noqa: MOD-025
|
||||
class ImportJobAlreadyProcessingException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to start import while another is already processing."""
|
||||
|
||||
def __init__(self, store_code: str, existing_job_id: int):
|
||||
@@ -238,7 +238,7 @@ class ImportValidationError(MarketplaceException):
|
||||
self.errors = errors or []
|
||||
|
||||
|
||||
class InvalidImportDataException(ValidationException): # noqa: MOD-025
|
||||
class InvalidImportDataException(ValidationException): # noqa: MOD025
|
||||
"""Raised when import data is invalid."""
|
||||
|
||||
def __init__(
|
||||
@@ -262,7 +262,7 @@ class InvalidImportDataException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "INVALID_IMPORT_DATA"
|
||||
|
||||
|
||||
class ImportRateLimitException(BusinessLogicException): # noqa: MOD-025
|
||||
class ImportRateLimitException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when import rate limit is exceeded."""
|
||||
|
||||
def __init__(
|
||||
@@ -291,7 +291,7 @@ class ImportRateLimitException(BusinessLogicException): # noqa: MOD-025
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class MarketplaceImportException(BusinessLogicException): # noqa: MOD-025
|
||||
class MarketplaceImportException(BusinessLogicException): # noqa: MOD025
|
||||
"""Base exception for marketplace import operations."""
|
||||
|
||||
def __init__(
|
||||
@@ -314,7 +314,7 @@ class MarketplaceImportException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class MarketplaceConnectionException(ExternalServiceException): # noqa: MOD-025
|
||||
class MarketplaceConnectionException(ExternalServiceException): # noqa: MOD025
|
||||
"""Raised when marketplace connection fails."""
|
||||
|
||||
def __init__(
|
||||
@@ -327,7 +327,7 @@ class MarketplaceConnectionException(ExternalServiceException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class MarketplaceDataParsingException(ValidationException): # noqa: MOD-025
|
||||
class MarketplaceDataParsingException(ValidationException): # noqa: MOD025
|
||||
"""Raised when marketplace data cannot be parsed."""
|
||||
|
||||
def __init__(
|
||||
@@ -347,7 +347,7 @@ class MarketplaceDataParsingException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "MARKETPLACE_DATA_PARSING_FAILED"
|
||||
|
||||
|
||||
class InvalidMarketplaceException(ValidationException): # noqa: MOD-025
|
||||
class InvalidMarketplaceException(ValidationException): # noqa: MOD025
|
||||
"""Raised when marketplace is not supported."""
|
||||
|
||||
def __init__(self, marketplace: str, supported_marketplaces: list | None = None):
|
||||
@@ -451,7 +451,7 @@ class MarketplaceProductValidationException(ValidationException):
|
||||
self.error_code = "PRODUCT_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class InvalidGTINException(ValidationException): # noqa: MOD-025
|
||||
class InvalidGTINException(ValidationException): # noqa: MOD025
|
||||
"""Raised when GTIN format is invalid."""
|
||||
|
||||
def __init__(self, gtin: str, message: str = "Invalid GTIN format"):
|
||||
@@ -463,7 +463,7 @@ class InvalidGTINException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "INVALID_GTIN"
|
||||
|
||||
|
||||
class MarketplaceProductCSVImportException(BusinessLogicException): # noqa: MOD-025
|
||||
class MarketplaceProductCSVImportException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when product CSV import fails."""
|
||||
|
||||
def __init__(
|
||||
@@ -490,7 +490,7 @@ class MarketplaceProductCSVImportException(BusinessLogicException): # noqa: MOD
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ExportError(MarketplaceException): # noqa: MOD-025
|
||||
class ExportError(MarketplaceException): # noqa: MOD025
|
||||
"""Raised when product export fails."""
|
||||
|
||||
def __init__(self, message: str, language: str | None = None):
|
||||
|
||||
@@ -25,8 +25,8 @@ class MarketplaceImportJobRequest(BaseModel):
|
||||
@field_validator("source_url")
|
||||
@classmethod
|
||||
def validate_url(cls, v):
|
||||
if not v.startswith(("http://", "https://")): # SEC-034
|
||||
raise ValueError("URL must start with http:// or https://") # SEC-034
|
||||
if not v.startswith(("http://", "https://")): # noqa: SEC034
|
||||
raise ValueError("URL must start with http:// or https://") # noqa: SEC034
|
||||
return v.strip()
|
||||
|
||||
@field_validator("marketplace")
|
||||
@@ -64,8 +64,8 @@ class AdminMarketplaceImportJobRequest(BaseModel):
|
||||
@field_validator("source_url")
|
||||
@classmethod
|
||||
def validate_url(cls, v):
|
||||
if not v.startswith(("http://", "https://")): # SEC-034
|
||||
raise ValueError("URL must start with http:// or https://") # SEC-034
|
||||
if not v.startswith(("http://", "https://")): # noqa: SEC034
|
||||
raise ValueError("URL must start with http:// or https://") # noqa: SEC034
|
||||
return v.strip()
|
||||
|
||||
@field_validator("marketplace")
|
||||
|
||||
@@ -467,7 +467,7 @@ class LetzshopStoreSyncService:
|
||||
.first()
|
||||
)
|
||||
if existing:
|
||||
store_code = f"{store_code[:16]}_{random.randint(100, 999)}"
|
||||
store_code = f"{store_code[:16]}_{random.randint(100, 999)}" # noqa: SEC042
|
||||
|
||||
# Generate subdomain from slug
|
||||
subdomain = letzshop_slug.lower().replace("_", "-")[:30]
|
||||
@@ -477,7 +477,7 @@ class LetzshopStoreSyncService:
|
||||
.first()
|
||||
)
|
||||
if existing_subdomain:
|
||||
subdomain = f"{subdomain[:26]}-{random.randint(100, 999)}"
|
||||
subdomain = f"{subdomain[:26]}-{random.randint(100, 999)}" # noqa: SEC042
|
||||
|
||||
# Create store data from cache
|
||||
address = f"{cache_entry.street or ''} {cache_entry.street_number or ''}".strip()
|
||||
|
||||
@@ -540,7 +540,7 @@ class PlatformSignupService:
|
||||
|
||||
logger.info(f"Welcome email sent to {user.email}")
|
||||
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
# Log error but don't fail signup
|
||||
logger.error(f"Failed to send welcome email to {user.email}: {e}")
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class TestMarketplaceImportJobRequestSchema:
|
||||
assert "source_url" in str(exc_info.value).lower()
|
||||
|
||||
def test_source_url_must_be_http_or_https(self):
|
||||
"""Test source_url must start with http:// or https://."""
|
||||
"""Test source_url must start with http:// or https://.""" # noqa: SEC034
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
MarketplaceImportJobRequest(
|
||||
source_url="ftp://example.com/products.csv",
|
||||
@@ -41,7 +41,7 @@ class TestMarketplaceImportJobRequestSchema:
|
||||
assert "url" in str(exc_info.value).lower()
|
||||
|
||||
def test_source_url_http_is_valid(self):
|
||||
"""Test http:// URLs are valid."""
|
||||
"""Test http:// URLs are valid.""" # noqa: SEC034
|
||||
request = MarketplaceImportJobRequest(
|
||||
source_url="http://example.com/products.csv",
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ class TestEncryptionService:
|
||||
|
||||
def test_encrypt_and_decrypt(self):
|
||||
"""Test basic encryption and decryption."""
|
||||
service = EncryptionService(secret_key="test-secret-key-12345")
|
||||
service = EncryptionService(secret_key="test-secret-key-12345") # noqa: SEC001
|
||||
original = "my-secret-api-key"
|
||||
|
||||
encrypted = service.encrypt(original)
|
||||
@@ -47,28 +47,28 @@ class TestEncryptionService:
|
||||
|
||||
def test_encrypt_empty_string_fails(self):
|
||||
"""Test that encrypting empty string raises error."""
|
||||
service = EncryptionService(secret_key="test-secret-key-12345")
|
||||
service = EncryptionService(secret_key="test-secret-key-12345") # noqa: SEC001
|
||||
|
||||
with pytest.raises(EncryptionError):
|
||||
service.encrypt("")
|
||||
|
||||
def test_decrypt_empty_string_fails(self):
|
||||
"""Test that decrypting empty string raises error."""
|
||||
service = EncryptionService(secret_key="test-secret-key-12345")
|
||||
service = EncryptionService(secret_key="test-secret-key-12345") # noqa: SEC001
|
||||
|
||||
with pytest.raises(EncryptionError):
|
||||
service.decrypt("")
|
||||
|
||||
def test_decrypt_invalid_ciphertext_fails(self):
|
||||
"""Test that decrypting invalid ciphertext raises error."""
|
||||
service = EncryptionService(secret_key="test-secret-key-12345")
|
||||
service = EncryptionService(secret_key="test-secret-key-12345") # noqa: SEC001
|
||||
|
||||
with pytest.raises(EncryptionError):
|
||||
service.decrypt("invalid-ciphertext")
|
||||
|
||||
def test_is_valid_ciphertext(self):
|
||||
"""Test ciphertext validation."""
|
||||
service = EncryptionService(secret_key="test-secret-key-12345")
|
||||
service = EncryptionService(secret_key="test-secret-key-12345") # noqa: SEC001
|
||||
encrypted = service.encrypt("test-value")
|
||||
|
||||
assert service.is_valid_ciphertext(encrypted) is True
|
||||
@@ -76,8 +76,8 @@ class TestEncryptionService:
|
||||
|
||||
def test_different_keys_produce_different_results(self):
|
||||
"""Test that different keys produce different encryptions."""
|
||||
service1 = EncryptionService(secret_key="key-one-12345")
|
||||
service2 = EncryptionService(secret_key="key-two-12345")
|
||||
service1 = EncryptionService(secret_key="key-one-12345") # noqa: SEC001
|
||||
service2 = EncryptionService(secret_key="key-two-12345") # noqa: SEC001
|
||||
|
||||
original = "test-value"
|
||||
encrypted1 = service1.encrypt(original)
|
||||
@@ -128,13 +128,13 @@ class TestLetzshopCredentialsService:
|
||||
|
||||
credentials = service.create_credentials(
|
||||
store_id=test_store.id,
|
||||
api_key="test-api-key-12345",
|
||||
api_key="test-api-key-12345", # noqa: SEC001
|
||||
auto_sync_enabled=False,
|
||||
sync_interval_minutes=30,
|
||||
)
|
||||
|
||||
assert credentials.store_id == test_store.id
|
||||
assert credentials.api_key_encrypted != "test-api-key-12345"
|
||||
assert credentials.api_key_encrypted != "test-api-key-12345" # noqa: SEC001
|
||||
assert credentials.auto_sync_enabled is False
|
||||
assert credentials.sync_interval_minutes == 30
|
||||
|
||||
@@ -262,7 +262,7 @@ class TestLetzshopCredentialsService:
|
||||
|
||||
service.create_credentials(
|
||||
store_id=test_store.id,
|
||||
api_key="letzshop-api-key-12345",
|
||||
api_key="letzshop-api-key-12345", # noqa: SEC001
|
||||
)
|
||||
|
||||
masked = service.get_masked_api_key(test_store.id)
|
||||
|
||||
@@ -34,7 +34,7 @@ class ConversationNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class MessageNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class MessageNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a message is not found."""
|
||||
|
||||
def __init__(self, message_identifier: str):
|
||||
@@ -68,7 +68,7 @@ class MessageAttachmentException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class UnauthorizedConversationAccessException(BusinessLogicException): # noqa: MOD-025
|
||||
class UnauthorizedConversationAccessException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when user tries to access a conversation they don't have access to."""
|
||||
|
||||
def __init__(self, conversation_id: int):
|
||||
|
||||
@@ -218,7 +218,7 @@ class SendGridProvider(EmailProvider):
|
||||
|
||||
except ImportError:
|
||||
return False, None, "SendGrid library not installed. Run: pip install sendgrid"
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"SendGrid send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -267,7 +267,7 @@ class MailgunProvider(EmailProvider):
|
||||
return True, result.get("id"), None
|
||||
return False, None, f"Mailgun error: {response.status_code} - {response.text}"
|
||||
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Mailgun send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -319,7 +319,7 @@ class SESProvider(EmailProvider):
|
||||
|
||||
except ImportError:
|
||||
return False, None, "boto3 library not installed. Run: pip install boto3"
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"SES send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -545,7 +545,7 @@ class ConfigurableSendGridProvider(EmailProvider):
|
||||
|
||||
except ImportError:
|
||||
return False, None, "SendGrid library not installed"
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Configurable SendGrid send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -597,7 +597,7 @@ class ConfigurableMailgunProvider(EmailProvider):
|
||||
return True, result.get("id"), None
|
||||
return False, None, f"Mailgun error: {response.status_code} - {response.text}"
|
||||
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Configurable Mailgun send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -652,7 +652,7 @@ class ConfigurableSESProvider(EmailProvider):
|
||||
|
||||
except ImportError:
|
||||
return False, None, "boto3 library not installed"
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Configurable SES send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -789,7 +789,7 @@ class StoreSendGridProvider(EmailProvider):
|
||||
|
||||
except ImportError:
|
||||
return False, None, "SendGrid library not installed"
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Store SendGrid send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -841,7 +841,7 @@ class StoreMailgunProvider(EmailProvider):
|
||||
return True, result.get("id"), None
|
||||
return False, None, f"Mailgun error: {response.status_code} - {response.text}"
|
||||
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Store Mailgun send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -896,7 +896,7 @@ class StoreSESProvider(EmailProvider):
|
||||
|
||||
except ImportError:
|
||||
return False, None, "boto3 library not installed"
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.error(f"Store SES send error: {e}")
|
||||
return False, None, str(e)
|
||||
|
||||
@@ -1015,7 +1015,7 @@ class EmailService:
|
||||
features = feature_service.get_store_features(self.db, store_id)
|
||||
# Convert to set of feature codes
|
||||
self._feature_cache[store_id] = {f.code for f in features.features}
|
||||
except Exception: # noqa: EXC-003
|
||||
except Exception: # noqa: EXC003
|
||||
self._feature_cache[store_id] = set()
|
||||
|
||||
return feature_code in self._feature_cache[store_id]
|
||||
|
||||
@@ -269,7 +269,7 @@ class StoreEmailSettingsService:
|
||||
|
||||
except (ValidationException, ExternalServiceException):
|
||||
raise # Re-raise domain exceptions
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
error_msg = str(e)
|
||||
settings.mark_verification_failed(error_msg)
|
||||
db.flush()
|
||||
|
||||
@@ -33,7 +33,7 @@ def test_email_settings(db, test_store):
|
||||
smtp_host="smtp.example.com",
|
||||
smtp_port=587,
|
||||
smtp_username="testuser",
|
||||
smtp_password="testpass", # noqa: SEC-001
|
||||
smtp_password="testpass", # noqa: SEC001
|
||||
smtp_use_tls=True,
|
||||
smtp_use_ssl=False,
|
||||
is_configured=True,
|
||||
@@ -56,7 +56,7 @@ def test_verified_email_settings(db, test_store):
|
||||
smtp_host="smtp.example.com",
|
||||
smtp_port=587,
|
||||
smtp_username="testuser",
|
||||
smtp_password="testpass", # noqa: SEC-001
|
||||
smtp_password="testpass", # noqa: SEC001
|
||||
smtp_use_tls=True,
|
||||
is_configured=True,
|
||||
is_verified=True,
|
||||
@@ -155,7 +155,7 @@ class TestStoreEmailSettingsWrite:
|
||||
"smtp_host": "smtp.example.com",
|
||||
"smtp_port": 587,
|
||||
"smtp_username": "user",
|
||||
"smtp_password": "pass", # noqa: SEC-001
|
||||
"smtp_password": "pass", # noqa: SEC001
|
||||
}
|
||||
|
||||
settings = store_email_settings_service.create_or_update(
|
||||
|
||||
@@ -38,7 +38,7 @@ __all__ = [
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TaskNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class TaskNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a background task is not found."""
|
||||
|
||||
def __init__(self, task_id: str):
|
||||
@@ -54,7 +54,7 @@ class TaskNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class CapacitySnapshotNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class CapacitySnapshotNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a capacity snapshot is not found."""
|
||||
|
||||
def __init__(self, snapshot_id: int):
|
||||
@@ -70,7 +70,7 @@ class CapacitySnapshotNotFoundException(ResourceNotFoundException): # noqa: MOD
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class MonitoringServiceException(BusinessLogicException): # noqa: MOD-025
|
||||
class MonitoringServiceException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when a monitoring operation fails."""
|
||||
|
||||
def __init__(self, operation: str, reason: str):
|
||||
@@ -108,7 +108,7 @@ class ScanNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class ScanExecutionException(ExternalServiceException): # noqa: MOD-025
|
||||
class ScanExecutionException(ExternalServiceException): # noqa: MOD025
|
||||
"""Raised when architecture scan execution fails."""
|
||||
|
||||
def __init__(self, reason: str):
|
||||
@@ -142,7 +142,7 @@ class ScanParseException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class ViolationOperationException(BusinessLogicException): # noqa: MOD-025
|
||||
class ViolationOperationException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when a violation operation fails."""
|
||||
|
||||
def __init__(self, operation: str, violation_id: int, reason: str):
|
||||
@@ -157,7 +157,7 @@ class ViolationOperationException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class InvalidViolationStatusException(ValidationException): # noqa: MOD-025
|
||||
class InvalidViolationStatusException(ValidationException): # noqa: MOD025
|
||||
"""Raised when a violation status transition is invalid."""
|
||||
|
||||
def __init__(self, violation_id: int, current_status: str, target_status: str):
|
||||
|
||||
@@ -101,12 +101,12 @@ class CapacityForecastService:
|
||||
try:
|
||||
image_stats = media_service.get_storage_stats(db)
|
||||
storage_gb = image_stats.get("total_size_gb", 0)
|
||||
except Exception: # noqa: EXC-003
|
||||
except Exception: # noqa: EXC003
|
||||
storage_gb = 0
|
||||
|
||||
try:
|
||||
db_size = platform_health_service._get_database_size(db)
|
||||
except Exception: # noqa: EXC-003
|
||||
except Exception: # noqa: EXC003
|
||||
db_size = 0
|
||||
|
||||
# Theoretical capacity from subscriptions
|
||||
|
||||
@@ -58,7 +58,7 @@ class OrderNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class OrderAlreadyExistsException(ValidationException): # noqa: MOD-025
|
||||
class OrderAlreadyExistsException(ValidationException): # noqa: MOD025
|
||||
"""Raised when trying to create a duplicate order."""
|
||||
|
||||
def __init__(self, order_number: str):
|
||||
@@ -77,7 +77,7 @@ class OrderValidationException(ValidationException):
|
||||
self.error_code = "ORDER_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class InvalidOrderStatusException(BusinessLogicException): # noqa: MOD-025
|
||||
class InvalidOrderStatusException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to set an invalid order status."""
|
||||
|
||||
def __init__(self, current_status: str, new_status: str):
|
||||
@@ -88,7 +88,7 @@ class InvalidOrderStatusException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class OrderCannotBeCancelledException(BusinessLogicException): # noqa: MOD-025
|
||||
class OrderCannotBeCancelledException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when order cannot be cancelled."""
|
||||
|
||||
def __init__(self, order_number: str, reason: str):
|
||||
@@ -182,7 +182,7 @@ class InvoiceSettingsNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class InvoiceSettingsAlreadyExistException(OrionException): # noqa: MOD-025
|
||||
class InvoiceSettingsAlreadyExistException(OrionException): # noqa: MOD025
|
||||
"""Raised when trying to create invoice settings that already exist."""
|
||||
|
||||
def __init__(self, store_id: int):
|
||||
@@ -252,7 +252,7 @@ class InvalidInvoiceStatusTransitionException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class OrderNotFoundForInvoiceException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class OrderNotFoundForInvoiceException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when an order for invoice creation is not found."""
|
||||
|
||||
def __init__(self, order_id: int):
|
||||
|
||||
@@ -490,7 +490,7 @@ class OrderInventoryService:
|
||||
f"Released {item.quantity} units of product {item.product_id} "
|
||||
f"for cancelled order {order.order_number}"
|
||||
)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
if skip_missing:
|
||||
skipped_items.append({
|
||||
"item_id": item.id,
|
||||
|
||||
@@ -972,7 +972,7 @@ class OrderService:
|
||||
f"{inventory_result.get('fulfilled_count', 0)} fulfilled, "
|
||||
f"{inventory_result.get('released_count', 0)} released"
|
||||
)
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.warning(
|
||||
f"Order {order.order_number} inventory operation failed: {e}"
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ class WebhookVerificationException(BusinessLogicException):
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class PaymentException(BusinessLogicException): # noqa: MOD-025
|
||||
class PaymentException(BusinessLogicException): # noqa: MOD025
|
||||
"""Base exception for payment-related errors."""
|
||||
|
||||
def __init__(
|
||||
@@ -66,7 +66,7 @@ class PaymentException(BusinessLogicException): # noqa: MOD-025
|
||||
super().__init__(message=message, error_code=error_code, details=details)
|
||||
|
||||
|
||||
class PaymentNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class PaymentNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a payment is not found."""
|
||||
|
||||
def __init__(self, payment_id: str):
|
||||
@@ -78,7 +78,7 @@ class PaymentNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
self.payment_id = payment_id
|
||||
|
||||
|
||||
class PaymentFailedException(PaymentException): # noqa: MOD-025
|
||||
class PaymentFailedException(PaymentException): # noqa: MOD025
|
||||
"""Raised when payment processing fails."""
|
||||
|
||||
def __init__(self, message: str, stripe_error: str | None = None):
|
||||
@@ -90,7 +90,7 @@ class PaymentFailedException(PaymentException): # noqa: MOD-025
|
||||
self.stripe_error = stripe_error
|
||||
|
||||
|
||||
class PaymentRefundException(PaymentException): # noqa: MOD-025
|
||||
class PaymentRefundException(PaymentException): # noqa: MOD025
|
||||
"""Raised when a refund fails."""
|
||||
|
||||
def __init__(self, message: str, payment_id: str | None = None):
|
||||
@@ -102,7 +102,7 @@ class PaymentRefundException(PaymentException): # noqa: MOD-025
|
||||
self.payment_id = payment_id
|
||||
|
||||
|
||||
class InsufficientFundsException(PaymentException): # noqa: MOD-025
|
||||
class InsufficientFundsException(PaymentException): # noqa: MOD025
|
||||
"""Raised when there are insufficient funds for payment."""
|
||||
|
||||
def __init__(self, required_amount: float, available_amount: float | None = None):
|
||||
@@ -121,7 +121,7 @@ class InsufficientFundsException(PaymentException): # noqa: MOD-025
|
||||
self.available_amount = available_amount
|
||||
|
||||
|
||||
class PaymentGatewayException(ExternalServiceException): # noqa: MOD-025
|
||||
class PaymentGatewayException(ExternalServiceException): # noqa: MOD025
|
||||
"""Raised when payment gateway fails."""
|
||||
|
||||
def __init__(self, gateway: str, message: str):
|
||||
@@ -132,7 +132,7 @@ class PaymentGatewayException(ExternalServiceException): # noqa: MOD-025
|
||||
self.gateway = gateway
|
||||
|
||||
|
||||
class InvalidPaymentMethodException(ValidationException): # noqa: MOD-025
|
||||
class InvalidPaymentMethodException(ValidationException): # noqa: MOD025
|
||||
"""Raised when an invalid payment method is provided."""
|
||||
|
||||
def __init__(self, method: str):
|
||||
|
||||
@@ -314,7 +314,7 @@ class GatewayService:
|
||||
"status": "healthy" if is_healthy else "unhealthy",
|
||||
"gateway": code,
|
||||
}
|
||||
except Exception as e: # noqa: EXC-003
|
||||
except Exception as e: # noqa: EXC003
|
||||
logger.exception(f"Gateway health check failed: {code}")
|
||||
return {
|
||||
"status": "error",
|
||||
|
||||
@@ -128,7 +128,7 @@ class PlatformNotFoundException(OrionException):
|
||||
)
|
||||
|
||||
|
||||
class PlatformInactiveException(OrionException): # noqa: MOD-025
|
||||
class PlatformInactiveException(OrionException): # noqa: MOD025
|
||||
"""Raised when trying to access an inactive platform."""
|
||||
|
||||
def __init__(self, code: str):
|
||||
@@ -140,7 +140,7 @@ class PlatformInactiveException(OrionException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class PlatformUpdateException(OrionException): # noqa: MOD-025
|
||||
class PlatformUpdateException(OrionException): # noqa: MOD025
|
||||
"""Raised when platform update fails."""
|
||||
|
||||
def __init__(self, code: str, reason: str):
|
||||
@@ -196,7 +196,7 @@ class StoreNotActiveException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class StoreNotVerifiedException(BusinessLogicException): # noqa: MOD-025
|
||||
class StoreNotVerifiedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to perform operations requiring verified store."""
|
||||
|
||||
def __init__(self, store_code: str):
|
||||
@@ -260,7 +260,7 @@ class StoreValidationException(ValidationException):
|
||||
self.error_code = "STORE_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class MaxStoresReachedException(BusinessLogicException): # noqa: MOD-025
|
||||
class MaxStoresReachedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when user tries to create more stores than allowed."""
|
||||
|
||||
def __init__(self, max_stores: int, user_id: int | None = None):
|
||||
@@ -275,7 +275,7 @@ class MaxStoresReachedException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class StoreAccessDeniedException(AuthorizationException): # noqa: MOD-025
|
||||
class StoreAccessDeniedException(AuthorizationException): # noqa: MOD025
|
||||
"""Raised when no store context is available for an authenticated endpoint."""
|
||||
|
||||
def __init__(self, message: str = "No store context available"):
|
||||
@@ -337,7 +337,7 @@ class MerchantNotFoundException(ResourceNotFoundException):
|
||||
)
|
||||
|
||||
|
||||
class MerchantAlreadyExistsException(ConflictException): # noqa: MOD-025
|
||||
class MerchantAlreadyExistsException(ConflictException): # noqa: MOD025
|
||||
"""Raised when trying to create a merchant that already exists."""
|
||||
|
||||
def __init__(self, merchant_name: str):
|
||||
@@ -348,7 +348,7 @@ class MerchantAlreadyExistsException(ConflictException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class MerchantNotActiveException(BusinessLogicException): # noqa: MOD-025
|
||||
class MerchantNotActiveException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to perform operations on inactive merchant."""
|
||||
|
||||
def __init__(self, merchant_id: int):
|
||||
@@ -359,7 +359,7 @@ class MerchantNotActiveException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class MerchantNotVerifiedException(BusinessLogicException): # noqa: MOD-025
|
||||
class MerchantNotVerifiedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to perform operations requiring verified merchant."""
|
||||
|
||||
def __init__(self, merchant_id: int):
|
||||
@@ -370,7 +370,7 @@ class MerchantNotVerifiedException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class UnauthorizedMerchantAccessException(AuthorizationException): # noqa: MOD-025
|
||||
class UnauthorizedMerchantAccessException(AuthorizationException): # noqa: MOD025
|
||||
"""Raised when user tries to access merchant they don't own."""
|
||||
|
||||
def __init__(self, merchant_id: int, user_id: int | None = None):
|
||||
@@ -385,7 +385,7 @@ class UnauthorizedMerchantAccessException(AuthorizationException): # noqa: MOD-
|
||||
)
|
||||
|
||||
|
||||
class InvalidMerchantDataException(ValidationException): # noqa: MOD-025
|
||||
class InvalidMerchantDataException(ValidationException): # noqa: MOD025
|
||||
"""Raised when merchant data is invalid or incomplete."""
|
||||
|
||||
def __init__(
|
||||
@@ -402,7 +402,7 @@ class InvalidMerchantDataException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "INVALID_MERCHANT_DATA"
|
||||
|
||||
|
||||
class MerchantValidationException(ValidationException): # noqa: MOD-025
|
||||
class MerchantValidationException(ValidationException): # noqa: MOD025
|
||||
"""Raised when merchant validation fails."""
|
||||
|
||||
def __init__(
|
||||
@@ -527,7 +527,7 @@ class CannotModifySelfException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class BulkOperationException(BusinessLogicException): # noqa: MOD-025
|
||||
class BulkOperationException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when bulk admin operation fails."""
|
||||
|
||||
def __init__(
|
||||
@@ -675,7 +675,7 @@ class TeamMemberAlreadyExistsException(ConflictException):
|
||||
)
|
||||
|
||||
|
||||
class TeamInvitationNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class TeamInvitationNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a team invitation is not found."""
|
||||
|
||||
def __init__(self, invitation_token: str):
|
||||
@@ -687,7 +687,7 @@ class TeamInvitationNotFoundException(ResourceNotFoundException): # noqa: MOD-0
|
||||
)
|
||||
|
||||
|
||||
class TeamInvitationExpiredException(BusinessLogicException): # noqa: MOD-025
|
||||
class TeamInvitationExpiredException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to accept an expired invitation."""
|
||||
|
||||
def __init__(self, invitation_token: str):
|
||||
@@ -709,7 +709,7 @@ class TeamInvitationAlreadyAcceptedException(ConflictException):
|
||||
)
|
||||
|
||||
|
||||
class UnauthorizedTeamActionException(AuthorizationException): # noqa: MOD-025
|
||||
class UnauthorizedTeamActionException(AuthorizationException): # noqa: MOD025
|
||||
"""Raised when user tries to perform team action without permission."""
|
||||
|
||||
def __init__(
|
||||
@@ -745,7 +745,7 @@ class CannotRemoveOwnerException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class CannotModifyOwnRoleException(BusinessLogicException): # noqa: MOD-025
|
||||
class CannotModifyOwnRoleException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when user tries to modify their own role."""
|
||||
|
||||
def __init__(self, user_id: int):
|
||||
@@ -756,7 +756,7 @@ class CannotModifyOwnRoleException(BusinessLogicException): # noqa: MOD-025
|
||||
)
|
||||
|
||||
|
||||
class RoleNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
class RoleNotFoundException(ResourceNotFoundException): # noqa: MOD025
|
||||
"""Raised when a role is not found."""
|
||||
|
||||
def __init__(self, role_id: int, store_id: int | None = None):
|
||||
@@ -776,7 +776,7 @@ class RoleNotFoundException(ResourceNotFoundException): # noqa: MOD-025
|
||||
self.details.update(details)
|
||||
|
||||
|
||||
class InvalidRoleException(ValidationException): # noqa: MOD-025
|
||||
class InvalidRoleException(ValidationException): # noqa: MOD025
|
||||
"""Raised when role data is invalid."""
|
||||
|
||||
def __init__(
|
||||
@@ -793,7 +793,7 @@ class InvalidRoleException(ValidationException): # noqa: MOD-025
|
||||
self.error_code = "INVALID_ROLE_DATA"
|
||||
|
||||
|
||||
class InsufficientTeamPermissionsException(AuthorizationException): # noqa: MOD-025
|
||||
class InsufficientTeamPermissionsException(AuthorizationException): # noqa: MOD025
|
||||
"""Raised when user lacks required team permissions for an action."""
|
||||
|
||||
def __init__(
|
||||
@@ -817,7 +817,7 @@ class InsufficientTeamPermissionsException(AuthorizationException): # noqa: MOD
|
||||
)
|
||||
|
||||
|
||||
class MaxTeamMembersReachedException(BusinessLogicException): # noqa: MOD-025
|
||||
class MaxTeamMembersReachedException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when store has reached maximum team members limit."""
|
||||
|
||||
def __init__(self, max_members: int, store_id: int):
|
||||
@@ -852,7 +852,7 @@ class TeamValidationException(ValidationException):
|
||||
self.error_code = "TEAM_VALIDATION_FAILED"
|
||||
|
||||
|
||||
class InvalidInvitationDataException(ValidationException): # noqa: MOD-025
|
||||
class InvalidInvitationDataException(ValidationException): # noqa: MOD025
|
||||
"""Raised when team invitation data is invalid."""
|
||||
|
||||
def __init__(
|
||||
@@ -963,7 +963,7 @@ class StoreDomainAlreadyExistsException(ConflictException):
|
||||
)
|
||||
|
||||
|
||||
class InvalidDomainFormatException(ValidationException): # noqa: MOD-025
|
||||
class InvalidDomainFormatException(ValidationException): # noqa: MOD025
|
||||
"""Raised when domain format is invalid."""
|
||||
|
||||
def __init__(self, domain: str, reason: str = "Invalid domain format"):
|
||||
@@ -1020,7 +1020,7 @@ class DomainAlreadyVerifiedException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class MultiplePrimaryDomainsException(BusinessLogicException): # noqa: MOD-025
|
||||
class MultiplePrimaryDomainsException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to set multiple primary domains."""
|
||||
|
||||
def __init__(self, store_id: int):
|
||||
@@ -1054,7 +1054,7 @@ class MaxDomainsReachedException(BusinessLogicException):
|
||||
)
|
||||
|
||||
|
||||
class UnauthorizedDomainAccessException(BusinessLogicException): # noqa: MOD-025
|
||||
class UnauthorizedDomainAccessException(BusinessLogicException): # noqa: MOD025
|
||||
"""Raised when trying to access domain that doesn't belong to store."""
|
||||
|
||||
def __init__(self, domain_id: int, store_id: int):
|
||||
|
||||
@@ -103,7 +103,7 @@ class MerchantDomain(Base, TimestampMixin):
|
||||
- EXAMPLE.COM -> example.com
|
||||
"""
|
||||
# Remove protocol
|
||||
domain = domain.replace("https://", "").replace("http://", "") # SEC-034
|
||||
domain = domain.replace("https://", "").replace("http://", "") # noqa: SEC034
|
||||
|
||||
# Remove trailing slash
|
||||
domain = domain.rstrip("/")
|
||||
|
||||
@@ -92,7 +92,7 @@ class StoreDomain(Base, TimestampMixin):
|
||||
- EXAMPLE.COM -> example.com
|
||||
"""
|
||||
# Remove protocol
|
||||
domain = domain.replace("https://", "").replace("http://", "") # SEC-034
|
||||
domain = domain.replace("https://", "").replace("http://", "") # noqa: SEC034
|
||||
|
||||
# Remove trailing slash
|
||||
domain = domain.rstrip("/")
|
||||
|
||||
@@ -34,7 +34,7 @@ class MerchantDomainCreate(BaseModel):
|
||||
def validate_domain(cls, v: str) -> str:
|
||||
"""Validate and normalize domain."""
|
||||
# Remove protocol if present
|
||||
domain = v.replace("https://", "").replace("http://", "") # SEC-034
|
||||
domain = v.replace("https://", "").replace("http://", "") # noqa: SEC034
|
||||
|
||||
# Remove trailing slash
|
||||
domain = domain.rstrip("/")
|
||||
|
||||
@@ -35,7 +35,7 @@ class StoreDomainCreate(BaseModel):
|
||||
def validate_domain(cls, v: str) -> str:
|
||||
"""Validate and normalize domain."""
|
||||
# Remove protocol if present
|
||||
domain = v.replace("https://", "").replace("http://", "") # SEC-034
|
||||
domain = v.replace("https://", "").replace("http://", "") # noqa: SEC034
|
||||
|
||||
# Remove trailing slash
|
||||
domain = domain.rstrip("/")
|
||||
|
||||
@@ -255,7 +255,7 @@ class TestAdminPlatformServiceQueries:
|
||||
another_admin = User(
|
||||
email="another_padmin@example.com",
|
||||
username="another_padmin",
|
||||
hashed_password=auth_manager.hash_password("pass"), # noqa: SEC-001
|
||||
hashed_password=auth_manager.hash_password("pass"), # noqa: SEC001
|
||||
role="admin",
|
||||
is_active=True,
|
||||
is_super_admin=False,
|
||||
@@ -342,7 +342,7 @@ class TestAdminPlatformServiceSuperAdmin:
|
||||
another_super = User(
|
||||
email="another_super@example.com",
|
||||
username="another_super",
|
||||
hashed_password=auth_manager.hash_password("pass"), # noqa: SEC-001
|
||||
hashed_password=auth_manager.hash_password("pass"), # noqa: SEC001
|
||||
role="admin",
|
||||
is_active=True,
|
||||
is_super_admin=True,
|
||||
@@ -416,7 +416,7 @@ class TestAdminPlatformServiceCreatePlatformAdmin:
|
||||
db=db,
|
||||
email="new_padmin@example.com",
|
||||
username="new_padmin",
|
||||
password="securepass123", # noqa: SEC-001
|
||||
password="securepass123", # noqa: SEC001
|
||||
platform_ids=[test_platform.id, another_platform.id],
|
||||
created_by_user_id=test_super_admin.id,
|
||||
first_name="New",
|
||||
@@ -444,7 +444,7 @@ class TestAdminPlatformServiceCreatePlatformAdmin:
|
||||
db=db,
|
||||
email=test_platform_admin.email, # Duplicate
|
||||
username="unique_username",
|
||||
password="securepass123", # noqa: SEC-001
|
||||
password="securepass123", # noqa: SEC001
|
||||
platform_ids=[test_platform.id],
|
||||
created_by_user_id=test_super_admin.id,
|
||||
)
|
||||
@@ -461,7 +461,7 @@ class TestAdminPlatformServiceCreatePlatformAdmin:
|
||||
db=db,
|
||||
email="unique@example.com",
|
||||
username=test_platform_admin.username, # Duplicate
|
||||
password="securepass123", # noqa: SEC-001
|
||||
password="securepass123", # noqa: SEC001
|
||||
platform_ids=[test_platform.id],
|
||||
created_by_user_id=test_super_admin.id,
|
||||
)
|
||||
|
||||
@@ -87,7 +87,7 @@ def pending_invitation(db, team_store, test_user, auth_manager):
|
||||
new_user = User(
|
||||
email=f"pending_{unique_id}@example.com",
|
||||
username=f"pending_{unique_id}",
|
||||
hashed_password=auth_manager.hash_password("temppass"), # noqa: SEC-001
|
||||
hashed_password=auth_manager.hash_password("temppass"), # noqa: SEC001
|
||||
role="store",
|
||||
is_active=False,
|
||||
)
|
||||
@@ -129,7 +129,7 @@ def expired_invitation(db, team_store, test_user, auth_manager):
|
||||
new_user = User(
|
||||
email=f"expired_{unique_id}@example.com",
|
||||
username=f"expired_{unique_id}",
|
||||
hashed_password=auth_manager.hash_password("temppass"), # noqa: SEC-001
|
||||
hashed_password=auth_manager.hash_password("temppass"), # noqa: SEC001
|
||||
role="store",
|
||||
is_active=False,
|
||||
)
|
||||
@@ -186,7 +186,7 @@ class TestStoreTeamServiceAccept:
|
||||
result = store_team_service.accept_invitation(
|
||||
db=db,
|
||||
invitation_token=pending_invitation.invitation_token,
|
||||
password="newpassword123", # noqa: SEC-001
|
||||
password="newpassword123", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
@@ -203,7 +203,7 @@ class TestStoreTeamServiceAccept:
|
||||
store_team_service.accept_invitation(
|
||||
db=db,
|
||||
invitation_token="invalid_token_12345",
|
||||
password="password123", # noqa: SEC-001
|
||||
password="password123", # noqa: SEC001
|
||||
)
|
||||
|
||||
def test_accept_invitation_already_accepted(self, db, team_member):
|
||||
@@ -213,7 +213,7 @@ class TestStoreTeamServiceAccept:
|
||||
store_team_service.accept_invitation(
|
||||
db=db,
|
||||
invitation_token="some_token", # team_member has no token
|
||||
password="password123", # noqa: SEC-001
|
||||
password="password123", # noqa: SEC001
|
||||
)
|
||||
|
||||
def test_accept_invitation_expired(self, db, expired_invitation):
|
||||
@@ -222,7 +222,7 @@ class TestStoreTeamServiceAccept:
|
||||
store_team_service.accept_invitation(
|
||||
db=db,
|
||||
invitation_token=expired_invitation.invitation_token,
|
||||
password="password123", # noqa: SEC-001
|
||||
password="password123", # noqa: SEC001
|
||||
)
|
||||
|
||||
assert "expired" in str(exc_info.value).lower()
|
||||
|
||||
@@ -17,7 +17,7 @@ class TestUserModel:
|
||||
user = User(
|
||||
email="db_test@example.com",
|
||||
username="dbtest",
|
||||
hashed_password="hashed_password_123", # noqa: SEC-001
|
||||
hashed_password="hashed_password_123", # noqa: SEC001
|
||||
role="user",
|
||||
is_active=True,
|
||||
)
|
||||
@@ -39,7 +39,7 @@ class TestUserModel:
|
||||
user1 = User(
|
||||
email="unique@example.com",
|
||||
username="user1",
|
||||
hashed_password="hash1", # noqa: SEC-001
|
||||
hashed_password="hash1", # noqa: SEC001
|
||||
)
|
||||
db.add(user1)
|
||||
db.commit()
|
||||
@@ -49,7 +49,7 @@ class TestUserModel:
|
||||
user2 = User(
|
||||
email="unique@example.com",
|
||||
username="user2",
|
||||
hashed_password="hash2", # noqa: SEC-001
|
||||
hashed_password="hash2", # noqa: SEC001
|
||||
)
|
||||
db.add(user2)
|
||||
db.commit()
|
||||
@@ -59,7 +59,7 @@ class TestUserModel:
|
||||
user1 = User(
|
||||
email="user1@example.com",
|
||||
username="sameusername",
|
||||
hashed_password="hash1", # noqa: SEC-001
|
||||
hashed_password="hash1", # noqa: SEC001
|
||||
)
|
||||
db.add(user1)
|
||||
db.commit()
|
||||
@@ -69,7 +69,7 @@ class TestUserModel:
|
||||
user2 = User(
|
||||
email="user2@example.com",
|
||||
username="sameusername",
|
||||
hashed_password="hash2", # noqa: SEC-001
|
||||
hashed_password="hash2", # noqa: SEC001
|
||||
)
|
||||
db.add(user2)
|
||||
db.commit()
|
||||
@@ -79,7 +79,7 @@ class TestUserModel:
|
||||
user = User(
|
||||
email="defaults@example.com",
|
||||
username="defaultuser",
|
||||
hashed_password="hash", # noqa: SEC-001
|
||||
hashed_password="hash", # noqa: SEC001
|
||||
)
|
||||
db.add(user)
|
||||
db.commit()
|
||||
@@ -93,7 +93,7 @@ class TestUserModel:
|
||||
user = User(
|
||||
email="optional@example.com",
|
||||
username="optionaluser",
|
||||
hashed_password="hash", # noqa: SEC-001
|
||||
hashed_password="hash", # noqa: SEC001
|
||||
first_name="John",
|
||||
last_name="Doe",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user