Not legal advice
dpdpkit is software that helps you implement obligations under India's Digital Personal Data Protection Act, 2023 and the DPDP Rules, 2025. It does not provide legal advice and does not guarantee compliance.
Models and errors¶
Pydantic v2 models for every dpdpkit aggregate. Every model carries tenant_id.
No ORM type ever crosses the repository boundary; adapters convert rows to these models.
OPEN_REQUEST_STATUSES
module-attribute
¶
OPEN_REQUEST_STATUSES = frozenset({RequestStatus.RECEIVED, RequestStatus.IDENTITY_PENDING, RequestStatus.IN_PROGRESS})
ACTIVE_SCHEDULE_STATUSES
module-attribute
¶
ACTIVE_SCHEDULE_STATUSES = frozenset({ScheduleStatus.SCHEDULED, ScheduleStatus.WARNING_PENDING, ScheduleStatus.WARNED, ScheduleStatus.HELD, ScheduleStatus.NEEDS_ATTENTION})
TenantModel
¶
Bases: _Model
LegalBasis
¶
Bases: str, Enum
Why processing is lawful: consent, or one of the legitimate uses in DPDP Act s.7.
ConsentAction
¶
ConsentStatus
¶
RequestKind
¶
Bases: str, Enum
RequestStatus
¶
Bases: str, Enum
ScheduleStatus
¶
Bases: str, Enum
RetentionTrigger
¶
Channel
¶
DeliveryStatus
¶
Role
¶
DataItem
¶
Bases: TenantModel
Processor
¶
Bases: TenantModel
DataStore
¶
Bases: TenantModel
RetentionRule
¶
Bases: TenantModel
trigger
class-attribute
instance-attribute
¶
trigger: RetentionTrigger = RetentionTrigger.LAST_ACTIVITY
period_days
class-attribute
instance-attribute
¶
period_days: int | None = Field(default=None, ge=0)
third_schedule_class
class-attribute
instance-attribute
¶
third_schedule_class: str | None = None
When set, the period comes from the policy pack's Third Schedule entry for this class.
Purpose
¶
Bases: TenantModel
NoticePurpose
¶
Bases: _Model
NoticeContent
¶
Bases: _Model
Notice
¶
Bases: TenantModel
ConsentEvent
¶
Bases: TenantModel
metadata
class-attribute
instance-attribute
¶
metadata: dict[str, Any] = Field(default_factory=dict)
AuditEntry
¶
Bases: TenantModel
ConsentState
¶
Bases: TenantModel
ConsentReceipt
¶
Bases: TenantModel
LedgerVerification
¶
Bases: TenantModel
RootHash
¶
Bases: TenantModel
RightsRequest
¶
Bases: TenantModel
response_contact
class-attribute
instance-attribute
¶
response_contact: dict[str, str] | None = None
Grievance
¶
Bases: RightsRequest
A rights request of kind grievance; kept as a distinct type for adapters that want one.
Nominee
¶
Bases: TenantModel
IdentityCheck
¶
SlaStatus
¶
ErasureSchedule
¶
Bases: TenantModel
processor_fanout
class-attribute
instance-attribute
¶
processor_fanout: dict[str, str] = Field(default_factory=dict)
LegalHold
¶
Bases: TenantModel
purpose
class-attribute
instance-attribute
¶
purpose: str | None = None
None holds every purpose for the principal.
ErasureRun
¶
Bases: TenantModel
PreviewItem
¶
Bases: _Model
Contact
¶
Message
¶
Bases: _Model
DeliveryReceipt
¶
Bases: TenantModel
deprecation
¶
Deprecation helpers used by every dpdpkit package (see "Deprecation policy" in the docs).
A deprecated API keeps working for at least two minor releases (and at least 90 days) after the release
that deprecates it, warns with DpdpkitDeprecationWarning every time it is used, and is listed
under "Deprecated" in the changelog.
Functions, methods and classes are marked with PEP 702 so type checkers report callers too. The message must be a string literal (mypy ignores computed messages) in the standard wording::
from typing_extensions import deprecated
@deprecated(
"Ledger.export_roots() is deprecated since dpdpkit 0.3 and will be removed in 0.5; "
"use Ledger.export_root() instead",
category=DpdpkitDeprecationWarning,
)
def export_roots(self): ...
Parameters, config keys and renamed module attributes use warn_deprecated and moved.
DpdpkitDeprecationWarning
¶
Bases: DeprecationWarning
Something you use will be removed in a later dpdpkit release. The message says what replaces it.
Python hides DeprecationWarning outside __main__ and test runners; to see these everywhere,
run with -W always::dpdpkit.DpdpkitDeprecationWarning.
warn_deprecated
¶
warn_deprecated(name: str, *, since: str, removed_in: str, use: str | None = None, stacklevel: int = 3) -> None
Warn about a deprecated parameter, config key or value from inside the code that still accepts it.
stacklevel=3 points at the caller of the function that calls this helper.
moved
¶
moved(module_name: str, renames: dict[str, tuple[str, Any, str, str]]) -> Callable[[str], Any]
Build a module __getattr__ that keeps old names importable with a warning.
renames maps an old attribute name to (new dotted name, object, since, removed_in)::
__getattr__ = moved(__name__, {"OldName": ("dpdpkit.models.NewName", NewName, "0.3", "0.5")})
deprecation_message
¶
deprecation_message(name: str, *, since: str, removed_in: str, use: str | None = None) -> str
Exceptions raised by dpdpkit. Each carries a stable code used in REST error bodies.
DpdpkitError
¶
DpdpkitError(message: str, **details: Any)
PolicyError
¶
PolicyError(message: str, **details: Any)
SequenceConflict
¶
SequenceConflict(message: str, **details: Any)
Bases: DpdpkitError
Raised by a repository when two writers race for the same ledger sequence number.
LedgerTampered
¶
LedgerTampered(row_id: str, chain: str, reason: str)
Bases: DpdpkitError
verify() found a row whose hash or chain link does not match.