Unofficial OpenTDF SDK for Python
This project is powered by gopy, which generates (and compiles) a CPython extension module from a go package. The gopy
tool unlocks performance, flexibility, and excellent Developer Experience to Python end-users. Read more about
gopy
on Github.
If you wish to expand the functionality of otdf-python
:
- Create a fork/branch
- Add new capabilities (e.g. in
main.go
) - Add a test (e.g. in
otdf_python_test.go
) - Commit your changes, push, and open a Pull Request via the Github project: https://github.com/b-long/opentdf-python-sdk
Install from the Python Package Index (PyPI):
# Install the latest from pypi.org
pip install otdf_python
# Install a pinned version
pip install otdf-python==0.0.9
# Install a pinned version, from test.pypi.org
pip install -i https://test.pypi.org/simple/ otdf-python==0.0.9
Simple usage examples are given below. In addition, we recommend you also:
- See the contents of
main.go
on Github. ✨ Note that all Upper-case functions are available in Python. - See the contents of
validate_otdf_python.py
on Github.
Creating a helper function may simplify the usage of otdf-python
.
For example:
def get_encrypt_config(data_attributes: list | None = None):
"""
The config object returned here can only be used for encryption.
While 'otdf_python.gotdf_python' internally can use golang interfaces,
to normalize config objects, that pattern causes a panic
when used from Python.
"""
print("Preparing 'EncryptionConfig' object")
from otdf_python.gotdf_python import EncryptionConfig
from otdf_python.go import Slice_string
if isinstance(data_attributes, list):
# Create config using the attributes from the caller
da = Slice_string(data_attributes)
config: EncryptionConfig = EncryptionConfig(
ClientId="opentdf-sdk",
ClientSecret="secret",
PlatformEndpoint=platformEndpoint,
TokenEndpoint="http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token",
KasUrl=f"http://{platformEndpoint}/kas",
# FIXME: Be careful with binding the 'DataAttributes' field on this struct.
#
# In golang, this is initialized as []string , but passing
# DataAttributes=None, or DataAttributes=[] from Python will fail.
DataAttributes=da,
)
else:
# Create config without attributes
config: EncryptionConfig = EncryptionConfig(
ClientId="opentdf-sdk",
ClientSecret="secret",
PlatformEndpoint=platformEndpoint,
TokenEndpoint="http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token",
KasUrl=f"http://{platformEndpoint}/kas",
)
# NOTE: Structs from golang can be printed, like below
# print(config)
print("Returning 'EncryptionConfig'")
return config
from otdf_python.gotdf_python import EncryptString
# Depends on the 'get_encrypt_config()' given
# in the README above
config: EncryptionConfig = get_encrypt_config()
tdf_manifest_json = EncryptString(inputText="Hello from Python", config=config)
from otdf_python.gotdf_python import EncryptFile
from otdf_python.go import Slice_string
# Depends on the 'get_encrypt_config()' given
# in the README above
config: EncryptionConfig = get_encrypt_config()
with tempfile.TemporaryDirectory() as tmpDir:
print("Created temporary directory", tmpDir)
da = Slice_string(["https://example.com/attr/attr1/value/value1", "https://example.com/attr/attr1/value/value2"])
encrypted_file = Path(tmpDir) / "some-file.tdf"
if encrypted_file.exists():
encrypted_file.unlink()
if encrypted_file.exists():
raise ValueError(
"The output path should not exist before calling 'EncryptFile()'."
)
outputFilePath = EncryptFile(
inputFilePath=str(SOME_PLAINTEXT_FILE),
outputFilePath=str(encrypted_file),
config=config,
)
print(f"The output file was written to destination path: {outputFilePath}")