Skip to content

Commit

Permalink
Improve documentation about configuration and workflows (#2919)
Browse files Browse the repository at this point in the history
Clarifies problems users found in the documentation

 error in parallel documentation #2915: Decorators are not needed for ParslPoolExecutor.map
 Reloading default HighThroughputExecutor after parsl.clear() results in KeyError: 'block_id' exception #2871 : Configs may not be re-used
 Fixes Docs: Further clarification on how serialization impacts where imports need to be #2918 : Explain when functions need imports
 Fixes Allowing for inputs and outputs to take immutable types #2925 : Explain mutable types are undesirable

Thanks, @Andrew-S-Rosen
  • Loading branch information
WardLT authored Oct 24, 2023
1 parent 8e4c392 commit a5aede7
Show file tree
Hide file tree
Showing 11 changed files with 430 additions and 150 deletions.
16 changes: 8 additions & 8 deletions docs/devguide/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ New Functionality
.. code-block:: python
@bash_app
def cat(inputs=[], outputs=[]):
def cat(inputs=(), outputs=()):
return 'cat {} > {}'.format(inputs[0], outputs[0])
concat = cat(inputs=['hello-0.txt'],
Expand All @@ -302,7 +302,7 @@ New Functionality
from parsl import File
@bash_app
def cat(inputs=[], outputs=[]):
def cat(inputs=(), outputs=()):
return 'cat {} > {}'.format(inputs[0].filepath, outputs[0].filepath)
concat = cat(inputs=[File('hello-0.txt')],
Expand All @@ -316,7 +316,7 @@ New Functionality
from parsl import File
@bash_app
def cat(inputs=[], outputs=[]):
def cat(inputs=(), outputs=()):
return 'cat {} > {}'.format(inputs[0].filepath, outputs[0].filepath)
Expand Down Expand Up @@ -397,16 +397,16 @@ New Functionality
# The following example worked until v0.8.0
@bash_app
def cat(inputs=[], outputs=[]):
def cat(inputs=(), outputs=()):
return 'cat {inputs[0]} > {outputs[0]}' # <-- Relies on Parsl auto formatting the string
# Following are two mechanisms that will work going forward from v0.9.0
@bash_app
def cat(inputs=[], outputs=[]):
def cat(inputs=(), outputs=()):
return 'cat {} > {}'.format(inputs[0], outputs[0]) # <-- Use str.format method
@bash_app
def cat(inputs=[], outputs=[]):
def cat(inputs=(), outputs=()):
return f'cat {inputs[0]} > {outputs[0]}' # <-- OR use f-strings introduced in Python3.6
Expand Down Expand Up @@ -510,12 +510,12 @@ New Functionality
# Old style: " ".join(inputs) is legal since inputs will behave like a list of strings
@bash_app
def concat(inputs=[], outputs=[], stdout="stdout.txt", stderr='stderr.txt'):
def concat(inputs=(), outputs=(), stdout="stdout.txt", stderr='stderr.txt'):
return "cat {0} > {1}".format(" ".join(inputs), outputs[0])
# New style:
@bash_app
def concat(inputs=[], outputs=[], stdout="stdout.txt", stderr='stderr.txt'):
def concat(inputs=(), outputs=(), stdout="stdout.txt", stderr='stderr.txt'):
return "cat {0} > {1}".format(" ".join(list(map(str,inputs))), outputs[0])
* Cleaner user app file log management.
Expand Down
2 changes: 1 addition & 1 deletion docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ How can I make an App dependent on multiple inputs?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You can pass any number of futures in to a single App either as positional arguments
or as a list of futures via the special keyword ``inputs=[]``.
or as a list of futures via the special keyword ``inputs=()``.
The App will wait for all inputs to be satisfied before execution.


Expand Down
3 changes: 3 additions & 0 deletions docs/teaching_scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Example Scripts

Scripts which illustrate example from the documentation that do not run well as part of the pytest
83 changes: 83 additions & 0 deletions docs/teaching_scripts/test_apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""Tests documentation related to building apps. Must reside outside the Parsl library to be effective"""
from typing import List, Union

import numpy as np

from parsl import python_app, HighThroughputExecutor, Config
import parsl

parsl.load(Config(executors=[HighThroughputExecutor(label='htex_spawn', max_workers=1, start_method='spawn', address='127.0.0.1')]))


# Part 1: Explain imports
# BAD: Assumes library has been imported
@python_app(executors=['htex_spawn'])
def bad_imports(x: Union[List[float], np.ndarray], m: float, b: float):
return np.multiply(x, m) + b


# GOOD: Imports libraries itself
@python_app(executors=['htex_spawn'])
def good_imports(x: Union[List[float], 'np.ndarray'], m: float, b: float):
import numpy as np
return np.multiply(x, m) + b


future = bad_imports([1.], 1, 0)

try:
future.result()
raise ValueError()
except NameError as e:
print('Failed, as expected. Error:', e)

future = good_imports([1.], 1, 0)
print(f'Passed, as expected: {future.result()}')

# Part 2: Test other types of globals
# BAD: Uses global variables
global_var = {'a': 0}


@python_app
def bad_global(string: str, character: str = 'a'):
global_var[character] += string.count(character) # `global_var` will not be accessible


# GOOD
@python_app
def good_global(string: str, character: str = 'a'):
return {character: string.count(character)}


try:
bad_global('parsl').result()
except NameError as e:
print(f'Failed, as expected: {e}')

for ch, co in good_global('parsl', 'a').result().items():
global_var[ch] += co


# Part 3: Mutable args

# BAD: Assumes changes to inputs will be communicated
@python_app
def append_to_list(input_list: list, new_val):
input_list.append(new_val)


mutable_arg = []
append_to_list(mutable_arg, 1).result()
assert mutable_arg == [], 'The list _was_changed'


# GOOD: Changes to inputs are returned
@python_app
def append_to_list(input_list: list, new_val) -> list:
input_list.append(new_val)
return input_list


mutable_arg = append_to_list(mutable_arg, 1).result()
assert mutable_arg == [1]
Loading

0 comments on commit a5aede7

Please sign in to comment.