Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- fixed the stale link to the context object documentation
- the plugin talks to the deployment through `cmem-client` only - the deprecated
`cmem-cmempy` dependency and all `setup_cmempy_user_access` calls are gone
- **breaking:** `setup_cmempy_user_access` also set `OAUTH_GRANT_TYPE` and
`OAUTH_ACCESS_TOKEN` in the environment of the whole process, which task code
calling `cmem.cmempy.*` could rely on without setting up access itself. That side
effect is gone, so such code now has to authenticate on its own - the documented
way is `get_client(context)`

### Fixed

- the **Install missing dependencies** action reports the installed version of an
already installed package instead of repeating its name
- the **Validate execution phase** action no longer fails with an `AttributeError`
when the execution code assigns `result = None`, which is the documented way of
handing nothing to the next task
- the **Validate execution phase** action starts from the `data` its initialization
code builds, instead of carrying the mutations of earlier action runs
- the documented behavior of a failed dependency installation: it stops the task
before the execution code runs, rather than letting the import fail later

## [1.2.1] 2025-09-18

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Do not use in production!

```
eval $(cmemc -c my-cmem config eval)
task clean check plugin:install
task clean check install
```

馃槇
Expand Down
15 changes: 10 additions & 5 deletions cmem_plugin_python/workflow_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,11 @@
Dependencies are matched by package name only.
A package which is already installed is left at the version which is there, and a version
specifier is not understood and leads to a fresh installation attempt on every run.
A failed installation does not stop the task: execution continues and the code fails later, at
the import.

An installation which fails stops the task before the execution code runs at all, because the
deployment rejects the request and the error is not caught.
A misspelled dependency therefore fails the workflow run rather than the import, and the
**Install missing dependencies** action reports the error instead of its per package output.
"""


Expand Down Expand Up @@ -376,9 +379,11 @@ def validate_execute_action(self) -> str:
"""Run the execute code and report results."""
init_scope = self.do_init()
test_inputs = init_scope.get("test_inputs", [])
scope = self.do_execute(test_inputs, None, self.data)
if "result" in scope:
result: Entities = scope["result"]
# the data of the fresh init scope, not self.data: the constructor's dict is mutated by
# every run of the execution code, so re-using it accumulates across action calls
scope = self.do_execute(test_inputs, None, init_scope.get("data", {}))
result: Entities | None = scope.get("result")
if result is not None:
output = "# Schema\n"
output += "``` python\n"
output += f"{result.schema!r}\n"
Expand Down
30 changes: 30 additions & 0 deletions tests/test_workflow_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,36 @@ def test_validate_execute_action() -> None:
)


def test_validate_execute_action_with_none_result() -> None:
"""Test Validate execute action with an explicit result of None"""
assert (
"No result provided"
in PythonCodeWorkflowPlugin(
init_code=PythonCode(""),
execute_code=PythonCode("result = None"),
).validate_execute_action()
)


def test_validate_execute_action_resets_data() -> None:
"""Test that the action starts from the data of a fresh initialization run"""
counting_code = PythonCode(
"""from cmem_plugin_base.dataintegration import entity
data["count"] += 1
result = entity.Entities(
entities=[entity.Entity(uri="urn:x-example:run", values=[[str(data["count"])]])],
schema=entity.EntitySchema(
type_uri="urn:x-example:count", paths=[entity.EntityPath("count")]
),
)"""
)
plugin = PythonCodeWorkflowPlugin(
init_code=PythonCode('data["count"] = 0'), execute_code=counting_code
)
for _ in range(3):
assert "['1']" in plugin.validate_execute_action()


def test_validate_execute_action_fail() -> None:
"""Test Validate execute action fails"""
with pytest.raises(SyntaxError, match=r"'\[' was never closed"):
Expand Down
Loading