Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
timsavage committed Jan 23, 2025
2 parents 0a6e68f + 18e6583 commit ba44de4
Show file tree
Hide file tree
Showing 8 changed files with 476 additions and 382 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

name: Test Python ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

Expand All @@ -33,7 +33,7 @@ jobs:
poetry run pytest --junit-xml=reports/xunit-result-${{ matrix.python-version }}.xml --cov=pyapp_flow --cov-branch --cov-report=xml:reports/coverage-${{ matrix.python-version }}.xml tests
- name: Analyze with SonarCloud
uses: sonarsource/sonarcloud-github-action@master
uses: sonarsource/sonarqube-scan-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
name: Build pre-release package

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- uses: actions/setup-python@master
name: Setup Python 3.8
Expand Down
12 changes: 11 additions & 1 deletion HISTORY
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
0.18.0
======

Additions
---------

- Add default_vars option to Workflows to apply default values if one is not
already provided.


0.17.0
======

Expand All @@ -7,7 +17,7 @@ Additions
- Add required_vars option to Workflows to ensure that required variables
are set before the workflow is executed.
- Integrate required_vars into CLI.
- Add sensitive filter when outputing variables in flow-trace
- Add sensitive filter when outputting variables in flow-trace


0.16.0
Expand Down
753 changes: 377 additions & 376 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pyapp-flow"
version = "0.17"
version = "0.18"
description = "Application workflow framework"
authors = ["Tim Savage <[email protected]>"]
license = "BSD-3-Clause"
Expand Down
13 changes: 12 additions & 1 deletion src/pyapp_flow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Append,
CaptureErrors,
Conditional,
DefaultVar,
FeatureEnabled,
ForEach,
Group,
Expand Down Expand Up @@ -60,7 +61,7 @@ class Workflow(Nodes):

__slots__ = ("_name", "description", "_required_vars")

def __init__(self, name: str, description: str = None):
def __init__(self, name: str, description: str | None = None):
super().__init__()
self._name = name
self.description = description
Expand Down Expand Up @@ -125,6 +126,16 @@ def set_vars(self, **kwargs) -> Self:
self._nodes.append(SetVar(**kwargs))
return self

def default_vars(self, **kwargs) -> Self:
"""Default variables to a particular value.
:param kwargs: Key/Value pairs to update in the context
:return: Returns self; fluent interface
"""
self._nodes.append(DefaultVar(**kwargs))
return self

def require_vars(self, **kwargs: Optional[Type]) -> Self:
"""Require variables to be present in the context.
Expand Down
39 changes: 39 additions & 0 deletions src/pyapp_flow/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,45 @@ def name(self):
return f"Set value(s) for {', '.join(self.values)}"


class DefaultVar(Navigable):
"""Set context variable to specified values if not already set.
:param values: Key/Value pairs or Key/Vallable pairs to be applied to the context
if key is not already defined.
.. code-block:: python
DefaultVar(
title="Hyperion",
published=datetime.date(1996, 11, 1),
updated=inline(lambda: datetime.datetime.now())
)
"""

__slots__ = ("values", )

def __init__(
self,
**values: Any | Callable[[WorkflowContext], Any],
):
self.values = values

def __call__(self, context: WorkflowContext):
"""Call object implementation."""
context.info("📝 %s", self)
values = [
(key, value(context) if callable(value) else value)
for key, value in self.values.items()
if key not in context.state
]
context.state.update(values)

@property
def name(self):
"""Name of the node"""
return f"Default value(s) for {', '.join(self.values)}"


class Append(Navigable):
"""Append a message to a list.
Expand Down
33 changes: 33 additions & 0 deletions tests/unit/test_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,39 @@ def test_str(self):
assert str(target) == "Set value(s) for var_b, var_c"



class TestDefaultVar:
@pytest.fixture
def target(self):
return nodes.DefaultVar(
var_b=42, var_c="bar", var_d=lambda ctx: ctx.state["var_a"] + "bar"
)

def test_call__with_value(self, target):
context = call_node(target, var_a="foo", var_b=13)

assert context.state == {
"__trace": [ANY],
"var_a": "foo",
"var_b": 13,
"var_c": "bar",
"var_d": "foobar",
}

def test_call__with_value(self, target):
context = call_node(target, var_d="eek")

assert context.state == {
"__trace": [ANY],
"var_b": 42,
"var_c": "bar",
"var_d": "eek",
}

def test_str(self, target):
assert str(target) == "Default value(s) for var_b, var_c, var_d"


class TestForEach:
def test_call__each_item_is_called(self):
target = nodes.ForEach("char", in_var="var_a").loop(
Expand Down

0 comments on commit ba44de4

Please sign in to comment.