Coverage for src / lexigram / contracts / tenancy / types.py: 0%

27 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-15 18:57 +0800

1"""Tenancy value types.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass, field 

6from datetime import datetime 

7from enum import Enum 

8from typing import Any 

9 

10 

11class TenantStatus(str, Enum): 

12 """Lifecycle status of a tenant. 

13 

14 Attributes: 

15 ACTIVE: Tenant is fully operational and accepts requests. 

16 INACTIVE: Tenant has been deactivated and no longer accepts requests. 

17 SUSPENDED: Tenant has been suspended (e.g. for non-payment) and is 

18 temporarily blocked from accessing the system. 

19 PROVISIONING: Tenant is being created; isolation resources are being 

20 set up. 

21 """ 

22 

23 ACTIVE = "active" 

24 INACTIVE = "inactive" 

25 SUSPENDED = "suspended" 

26 PROVISIONING = "provisioning" 

27 

28 

29@dataclass(frozen=True) 

30class TenantInfo: 

31 """Core tenant identity record. 

32 

33 The ``config`` field here is the tenant's *static* provisioning config 

34 (plan limits, feature flags set at creation time). Runtime per-tenant 

35 overrides are managed separately by ``TenantConfigProviderProtocol`` / 

36 ``TenantConfigService``. The two are independent — ``TenantInfo.config`` 

37 is a snapshot stored alongside the tenant record; ``TenantConfigService`` 

38 is a live, cached, key-value overlay. 

39 

40 Attributes: 

41 tenant_id: Unique identifier for the tenant. 

42 slug: URL-safe, human-readable identifier (e.g. ``acme-corp``). 

43 name: Display name of the tenant. 

44 status: Current lifecycle status. 

45 plan: Subscription plan name (optional). 

46 config: Static provisioning configuration snapshot. 

47 metadata: Arbitrary application-defined metadata. 

48 created_at: Timestamp when the tenant was created. 

49 """ 

50 

51 tenant_id: str 

52 slug: str 

53 name: str 

54 status: TenantStatus 

55 plan: str | None = None 

56 config: dict[str, Any] = field(default_factory=dict) 

57 metadata: dict[str, Any] = field(default_factory=dict) 

58 created_at: datetime | None = None 

59 

60 

61@dataclass(frozen=True) 

62class TenantResolutionContext: 

63 """Immutable snapshot of request data available for tenant resolution. 

64 

65 Passed to every :class:`~lexigram.contracts.tenancy.protocols.TenantResolverProtocol` 

66 during the resolution chain so resolvers can inspect request metadata 

67 without depending on any web framework type. 

68 

69 Attributes: 

70 headers: HTTP request headers (lowercased keys). 

71 host: The ``Host`` header value (e.g. ``acme.app.com``). 

72 path: The request path (e.g. ``/api/tenants/acme/users``). 

73 claims: Decoded JWT claims from the current authentication context. 

74 """ 

75 

76 headers: dict[str, str] 

77 host: str | None = None 

78 path: str | None = None 

79 claims: dict[str, Any] = field(default_factory=dict) 

80 

81 

82__all__ = [ 

83 "TenantInfo", 

84 "TenantResolutionContext", 

85 "TenantStatus", 

86]