cmemc - Python Scripts¤
Introduction¤
As a more lightweight and fault-tolerant alternative to using cmempy directly, we recommend to call cmemc commands directly in your Python automation scripts.
The advantages of this approach are:
- You can test and use your calls in the command line before integrating them.
- You don’t have to worry about internal details and have a well-documented and stable interface.
- Authorization is done in the same way, cmemc is doing this.
Installation¤
cmemc is published as an Apache 2 licensed open source python package at pypi.org, hence you are able to install it with a simple pip command:
Configure a connection¤
Assuming you have already configured your cmemc connection, using it in Python scripts is quite easy.
This will tell cmemc to use the configured connection my-dev-cmem
.
Running commands¤
In order to execute a command and process the results, you can use this wrapper function:
import json
from click.testing import CliRunner
from cmem_cmemc.cli import cli
def cmemc(params: list[str]) -> str | list[str] | list[dict]:
"""Run a cmemc command and provide the output.
When using the --raw option, output is a parsed list of dictionaries.
When using the --id-only option, output is a parsed list of strings.
Returns plain text output otherwise.
Have a look at click API documentation for more options:
https://click.palletsprojects.com/en/stable/api/#click.testing.CliRunner
"""
result = CliRunner().invoke(cli, params)
if result.exit_code != 0:
raise RuntimeError(result.exception)
output: str = result.stdout
if "--id-only" in params:
return output.splitlines()
if "--raw" in params:
return json.loads(output)
return output
This function will use the configured connection to execute a command and return the result.
Please note that the output can bei either a multi-line string, a list of strings or a list of dictionaries.
This is because we made sure that --raw
outputs JSON and --id-only
only identifier.
As a last step, you can iterate and process the results:
# specify the command as a list of arguments - in this case: list all existing worflows
command = ["workflow", "list", "--raw"]
# iterate and process the output
for workflow in cmemc(command):
project_id = workflow.get("projectId")
workflow_id = workflow.get("id")
print(f"Workflow '{workflow_id}' in '{project_id}'")
Using a shebang to create an executable file¤
As a nice addon, you could extend your script with a shebang to start uv. This will also install and manage dependencies and python versions for you:
The complete script looks like this:
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
# "cmem-cmemc",
# ]
# ///
import json
from os import environ
from click.testing import CliRunner
from cmem_cmemc.cli import cli
def cmemc(params: list[str]) -> str | list[str] | list[dict]:
"""Run a cmemc command and provide the output.
When using the cmemc --raw option, output is a parsed list of dictionaries.
When using the cmemc --id-only option, output is a parsed list of strings.
Have a look at click API documentation for more options:
https://click.palletsprojects.com/en/stable/api/#click.testing.CliRunner
"""
result = CliRunner().invoke(cli, params)
if result.exit_code != 0:
raise RuntimeError(result.exception)
output: str = result.stdout
if "--id-only" in params:
return output.splitlines()
if "--raw" in params:
return json.loads(output)
return output
# use the cmemc connection
environ["CMEMC_CONNECTION"] = "my-dev-cmem"
# specify the command as a list of arguments
# in this case: list all existing worflows
command = ["workflow", "list", "--raw"]
# iterate and process the output
for workflow in cmemc(command):
project_id = workflow.get("projectId")
workflow_id = workflow.get("id")
print(f"Workflow '{workflow_id}' in '{project_id}'")
Executing this python script will look like this:
$ ./cmemc-script.py
Workflow 'input-output' in 'io'
Workflow 'input-output-replaceable' in 'io'
Workflow 'normal' in 'io'
Workflow 'only-input' in 'io'
Workflow 'only-input-included' in 'io'
Workflow 'only-input-replaceable' in 'io'
Workflow 'only-output' in 'io'
Workflow 'only-output-replaceable' in 'io'