> For the complete documentation index, see [llms.txt](https://docs.licensespring.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.licensespring.com/sdks/python-sdk/python-sdk.md).

# Python SDK

The LicenseSpring Python Library provides convenient access to the LicenseSpring API from applications written in the Python language.

## Installation

Install `licensespring` library:

```bash
pip install licensespring
```

Requires: Python >=3.9

## Set app version

```python
import licensespring

licensespring.app_version = "MyApp 1.0.0"
```

## Hardware (Device) IDs

This library provides preconfigured hardware identity providers:

* `HardwareIdProvider` (default)
* `PlatformIdProvider`
* `HardwareIdProviderSource` (recommended)

You can set the desired hardware identity provider when initializing the [**Configuration**](#configuration-setup):

```python
from licensespring.hardware import PlatformIdProvider
from licensespring.licensefile.config import Configuration

conf = Configuration(product="your_product_short_code", hardware_id_provider=PlatformIdProvider)
```

It also supports their customization and creation of your own hardware ID provider.

### HardwareIdProvider

Uses [uuid.getnode()](https://docs.python.org/3/library/uuid.html#uuid.getnode) to generate unique ID per device as described:

> Get the hardware address as a 48-bit positive integer. The first time this runs, it may launch a separate program, which could be quite slow. If all attempts to obtain the hardware address fail, we choose a random 48-bit number with the multicast bit (least significant bit of the first octet) set to 1 as recommended in RFC 4122. “Hardware address” means the MAC address of a network interface. On a machine with multiple network interfaces, universally administered MAC addresses (i.e. where the second least significant bit of the first octet is unset) will be preferred over locally administered MAC addresses, but with no other ordering guarantees.

All of the methods exposed by `HardwareIdProvider`:

```python
class HardwareIdProvider:
    def get_id(self):
        return str(uuid.getnode())

    def get_os_ver(self):
        return platform.platform()

    def get_hostname(self):
        return platform.node()

    def get_ip(self):
        return socket.gethostbyname(self.get_hostname())

    def get_is_vm(self):
        return False

    def get_vm_info(self):
        return None

    def get_mac_address(self):
        return ":".join(("%012X" % uuid.getnode())[i : i + 2] for i in range(0, 12, 2))

    def get_request_id(self):
        return str(uuid.uuid4())
```

### HardwareIdProviderSource

Utilizes a proprietary in-house algorithm for our SDKs **(recommended algorithm)** [Hardware ID Algorithm](https://pypi.org/project/licensespring-hardware-id-generator/).

```python
class HardwareIdProviderSource(HardwareIdProvider):
    def get_id(self):
        hardware_id = get_hardware_id(HardwareIdAlgorithm.Default)

        if logging.getLogger().hasHandlers():
            logs = get_logs()
            version = get_version()
            logging.info("Version: ",version)
            logging.info("Hardware ID:",hardware_id)
            for log_line in logs:
                logging.info(log_line)

        return hardware_id
```

### PlatformIdProvider

Uses [sys.platform](https://docs.python.org/3/library/sys.html#sys.platform) and OS queries to find the raw GUID of the device.

Extends the `HardwareIdProvider` and overwrites only the `get_id` method:

```python
class PlatformIdProvider(HardwareIdProvider):
    def get_id(self):
        id = None

        if sys.platform == 'darwin':
            id = execute("ioreg -d2 -c IOPlatformExpertDevice | awk -F\\\" '/IOPlatformUUID/{print $(NF-1)}'")

        if sys.platform == 'win32' or sys.platform == 'cygwin' or sys.platform == 'msys':
            id = read_win_registry('HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography', 'MachineGuid')
            if not id:
                id = execute('wmic csproduct get uuid').split('\n')[2].strip()

        if sys.platform.startswith('linux'):
            id = read_file('/var/lib/dbus/machine-id')
            if not id:
                id = read_file('/etc/machine-id')

        if sys.platform.startswith('openbsd') or sys.platform.startswith('freebsd'):
            id = read_file('/etc/hostid')
            if not id:
                id = execute('kenv -q smbios.system.uuid')

        if not id:
            id = super().get_id()

        return id
```

### Customization

Extend any of the preconfigured hardware identity providers, overwrite the methods you want and provide it when initializing the [**Configuration**](#configuration-setup):

```python
class CustomHardwareIdProvider(HardwareIdProvider):
    def get_id(self):
        return "_my_id_"

conf = Configuration(product="your_product_short_code", hardware_id_provider=CustomHardwareIdProvider)
```

## Licensefile

### Licensefile setup

The licensefile is encrypted (AES-256-GCM) automatically; no manual key/IV setup is required. The encryption password is derived from your `shared_key` (API keys) or `client_secret` (OAuth). `file_key`/`file_iv` on [**Configuration**](#configuration-setup) are optional overrides, only needed if you're migrating a licensefile created with a custom key/IV on an older SDK version.

### Configuration Setup

```python
from licensespring.licensefile.config import Configuration

conf = Configuration(product="your_product_short_code",
        api_key="your_api_key",
        shared_key="your_shared_key",
        file_key=None,
        file_iv=None,
        hardware_id_provider=HardwareIdProviderSource,
        verify_license_signature=True,
        signature_verifier=SignatureVerifier,
        api_domain="api.licensespring.com",
        api_version="v4",
        filename="License",
        file_path=None,
        file_extension="key",
        grace_period_conf=24,
        air_gap_public_key="your_air_gap_public_key",
        client_id="your_client_id",
        client_secret="your_client_secret",
        certificate_chain_path="path_to_certificate/chain.pem",
        enable_airgapped_skip_time_check=False,
        enable_process_safety=False,
        tpm_enabled=False)
```

* **product (str)**: product short code.
* **api\_key (str,optional)**: Your unique API key used for authentication with the licensing server.
* **shared\_key (str,optional)**: A shared secret key used alongside the API key for enhanced security during the license verification process.
* **file\_key (str, optional)**: Only needed when migrating a licensefile created with a custom key on an older SDK version; otherwise the password is derived automatically from `shared_key`/`client_secret`. See [**Licensefile setup**](#licensefile-setup).
* **file\_iv (str, optional)**: Used alongside `file_key` for the same migration case.
* **hardware\_id\_provider (object, optional)**: The provider class used for generating a unique hardware ID. This ID helps in binding the license to specific hardware. Defaults to `HardwareIdProviderSource`.
* **verify\_license\_signature (bool, optional)**: A boolean flag indicating whether the license's digital signature should be verified. Defaults to True for enhanced security.
* **signature\_verifier (object, optional)**: The class responsible for verifying the digital signature of licenses. Defaults to SignatureVerifier.
* **api\_domain (str, optional)**: The domain name of the API server with which the licensing operations are performed. Defaults to "api.licensespring.com".
* **api\_version (str, optional)**: The version of the API to use for requests. This allows for compatibility with different versions of the licensing API. Defaults to "v4".
* **filename (str, optional)**: The default filename for saved license files. This can be customized as needed. Defaults to "License".
* **file\_path (str, optional)**: The path where license files should be saved on the client system. If not specified, a [**default location**](https://docs.licensespring.com/sdks/tutorials/best-practices/local-license-file#W8U6X) is used.
* **file\_extension (str, optional)**: The extension used for the saved license file, without the leading dot. Defaults to "key" (e.g. "License.key"). The lock file used for cross-process safety is derived from this too (e.g. "License.key.lock").
* **grace\_period\_conf (int, optional)**: The number of hours to allow as a grace period for Defaults to 24 hours.
* **air\_gap\_public\_key (str, optional)**: Air gap public key from platform check [**here**](https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/air-gapped#Ws1BB) for more
* **client\_id (str, optional)**: Client ID for OAuth authorization purposes
* **client\_secret (str, optional)**: Client Secret for OAuth authorization purposes
* **certificate\_chain\_path (str, optional)**: Used for singature verification for Floating Server v2 (e.g "path\_to\_cert\_chain/chain.pem"). This file is provided by the platform.
* **enable\_airgapped\_skip\_time\_check** (bool, optional): When set to True, SDK would skip checking date time with airgap licenses, until turned on again.
* **enable\_process\_safety (bool, optional)**: Opt-in flag for cross-process-safe licensefile writes (advisory OS-level file locking). Defaults to False: the SDK does not acquire or wait on any lock.
* **tpm\_enabled (bool, optional)**: Opt-in flag to bind the license to this device's TPM/Secure Enclave key pair in addition to the hardware ID. Defaults to False.

{% hint style="warning" %}

* `hardware_id_provider` now defaults to [`HardwareIdProviderSource`](#hardwareidprovidersource); pass `hardware_id_provider=HardwareIdProvider` explicitly if you need the legacy provider.
* if both **API keys** and **OAuth** is specified SDK will use OAuth for authorization
  {% endhint %}

### LicenseID

* **from\_key(cls, key)**: Class method to create a LicenseID instance for key-based activation
* **from\_user(cls, username, password)**: Class method to create a LicenseID instance for user-based activation.

#### Key-based setup

```python
license_id = LicenseID.from_key("your_license_key")
```

#### User-based setup

```python
license_id = LicenseID.from_user(username="email@email.com",password="password")
```

### LicenseManager

```python
from licensespring.licensefile.license_manager import LicenseManager,LicenseID

manager = LicenseManager(conf)
```

#### Configuration parameters

conf (Configuration): [**A configuration object**](#configuration-setup)

#### Activation methods

Methods for activating a license, grouped by whether they require a live connection to the license server (Online) or not (Offline).

**Online**

**activate\_license**

Activates a license with the license server and updates local license data. When activating user based license we advise that **unique\_license\_id** is set which represent **"id"** field within the [license check](https://docs.licensespring.com/license-api/check).

{% tabs %}
{% tab title="Key-based" %}

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H6QM-6H5R-ZENJ-VBLK")

license = manager.activate_license(license_id)
```

{% endtab %}

{% tab title="User-based" %}

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_user(username="python@gmail.com",password="7t_x3!o9")

license = manager.activate_license(license_id,unique_license_id=1723642193958949)
```

{% endtab %}
{% endtabs %}

**Parameters**:

* **license\_id** (LicenseID): An instance containing the license key or user credentials.
* **bundle\_code** (str, optional): specify unique bundle\_code of a bundle
* **hardware\_id** (str, optional): A unique identifier for the hardware.
* **unique\_license\_id** (int, optional): A unique identifier for the license.
* **customer\_account\_code** (str, optional): An account code for the customer.
* **redirect\_uri** (str, optional): redirect\_uri. Defaults to None.
* **id\_token** (str, optional): Token for identity verification.
* **code** (str, optional): An additional code for license verification.
* **app\_ver** (str, optional): The version of the application requesting activation.
* **os\_ver** (str, optional): The operating system version of the host.
* **hostname** (str, optional): The hostname of the device requesting activation.
* **ip** (str, optional): The IP address of the device.
* **is\_vm** (bool, optional): Indicates whether the application is running on a virtual machine.
* **vm\_info** (str, optional): Information about the virtual machine, if applicable.
* **mac\_address** (str, optional): The MAC address of the device.

**Return**: **License** object representing the activated license.

**Offline**

**create\_offline\_activation\_file**

Creates .req file for offline activation, including various optional parameters related to the device and software environment.

**Parameters**:

* **license\_id** (LicenseID): An instance containing the license key or user credentials.
* **req\_path** (str): Specify the path where to create .req file.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H94R-S6KB-L7AJ-SXLK")

req_file_path = manager.create_offline_activation_file(license_id,'offline_files/test')
```

**Return** (str): Path of the .req file created for activation.

**activate\_license\_offline**

Activates a license offline using a .lic file provided via the specified path.

**Parameters**:

* **ls\_activation\_path** (str): Path to the activation file.

```python
file_path = 'offline_files/ls_activation.lic'

manager = LicenseManager(conf)

license = manager.activate_license_offline(file_path)
```

**Raises**:

* **LicenseActivationException**: Activation data is not valid.
* **LicenseActivationException**: Response file ID mismatch.
* **LicenseActivationException**: License does not belong to this device.

**Return** (License): Returns a License object representing the activated license.

**get\_air\_gap\_activation\_code**

Get activation code for air gap license.

**Parameters**:

* **initialization\_code** (str): initialization code
* **license\_key** (str): license key

```python
initialization_code = "Q/MWfwp1NWAYARl8Q7KSo5Cg2YKqS2QLlnQ3nEeSBsk="
license_key = "UFF3-E9GA-VUJQ-GMLK"

manager = LicenseManager(conf)
activation_code = manager.get_air_gap_activation_code(initialization_code=initialization_code, license_key=license_key)

print("Activation code:",activation_code)
```

**Return** (str): activation code

**activate\_air\_gap\_license**

Activate air gap license.

**Parameters**:

* **confirmation\_code** (str): confirmation code
* **policy\_path** (str): policy path (file or folder)
* **license\_key** (str): license\_key
* **policy\_id** (str): policy id

```python
confirmation = "ERbQBuE8giIjqMPj972Skipehqn0szQ8TH56INyo3OdtMHO1SuTVsoCOSnJWB6rml98PJ6SjybTPymOVZTG4hQ=="
policy_id = "998"
license_key = "UFF3-E9GA-VUJQ-GMLK"
policy_path = "path_to_air_lic"

manager = LicenseManager(conf)
license = manager.activate_air_gap_license(
                confirmation_code=confirmation, policy_path=policy_path, license_key=license_key, policy_id=policy_id
            )
```

**Raises**:

* **LicenseActivationException**: Signature verification failed

**Return** (License): License

#### load\_license

Loads the license file and sets attributes for the LicenseData instance. Returns an instance of the License class reflecting the loaded license.

```python
manager = LicenseManager(conf)

license = manager.load_license()
```

**Return**: **License** object representing the activated license.

#### reconfigure

Change the current configuration.

**Parameters**:

* **conf** (Configuration): Configuration object

```python
manager = LicenseManager(conf)

manager.reconfigure(
        Configuration(
            product="lkprod2",
            api_key="new_key",
            shared_key="new_key",
            file_key="file_key",
            file_iv="file_iv",
            file_path="bb",
            grace_period_conf=12,
            is_guard_file_enabled=True,
        )
    )
```

#### LicenseManager getters and utilities

Accessor and utility methods on the `LicenseManager` object, grouped by whether they read purely local data (Offline) or make a network call to the license server (Online). Used the same way as `manager.current_config()`.

**Offline**

* `current_config()` -> `dict`: Get current configuration
* `is_license_file_corrupted()` -> `bool`: Checks if the licensefile is corrupted
* `clear_local_storage()`: Clear all data from the current product
* `data_location()` -> `str`: Get licensefile location
* `set_data_location(path: str)`: Set data location
* `license_file_name()` -> `str`: Get licensefile name
* `set_license_file_name(name: str)`: Set licensefile name

**Online**

* `is_online(throw_e: bool = True)` -> `bool`: Checks if the licensing server is accessible
* `get_version_list(license_id: LicenseID, channel: str = None, unique_license_id: int = None, env: str = None)` -> `list`: Get the list of available versions for a license
* `get_product_details(include_latest_version: bool = False, include_custom_fields: bool = False, env: str = None)` -> `dict`: Get product details from the server
* `get_installation_file(license_id: LicenseID, unique_license_id: int = None, env: str = None, version: str = None, channel: str = None)` -> `dict`: Get the installation file for a version
* `get_customer_license_users(customer: Customer)` -> `dict`: Get the license users belonging to a customer
* `get_user_licenses(license_id: LicenseID = None, customer_account_code: str = None, id_token: str = None, code: str = None, redirect_uri: str = None)` -> `list`: Get the licenses belonging to a user
* `get_sso_url(account_code: str, use_auth_code: bool = True)` -> `dict`: Get the SSO url for a customer account

#### get\_trial\_license

Creates LicenseID for trial licenses.

**Parameters**:

* **customer** (Customer): Customer object
* **license\_policy** (str,optional): license policy code. Defaults to None.

```python
customer = Customer(email='python_policy@gmail.com')

manager = LicenseManager(conf)

license_id = manager.get_trial_license(customer=customer,license_policy='test')

license = manager.activate_license(license_id=license_id)
```

**Return** (LicenseID): Returns a LicenseID object.

### Bundle Manager

Object responsible for Bundle operations.

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.license_manager import LicenseID
from licensespring.licensefile.bundle_manager import BundleManager

conf = Configuration(
        product="your-product-code",
        api_key="your-api-key",
        shared_key="your-shared-key",
        file_key="d66db34b03c2d6961bb3e14ff40592c0c39ec7210113f194c0da50c2d4d002be",
        file_iv="a770af52b2aa3b73ad218b6cfc4e9707")

bundle_manager = BundleManager(conf)
```

#### Online

Methods that make a network call to the license server.

**activate\_bundle**

Activates the bundle.

**Parameters**:

* **license\_id** (LicenseID): An instance containing the license key or user credentials.
* **hardware\_id**(str, optional): A unique identifier for the hardware.
* **unique\_license\_id** (int, optional): A unique identifier for the license.
* **customer\_account\_code** (str, optional): An account code for the customer.
* **id\_token** (str, optional): Token for identity verification.
* **code** (str, optional): An additional code for license verification.
* **redirect\_uri** (str, optional): redirect\_uri. Defaults to None.
* **app\_ver** (str, optional): The version of the application requesting activation.
* **os\_ver** (str, optional): The operating system version of the host.
* **hostname** (str, optional): The hostname of the device requesting activation.
* **ip** (str, optional): The IP address of the device.
* **is\_vm** (bool, optional): Indicates whether the application is running on a virtual machine.
* **vm\_info** (str, optional): Information about the virtual machine, if applicable.
* **mac\_address** (str, optional): The MAC address of the device.

```python
#user based
license_id = LicenseID().from_user(username="ki@ki.com",password="!f53n!z2")
#key based
license_id = LicenseID().from_key("ASQU-AYHA-FX4S-FRLK")

bundles = bundle_manager.activate_bundle(license_id)
```

**Return (dict\[str, License])**: A dictionary where the keys are product short codes and the values are License objects.

**check\_bundle**

Check bundle and update the licensefile.

**Parameters**:

* **license\_id** (LicenseID): license\_id
* **hardware\_id**(str, optional): A unique identifier for the hardware. Defaults to None.
* **unique\_license\_id** (int, optional): A unique identifier for the license. Defaults to None.
* **include\_expired\_features** (bool, optional): If True, includes expired license features in the check. Defaults to False.
* **env** (str, optional): optional param takes "win", "win32", "win64", "mac", "linux", "linux32" or "linux64". Defaults to None.

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")
# make sure that bundle is activated
bundles = bundle_manager.check_bundle(license_id,"file_path")
```

**Returns (dict\[str, License])**: A dictionary where the keys are product short codes and the values are License objects.

**deactivate\_bundle**

Deactivate bundle.

**Parameters**:

* **license\_id** (LicenseID): license\_id
* **hardware\_id** (str, optional): hardware id. Defaults to None.
* **unique\_license\_id** (int, optional): A unique identifier for the license. Defaults to None.
* **remove\_local\_data** (bool, optional): remove licensefile from storage. Defaults to False.

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")

bundle_manager.deactivate_bundle(license_id,"file_path")
```

#### Offline

Methods that operate on local licensefile/cache data or offline activation files, without contacting the license server.

**get\_current\_bundle**

Get current bundle from cache or licensefile.

```python
bundles = bundle_manager.get_current_bundle()
```

**Return (dict\[str, License])**: A dictionary where the keys are product short codes and the values are License objects.

**create\_offline\_activation\_file**

Creates .req file for activation.

**Parameters**:

* **license\_id** (LicenseID): An instance containing the license key or user credentials.
* **req\_path** (str): Specify place where to create .req file
* **hardware\_id** (str, optional): A unique identifier for the hardware.
* **app\_ver** (str, optional): The version of the application requesting activation.
* **os\_ver** (str, optional): The operating system version of the host.
* **hostname** (str, optional): The hostname of the device requesting activation.
* **ip** (str, optional): The IP address of the device.
* **is\_vm** (bool, optional): Indicates whether the application is running on a virtual machine.
* **vm\_info** (str, optional): Information about the virtual machine.
* **mac\_address** (str, optional): The MAC address of the device.
* **device\_variables** (dict, optional): device variables.

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")

req_file_path = bundle_manager.create_offline_activation_file(license_id, "file_path")
```

**Return(str)**: path of the .req file

**activate\_bundle\_offline**

Activate offline bundle licenses.

**Parameters**:

* **ls\_activation\_path** (str): path to a .lic file

```python
bundle_manager.activate_bundle_offline("file_path_to_lic_file.lic")
```

**Return (dict\[str, License])**: dictionary of licenses in a bundle

**deactivate\_bundle\_offline**

Generates .req file for the offline deactivation.

**Parameters**:

* **license\_id** (LicenseID): license\_id
* **offline\_path** (str): path of the .req file
* **unique\_license\_id** (int): unique license id

```python
license_id = LicenseID.from_key("VNFT-7KPY-D5BQ-5NLK")
bundle_manager.deactivate_bundle_offline(license_id,"file_path")
```

**Return(str)**: path of the deactivation file

### License object

Object responsible for license operations.

#### License getters

Read-only accessors on the `License` object that return cached license data (no network calls or side effects), most taking no arguments, used the same way as `license.is_expired()`:

* `is_floating_expired()` -> `bool`: Determines whether the license's floating period has expired
* `floating_timeout()` -> `int`: Retrieve the license floating timeout
* `is_floating()` -> `bool`: Check if license is floating (Floating Server or Floating Cloud)
* `floating_client_id()` -> `str`: Get floating client id
* `is_controlled_by_floating_server()` -> `bool`: Check if license is controlled by Floating Server
* `floating_in_use_devices()` -> `int`: Number of floating devices in use
* `floating_end_date()` -> `datetime`: Datetime when the floating license will be released
* `max_floating_users()` -> `int`: Number of max floating users
* `is_validity_period_expired()` -> `bool`: Determines whether the license's validity period has expired
* `validity_period()` -> `datetime`: Gets validity period of the license
* `validity_with_grace_period()` -> `datetime`: Gets the validity period with grace period of the license
* `license_user()` -> `dict`: Gets the license user
* `maintenance_days_remaining()` -> `int`: Gets how many days are left until the maintenance ends
* `days_remaining()` -> `int`: Gets how many days are left until the validity period ends
* `customer_information()` -> `dict`: Gets customer information
* `id()` -> `int`: Gets license id
* `max_transfers()` -> `int`: Get the max transfers
* `transfer_count()` -> `int`: Get the transfer count
* `is_device_transfer_allowed()` -> `bool`: Get if the device transfer is allowed
* `is_device_transfer_limited()` -> `bool`: Get if the device transfer is limited
* `days_since_last_check()` -> `int`: Get how many days passed since last check
* `start_date()` -> `datetime`: Get the start date of the license
* `maintenance_period()` -> `datetime`: Get the maintenance period of the license
* `is_maintenance_period_expired()` -> `bool`: Checks if the maintenance period has expired
* `last_check()` -> `datetime`: Gets when the last check was performed
* `last_usage()` -> `datetime`: Gets when the license was last used
* `activation_date()` -> `datetime`: Gets when the license was last used
* `license_type()` -> `str`: Gets the license type
* `max_activations()` -> `int`: Gets the license max activations
* `metadata()` -> `dict`: Gets the license metadata
* `allow_unlimited_activations()` -> `bool`: Check if unlimited activations are allowed
* `allow_grace_subscription_period()` -> `bool`: Check if grace subscription period is allowed
* `is_subscription_grace_period_started()` -> `bool`: Check if grace subscription period has started
* `is_grace_period_started()` -> `bool`: Check if license is in grace period
* `grace_period_hours_remaining()` -> `int`: Get remain hours of grace period
* `get_grace_period()` -> `int`: Get grace period
* `subscription_grace_period()` -> `int`: Get subscription grace period
* `is_expired()` -> `bool`: Checks if the license validity has expired
* `license_enabled()` -> `bool`: Checks if the license is enabled
* `license_active()` -> `bool`: Checks if the license is active
* `is_valid()` -> `bool`: Checks if the license is valid (license is active, enabled and didn't expired)
* `prevent_vm()` -> `bool`: Checks if the license prevents virtual machines
* `is_trial()` -> `bool`: Checks if the license is trial
* `expiry_date()` -> `datetime`: Get expiry date of floating license
* `borrow_until()` -> `datetime`: Get the date until a license is borrowed
* `is_borrowed()` -> `bool`: Check if a license is borrowed
* `local_consumptions()` -> `int`: Get local consumptions
* `max_consumptions()` -> `int`: Get max consumptions
* `total_consumptions()` -> `int`: Get total consumptions
* `max_overages()` -> `int`: Get max overages
* `allow_unlimited_consumptions()` -> `int`: Check if unlimited consumptions is allowed
* `consumption_reset()` -> `bool`: Check if there is consumption reset
* `allow_overages()` -> `bool`: Check if overages are allowed
* `consumption_period()` -> `str`: Get consumption period
* `features()` -> `list`: Get feature list
* `get_product_details()` -> `dict`: Get product details from licensefile (offline)
* `custom_fields()` -> `list`: Get custom fields from licensefile -> `[{name, value},..]`
* `get_custom_field(field_name)` -> `dict`: Get a single custom field by name from licensefile -> `{name, value}`
* `is_tpm_auth()` -> `bool`: Check if license is bound to a TPM/Secure Enclave key pair
* `tpm_signing_public_key()` -> `str`: Get the TPM/Secure Enclave signing public key enrolled with the license
* `get_feature_data(feature_code)` -> `dict`: Get feature data
* `is_grace_period(ex)` -> `bool`: Determines if the current license state is within its grace period following a specific exception
* `get_device_variable(variable_name)` -> `dict`: Get device variable if exists

#### check\_license\_status

Verifies the current status of the license. It raises exceptions if the license is not enabled, not active, or expired.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check_license_status()
```

**Raises**: **LicenseStateException**: Raised if the license fails one of the following checks:

* License is not enabled.
* License is not active.
* License validity period has expired.

**Return**: None

#### check

Performs an online check to synchronize the license data with the backend. This includes syncing consumptions for consumption-based licenses.

**Parameters**:

* **include\_expired\_features (bool, optional)**: Includes expired license features in the check.
* **env (str, optional)**: "win", "win32", "win64", "mac", "linux", "linux32" or "linux64"

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

response=license.check()
```

**Raises**:

* **ClientError**: Raised if there's an issue with the API client's request, such as invalid credentials or unauthorized access.
* **RequestException**: Raised if there's a problem with the request to the licensing server, such as network issues or server unavailability.

**Return (dict)**: The updated license cache.

#### deactivate

Deactivates the license and optionally deletes the local license file.

**Parameters**:

* **delete\_license (bool, optional)**: If **True**, deletes the local license file upon deactivation.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.deactivate()
```

**Return**: None

#### local\_check

This method ensures the integrity and consistency of the licensing information by comparing the data stored in the local license file with the predefined configurations in the **Configuration object**.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.local_check()
```

**Raises**:

* **ConfigurationMismatch**: Raised if the product code or hardware ID in the license file does not match the expected values provided in the Configuration
* **VMIsNotAllowedException**: Raised if the license is used in a VM environment when the license explicitly disallows it.
* **TimeoutExpiredException**: Raised if a floating license has expired. This is more relevant if is\_floating\_expired is later implemented to perform actual checks.
* **ClockTamperedException**: Raised if there is evidence of tampering with the system's clock, detected by comparing the system's current time with the last usage time recorded in the license file.

**Return**: None

#### add\_local\_consumption

Adds local consumption records for **consumption-based licenses**.

**Parameters**:

* **consumptions (bool, optional)**: The number of consumptions to add locally

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.add_local_consumption()
```

**Raises**:

* **LicenseSpringTypeError**: Raised if the license type does not support consumption (i.e., not a consumption-based license).
* **ConsumptionError**: Raised if adding the specified number of consumptions would exceed the allowed maximum for the license.

**Return**: None

#### sync\_consumption

Synchronizes local consumption data with the server, adjusting for overages if specified.

**Parameters**:

* **req\_overages (int, optional)**: Specifies behavior for consumption overages.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.add_local_consumption(5)

license.sync_consumption()
```

**Raises**:

* **RequestException**: Raised if the request to synchronize consumption data with the server fails, for instance, due to network issues or server unavailability.

**Return (bool)**: True if the consumption data was successfully synchronized; False otherwise.

#### change\_password

Changes password of a user.

**Parameters**:

* **password** (str): Old password of license user
* **new\_password**(str): New password of license user

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_user(username="python@gmail.com",password="7t_x3!o9")

license = manager.activate_license(license_id)

license.change_password(password="7t_x3!o9",new_password="12345678")
```

**Return (str)**: "password\_changed"

#### setup\_license\_watch\_dog

Initializes and starts the license watchdog with the specified callback and timeout settings.

**Parameters**:

* **callback** (Callable): A callable to be executed by the watchdog in response to specific events or conditions.
* **timeout** (int): The period in minutes after which the watchdog should perform its checks.
* **deamon** (bool, optional): Run thread as deamon. Defaults to False.
* **run\_immediately** (bool,optional): run license check immediately, if False wait for timeout first.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_license_watch_dog(callback,timeout)
```

**Return**: None

#### stop\_license\_watch\_dog

Stops the license watchdog if it is currently running, effectively halting its monitoring and callback activities.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_license_watch_dog(callback,timeout)

license.stop_license_watch_dog()
```

**Return**: None

#### setup\_feature\_watch\_dog

Initializes and starts the feature watchdog with the specified callback and timeout.

**Parameters**:

* **callback** (Callable): A callable to be executed by the watchdog in response to specific events or conditions.
* **timeout** (int): The period in minutes after which the watchdog should perform its checks.
* **deamon** (bool, optional): Run thread as deamon. Defaults to False.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_feature_watch_dog(callback,timeout)
```

**Return**: None

#### stop\_feature\_watch\_dog

Stops the feature watchdog if it is currently running.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.setup_feature_watch_dog(callback,timeout)

license.stop_feature_watch_dog()
```

**Return**: None

#### add\_local\_feature\_consumption

Adds local consumption to the feature.

**Parameters**:

* **feature** (str): feature code.
* **consumptions** (int,optional): Number of consumptions.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.add_local_feature_consumption("lkprod1cf1",3)
```

**Raises**:

* **ItemNotFoundError**: If the feature specified by `feature_code` does not exist.
* **LicenseSpringTypeError**: If the identified feature is not of the "consumption" type.
* **ConsumptionError**: If adding the specified number of consumptions would exceed the feature's consumption limits.

**Return**: None

#### sync\_feature\_consumption

Synchronizes local consumption data with the server.

**Parameters**:

* **feature** (str): feature code.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.add_local_feature_consumption("lkprod1cf1",3)

license.sync_feature_consumption("lkprod1cf1")
```

**Return** (bool): True if the consumption data was successfully synchronized; False otherwise.

#### floating\_borrow

Attempts to borrow a floating license until the specified date, updating the system status based on the outcome of the borrow attempt.

**Parameters**:

* **borrow\_until** (str): A string representing the date until which the license should be borrowed.
* **password** (str,optional): Password for the license if required.
* **id\_token** (str, optional): id\_token. Defaults to None.
* **code** (str, optional): code. Defaults to None.
* **customer\_account\_code** (str, optional): customer account code. Defaults to None.
* **redirect\_uri** (str,optinal): redirect uri. Defaults to None.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.floating_borrow("2031-05-06T00:00:00Z")
```

**Return**: None

#### floating\_release

Releases a borrowed floating license and updates the license status accordingly.

**Parameters**:

* **throw\_e**(bool): A boolean indicating whether to raise an exception on failure.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check()

license.floating_release(False)
```

**Return**: None

#### check\_feature

Checks for a specific license feature and updates the license cache accordingly.

**Parameters**:

* **feature**(str): feature code.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check_feature("lkprod1f1fc1")
```

**Return**: None

#### release\_feature

Releases a borrowed license feature and updates the license cache accordingly.

**Parameters**:

* **feature**(str): feature code.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check_feature("lkprod1f1fc1")

license.release_feature("lkprod1f1fc1")
```

**Return**: None

#### borrow\_feature

Borrow license feature.

**Parameters**:

* **feature** (str): feature code
* **borrow\_until** (str): borrow until e.g "2029-05-06T00:00:00Z"
* **password**(str, optional): password. Defaults to None.
* **id\_token** (str, optional): id\_token. Defaults to None.
* **code** (str, optional): code. Defaults to None.
* **customer\_account\_code** (str, optional): customer account code. Defaults to None.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H7G3-F4PJ-4AEJ-UKYL")

license = manager.activate_license(license_id)

license.check_feature("lkprod1f1fc1")

license.borrow_feature("lkprod1f1fc1","2029-05-06T00:00:00Z")
```

**Return**: None

#### update\_offline

Updates license via refresh file.

**Parameters**:

* **path** (str): path of the refresh file
* **reset\_consumption** (bool): True resets consumption otherwise False

```python
file_path = 'path_to_lic_file/license.lic'

manager = LicenseManager(conf)

license = manager.activate_license_offline(file_path)

license.update_offline('offline_files/license_refresh.lic',False)
```

**Raises**:

* **ConfigurationMismatch**: The update file does not belong to this device
* **ConfigurationMismatch**: The update file does not belong to this product

**Return**(bool): True if license was successfully updated otherwise False

#### get\_deactivation\_code

Get deactivation code for air gap licenses.

**Parameters**:

* **initialization\_code** (str): initialization\_code

```python
initialization_code="your_initialization_code"
manager = LicenseManager(conf)
#load air gap license
license = manager.load_license()

deactivation_code = license.get_deactivation_code(initialization_code)

print("Deactivation code:",deactivation_code)
```

**Return** (str): deactivation code

#### deactivate\_air\_gap

Deactivate air gap license and clear storage.

**Parameters**:

* **confirmation\_code** (str): confirmation\_code

```python
confirmation_code="your_confirmation_code"
manager = LicenseManager(conf)
#load air gap license
license = manager.load_license()
license.deactivate_air_gap(confirmation_code)
```

**Raises**:

* **LicenseActivationException**: VerificationError

**Return**: None

#### deactivate\_offline

Generates .req file for the offline deactivation.

**Parameters**:

* **offline\_path**(str): path of the .req file
* **device\_variables** (dict): device variables

```python
file_path = 'path_to_lic_file/license.lic'

manager = LicenseManager(conf)

license = manager.activate_license_offline(file_path)

license.deactivate_offline('path_where_to_create_req_file')
```

**Raises**:

* **ConfigurationMismatch**: The update file does not belong to this device
* **ConfigurationMismatch**: The update file does not belong to this product

**Return**(bool): True if license was successfully updated otherwise False

#### product\_details

Update product details from LicenseSpring server.

**Parameters**:

* **include\_custom\_fields** (bool, optional): custom fields information. Defaults to False.
* **include\_latest\_version** (bool, optional): Lateset version information. Defaults to False.
* **env (str, optional)**: "win", "win32", "win64", "mac", "linux", "linux32" or "linux64"

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)

response = license.product_details()
```

**Return**(dict): response

#### set\_device\_variables

Set device variables locally.

**Parameters**:

* **variables** (dict): variables dict
* **save** (bool, optional): Save cache to licensefile. Defaults to True.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)

license.set_device_variables({"english":"value"})
```

**Return**: None

#### get\_device\_variables

Get device variables from server or locally.

**Parameters**:

* **get\_from\_be** (bool, optional): If True collects data from LicenseSpring server. Defaults to True.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)

license.get_device_variables(get_from_be=True)
```

**Raises**:

* **RequestException** (Grace period not allowed)

**Return**(list): List of device variables

#### send\_device\_variables

Send device variables to LicenseSpring server. Handles GracePeriod.

```python
manager = LicenseManager(conf)

license_id = LicenseID.from_key("H9V3-72XX-ZRAJ-S6LK")

license = manager.activate_license(license_id)

license.send_device_variables()
```

**Raises**:

* **RequestException** (Grace period not allowed)

**Return**(bool): True if new variables are sent to LicenseSpring server otherwise, False

## Floating Server

**Floating Manager**:

* This object is responsible for managing operations with the Floating Server, while also integrating the license file

### Floating Manager

To initialize Floating Manager [Configuration](#configuration-setup) needs to be created. For Floating server you can set arbitrary values for `shared_key` and `api_key` keys. To enable signature verification in Floating Server v2, set the certificate\_chain\_path in the Configuration object.

### auth

Authenticate.

**Parameters**:

* **username** (str): username
* **password** (str): password

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

fs_manager = FloatingManager(conf=conf)
fs_manager.auth(username="admin",password="tetejac")
```

**Return**(dict): Response

### register

Register license.

**Parameters**:

* **os\_hostname** (str, optional): os hostname. Defaults to None.
* **ip\_local** (str, optional): ip local. Defaults to None.
* **user\_info** (str, optional): user info. Defaults to None.
* **license\_id** (int, optional):license id. Defaults to None.

```python
from licensespring.licensefile.config import Configuration
from licensespring.licensefile.floating_manager import FloatingManager

conf = Configuration(
    product=product,
    api_key="arbitrary",
    shared_key="arbitrary",
    file_key="your_file_key",
    file_iv="your_file_iv",
    api_domain="api_domain",
    api_protocol="http/https",
    certificate_chain_path="certificate_chain_path/chain.pem" # used for signature verification
)

fs_manager = FloatingManager(conf=conf)
license = fs_manager.register()
```

**Return**(License): License object

### unregister

Unregister license.

**Parameters**:

* license\_id (int, optional): license id. Defaults to None.

```python
fs_manager = FloatingManager(conf=conf)
# There are multiple options to unregister a license
# 1. floating manager
fs_manager.unregister()
# 2.1. license object -> deactivate method
license.deactivate()
#2.2 license object -> floating release
license.floating_release(False)
```

**Return**(str): "user\_unregistered"

### unregister\_all

Unregister all users.

```python
fs_manager = FloatingManager(conf=conf)
fs_manager.unregister_all()
```

### borrow\_license

Borrow license.

**Parameters**:

* **borrowed\_until** (str): borrow until date
* **os\_hostname** (str, optional): os hostname. Defaults to None.
* **ip\_local** (str, optional): ip local. Defaults to None.
* **user\_info** (str, optional): user info. Defaults to None.
* **license\_id**(int, optional):license id. Defaults to None.

```python
fs_manager = FloatingManager(conf=conf)
license = fs_manager.borrow("2031-05-06T00:00:00Z")
# borrow can be also used within the License object
license.floating_borrow("2031-05-06T00:00:00Z")
```

**Return**(License): License object

### is\_online

Checks if floating server is online.

**Parameters**:

* **throw\_e** (bool, optional): True if you want raise exception. Defaults to False.

```python
fs_manager = FloatingManager(conf=conf)
response = fs_manager.is_online()
```

**Raises**:

* **ex**: Exception

**Return**(bool): True if server is online, otherwise False

### fetch\_licenses

List licenses.

**Parameters**:

* **product** (str,optional): product short code filter

```python
fs_manager = FloatingManager(conf=conf)

response = fs_manager.fetch_licenses(product="test")
print(response)
```

**Return**(dict): Response

### Methods supported inside License object

[License consumptions](#add_local_consumption), [feature consumptions](#add_local_feature_consumption), [register feature](#check_feature), [release feature](#release_feature) are supported within `License` object for Floating Server.

## License

LicenseSpring SDK Source Code License (LSSCL)

Preamble:

This LicenseSpring SDK Source Code License (LSSCL) governs the use, distribution, and modification of the source code for this LicenseSpring SDKs. This SDK is designed to facilitate the integration of LicenseSpring's license management service into your applications. By accessing, using, or modifying the SDK, you agree to the terms and conditions set forth in this license.

1. **Permissions:**
   * You are permitted to access, read, and modify the source code of this LicenseSpring SDK.
   * You may create derivative works that include this SDK, provided all derivative works are used solely as part of the LicenseSpring service.
2. **Distribution:**
   * You may distribute the original or modified versions of software that incorporates the SDK, provided that all distributed versions retain this LSSCL license.
   * Distributed versions, including modifications, must be used to facilitate the integration of LicenseSpring’s service and may not be:
     * Provided as part of a hosted or cloud-based service that allows others to access the SDK’s functionality without interacting directly with the LicenseSpring service.
     * Integrated into other services which compete with or do not use the LicenseSpring service.
3. **Usage Restrictions:**
   * The SDK, in its original or modified form, may only be used as part of the LicenseSpring service, whether on a free or paid plan.
   * You are prohibited from using the SDK independently or as part of any service that does not interact with the LicenseSpring service.
4. **Prohibited Actions:**
   * You may not circumvent or disable any technical measures that control access to the SDK.
   * You must not remove, alter, or obscure any license notices, copyright notices, or other proprietary notices from the SDK.
5. **Termination:**
   * Any violation of these terms will result in the automatic termination of your rights under this license.
   * Upon termination, you must cease all use and distribution of the SDK and destroy all copies in your possession.
6. **Disclaimer of Warranty and Liability:**

   THE SOFTWARE IS PROVIDED "AS IS" AND LICENSESPRING DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. LICENSESPRING SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING OUT OF OR RELATED TO THE USE OR PERFORMANCE OF THE SOFTWARE.

Copyright 2024 Cense Data Inc DBA LicenseSpring\
Contact: <support@licensespring.com>

### Dependency licenses

| Name               | Version | License                                             | URL                                                        |
| ------------------ | ------- | --------------------------------------------------- | ---------------------------------------------------------- |
| certifi            | 25.1.0  | Mozilla Public License 2.0 (MPL 2.0)                | <https://github.com/certifi/python-certifi>                |
| charset-normalizer | 3.4.1   | MIT License                                         | <https://github.com/Ousret/charset\\_normalizer>           |
| idna               | 3.10    | BSD License                                         | <https://github.com/kjd/idna>                              |
| pycryptodome       | 3.21.0  | Apache Software License; BSD License; Public Domain | <https://www.pycryptodome.org>                             |
| requests           | 2.32.3  | Apache Software License                             | <https://requests.readthedocs.io>                          |
| urllib3            | 2.3.0   | MIT License                                         | <https://github.com/urllib3/urllib3/blob/main/CHANGES.rst> |
| winregistry        | 2.1.0   | UNKNOWN                                             | <https://github.com/shpaker/winregistry>                   |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.licensespring.com/sdks/python-sdk/python-sdk.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
