Python SDK
The Python 3.9+ package is dycrypt-license, imported as dycrypt_license. Its only runtime dependency is cryptography.
Install
Section titled “Install”Until the package is published to PyPI, install it from the DYCRYPT SDK checkout:
pip install /path/to/dycrypt/sdk/pythonThe drop-in module at sdk/python/dropin/dycrypt_license.py exposes the same API.
Print a machine fingerprint
Section titled “Print a machine fingerprint”import sysfrom dycrypt_license import fingerprint
if "--fingerprint" in sys.argv: print(fingerprint()) raise SystemExit(0)Use this before issuing a Full Offline or offline-activated Hybrid licence.
Configure one verifier
Section titled “Configure one verifier”from dycrypt_license import LicenseVerifier, OnlinePolicy
with open("product-public-key.pem", encoding="utf-8") as handle: public_key_pem = handle.read()
verifier = LicenseVerifier( public_key_pem, "your-product-key", issuer_url="https://app.dycrypt.com", org_slug="your-org-slug", online_policy=OnlinePolicy.ADVISORY, timeout=5.0, state_path="/var/lib/your-app/dycrypt-state.json",)Omit the issuer settings and state_path for Full Offline. Build the verifier once and share it safely between threads.
state_path preserves successful-check timestamps across application restarts. Protect that file with the same operating-system permissions as other application state.
Full Offline
Section titled “Full Offline”with open("customer.lic", encoding="utf-8") as handle: result = verifier.verify(handle.read())enforce(result)Full Online and Hybrid
Section titled “Full Online and Hybrid”with open("customer.lic", encoding="utf-8") as handle: result = verifier.check(handle.read())enforce(result)check() is blocking. Run it at startup and from the background schedule your application owns. The SDK performs local verification before any request is made.
Handle every status
Section titled “Handle every status”from dycrypt_license import LicenseStatus
def enforce(result): if result.status == LicenseStatus.ACTIVE: return if result.status == LicenseStatus.GRACE: print("Licence is inside its expiry grace period") return if result.status == LicenseStatus.STALE: raise SystemExit("Reconnect to refresh the licence status") if result.status == LicenseStatus.PENDING: raise SystemExit("Licence starts at %s" % result.starts_at) raise SystemExit("Unlicensed (%s): %s" % (result.status, result.reason))ACTIVE and GRACE are the only statuses where result.valid is true.
Read product claims
Section titled “Read product claims”max_users = result.integer("maxUsers", 5)edition = result.string("edition", "standard")export_enabled = result.boolean("exportEnabled", False)features = result.string_list("features", [])Typed accessors never coerce a wrong JSON type. They return the fallback you provide.