You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Current »

The LM-X Python wrapper is a thin Python interface over the native LM-X client library. It provides Pythonic access to the entire LM-X API. Example Python code (local, network, callbacks, licstat, clientstore, trial, admin) is included in the LM-X examples subdirectory.

Usage of the Python wrapper is detailed below.

Package contents

The Python wrapper package is delivered as an LM-X wheel (lmx-*-py3-none-any.whl) that you can install with pip. The wheel contains:

  • Python package: lmx (client.py, _ffi.py, _marshal.py, _callbacks.py, types.py, errors.py)
  • Embedded native LM-X client library (platform-specific):
    • liblmx.so (Linux/Unix)
    • liblmx.dylib (macOS)
    • liblmx.dll (Windows)

The wheel is non-pure (root_is_pure = False) and platform-tagged.

Prerequisites

Prerequisites for using the Python wrapper include:

  • Python version greater than or equal to version 3.8
  • LM-X SDK build output for your target platform
  • Matching Python bitness and SDK target bitness (32-bit or 64-bit)

Building the wheel

Building the Python wheel is described below.

Build from SDK root (recommended method)

To build the wheel from the SDK root (recommended), build the SDK as usual. The wheel build is part of the SDK makefile flow:

  • For Unix/Linux/macOS:
    make
    
  • For Windows (Visual Studio and nmake environment):
    nmake
    

This runs python/build_sdk_wheel.py and produces:

  • python/lmx-*.whl
  • python/wheel_build.log

Build only the wheel target

To build only the wheel target:

  • For Unix/Linux/macOS:
    make build_python_wheel
    
  • For Windows:
    nmake build_python_wheel
    

Build using manual script invocation

To build the wheel manually from SDK root, run the following script:

python3 python/build_sdk_wheel.py \
  --platform linux_x64 \
  --library linux_x64/liblmx.so \
  --output-dir python \
  --venv python/.venv_wheel

 

  • --platform must match the LM-X host directory name (for example linux_x64, win64_x64, darwin_universal).
  • If prerequisites are not met, the build will be skipped (exit code 0) and the SKIPPED: reason will be logged in python/wheel_build.log.

Installing and starting the wheel

Installing and starting the wheel is described below.

Install the generated wheel

From SDK examples/python, run:

pip install ../../python/lmx-*.whl

Run example scripts

You can start the wheel using one of the following example scripts.

python3 local.py
python3 network.py
python3 callbacks.py
python3 licstat.py
python3 clientstore.py
python3 trial.py
python3 admin.py

You can also use the provided example makefile targets:

  • For Unix/Linux/macOS: 
    make run_local (and run_network, run_callbacks, run_licstat, run_clientstore, run_trial, run_admin, run_all)
  • For Windows: 
    nmake run_local (same target set)

Python wrapper usage example

The following is a simple example of using the Python wrapper. 

from lmx import LMX_STATUS, LmxClient, LmxSettings

FEATURE = "f2"

with LmxClient() as client:
    status = client.init()
    if status != int(LMX_STATUS.LMX_SUCCESS):
        raise RuntimeError(f"LMX_Init failed: {status}")

    # Setup license path
    client.set_option(LmxSettings.LMX_OPT_LICENSE_PATH, "6200@localhost")

    # Checkout one license
    status = client.checkout(FEATURE, 1, 0, 1)
    if status != int(LMX_STATUS.LMX_SUCCESS):
        error = client.get_error_message()
        raise RuntimeError(f"LMX_Checkout failed: status={status}, error={error}")

    # Checkin the license
    status = client.checkin(FEATURE, 1)
    if status != int(LMX_STATUS.LMX_SUCCESS):
        raise RuntimeError(f"LMX_Checkin failed: {client.get_error_message()}")

How the Python wrapper works

The Python wrapper works as follows:

  1. LmxClient is a thread-safe OO facade over LM-X C APIs.
  2. The wrapper loads native LM-X symbols through ctypes.CDLL (lmx/_ffi.py).
  3. Method calls map 1:1 to native exports (LMX_Init, LMX_Checkout, LMX_Checkin, etc.).
  4. Complex C structs are converted into Python dictionaries/dataclasses by marshal helpers (lmx/_marshal.py).
  5. Python callback options are converted to C function pointers.
  6. Status codes are returned as integers compatible with LMX_STATUS enum values.

Native library resolution order

When creating LmxClient() the wrapper searches in this order:

  1. Explicit constructor path (library_path), where the path must be absolute.
  2. LMX_PYTHON_LIBRARY_PATH env var (absolute file path or absolute directory).
  3. Directory containing lmx/_ffi.py (typically wheel package location).
  4. Current working directory.
  5. OS PATH entries.

If no valid library is found, an LmxUsageError exception is raised for the attempted paths.

Troubleshooting

Troubleshooting for issues using the Python wrapper are described below.

Wheel not generated

If the wheel is not generated, you will get the following error after the build:

No python/lmx-*.whl

To resolve this issue, try the following:

  1. Inspect python/wheel_build.log for SKIPPED: messages.
  2. Verify that the Python interpreter exists and is callable.
  3. Verify that the interpreter bitness matches target platform bitness.
  4. Verify that the native library path provided to build the script exists.

Inability to locate the LM-X client library

If the import/initialization fails because the LM-X client library path cannot be resolved, you will see the following error: 

Could not locate LM-X client library

To resolve this issue, try the following:

  1. Ensure that the wheel was installed successfully (pip show lmx).
  2. If overriding the library location, set an absolute LMX_PYTHON_LIBRARY_PATH.
  3. If using LmxClient(library_path=...), pass an absolute file path.
  4. Confirm that the file name matches the platform (.so, .dylib, .dll).

Callback-related crashes or unexpected behavior

If you are experiencing callback-related crashes or other unexpected behavior, try the following:

  1. Register callbacks using only set_option().
  2. Ensure callback signatures are compatible with expected LM-X callback shapes.
  3. Do not bypass LmxClient internals for callback pointer handling.
  • No labels