Skip to content

Commit

Permalink
Remove join from python_app decorator, and reimplement join_app
Browse files Browse the repository at this point in the history
The join parameter should never be set by a user, and gives bad error
messages if it is set - see issue #2174.

The parameter was only there so that the join_app decorator could be
implemented in terms of the python_app decorator. This PR changes how
that implementation works so that this misbehaviour is not exposed
to end users.

Fixes issue #2174
  • Loading branch information
benclifford committed Mar 13, 2023
1 parent 33398b1 commit 7db3d9b
Showing 1 changed file with 32 additions and 12 deletions.
44 changes: 32 additions & 12 deletions parsl/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def python_app(function=None,
----------
function : function
Do not pass this keyword argument directly. This is needed in order to allow for omitted parenthesis,
for example, ``@python_app`` if using all defaults or ``@python_app(walltime=120)``. If the
for example, ``@join_app`` if using all defaults or ``@python_app(walltime=120)``. If the
decorator is used alone, function will be the actual function being decorated, whereas if it
is called with arguments, function will be None. Default is None.
data_flow_kernel : DataFlowKernel
Expand All @@ -91,10 +91,6 @@ def python_app(function=None,
Labels of the executors that this app can execute over. Default is 'all'.
cache : bool
Enable caching of the app call. Default is False.
join : bool
If True, this app will be a join app: the decorated python code must return a Future
(rather than a regular value), and and the corresponding AppFuture will complete when
that inner future completes.
"""
from parsl.app.python import PythonApp

Expand All @@ -105,7 +101,7 @@ def wrapper(f):
cache=cache,
executors=executors,
ignore_for_cache=ignore_for_cache,
join=join)
join=False)
return wrapper(func)
if function is not None:
return decorator(function)
Expand All @@ -116,13 +112,37 @@ def wrapper(f):
def join_app(function=None,
data_flow_kernel: Optional[DataFlowKernel] = None,
cache: bool = False,
executors: Union[List[str], Literal['all']] = 'all',
ignore_for_cache: Optional[List[str]] = None):
return python_app(function=function,
data_flow_kernel=data_flow_kernel,
cache=cache,
ignore_for_cache=ignore_for_cache,
join=True,
executors=["_parsl_internal"])
"""Decorator function for making join apps
Parameters
----------
function : function
Do not pass this keyword argument directly. This is needed in order to allow for omitted parenthesis,
for example, ``@python_app`` if using all defaults or ``@python_app(walltime=120)``. If the
decorator is used alone, function will be the actual function being decorated, whereas if it
is called with arguments, function will be None. Default is None.
data_flow_kernel : DataFlowKernel
The :class:`~parsl.dataflow.dflow.DataFlowKernel` responsible for managing this app. This can
be omitted only after calling :meth:`parsl.dataflow.dflow.DataFlowKernelLoader.load`. Default is None.
cache : bool
Enable caching of the app call. Default is False.
"""
from parsl.app.python import PythonApp

def decorator(func):
def wrapper(f):
return PythonApp(f,
data_flow_kernel=data_flow_kernel,
cache=cache,
executors=["_parsl_internal"],
ignore_for_cache=ignore_for_cache,
join=True)
return wrapper(func)
if function is not None:
return decorator(function)
return decorator


@typeguard.typechecked
Expand Down

0 comments on commit 7db3d9b

Please sign in to comment.