Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat python_app input/output default arguments like other magic keywords, and like bash_app #3489

Merged
merged 8 commits into from
Jul 2, 2024

Conversation

arhag23
Copy link
Contributor

@arhag23 arhag23 commented Jun 14, 2024

Description

In a previous PR (#3485), some fields where the default values of outputs and inputs for AppBase were removed. These fields were not being used in any way. However, like the other parsl reserved parameters, the defaults should have been stored in the AppBase.kwargs dict which is used to ensure that the default values of these special reserved parameters are in invocation_kwargs which is sent to the dataflow kernel and used to resolve the corresponding special behaviors. The correct behavior was only observed in BashApp since it does additional checking to store all default args (even the non-reserved ones) to invocation_kwargs. Now it should be consistent for both types of apps.

Changed Behaviour

PythonApp will now correctly resolve default arguments for the inputs and outputs special parameters.

Type of change

  • Bug fix
  • Code maintenance/cleanup

@benclifford
Copy link
Collaborator

parsl/tests/test_staging/test_zip_out.py is failing in CI - perhaps also for you locally?

@arhag23 arhag23 marked this pull request as draft June 14, 2024 15:55
@arhag23
Copy link
Contributor Author

arhag23 commented Jun 14, 2024

I'm not able to run the entire test suite locally, but I tried running the individual test that fails and it seems to run fine locally.

@astro-friedel
Copy link

From the logs it appears that test_bash_multiple_set from test_mpi_mode_enabled.py is the test that is failing for python 3.8 with a serialization error. I do see that the CI test were run mutiple times, each one failed at a different spot with the same serialization error. I have been unable to run the full test suite for Parslas I cannot find a compatible cctools for my OS (ubuntu 22.04), so I am unable to reproduce the error locally.

@benclifford
Copy link
Collaborator

For future, the error that @astro-friedel is referring to that has appeared a few times looks like this below paste.

The non-obvious bit of this (to me) is that the code is trying to serialize a Queue object. That shouldn't ever be happening, and its not clear to me where in the serialization graph that Queue object is coming from - the stack trace doesn't give a huge amount of information about the internal structure of whats being serialized.

I'll try to dig into debugging this more seriously in the next few days.

2024-06-14T20:17:34.2816704Z DEBUG    parsl.dataflow.dflow:dflow.py:687 Got an exception launching task
2024-06-14T20:17:34.2816818Z Traceback (most recent call last):
2024-06-14T20:17:34.2817437Z   File "/home/runner/work/parsl/parsl/parsl/executors/high_throughput/executor.py", line 668, in submit
2024-06-14T20:17:34.2817642Z     fn_buf = pack_res_spec_apply_message(func, args, kwargs,
2024-06-14T20:17:34.2818111Z   File "/home/runner/work/parsl/parsl/parsl/serialize/facade.py", line 87, in pack_res_spec_apply_message
2024-06-14T20:17:34.2818498Z     return pack_apply_message(func, args, (kwargs, resource_specification), buffer_threshold=buffer_threshold)
2024-06-14T20:17:34.2818908Z   File "/home/runner/work/parsl/parsl/parsl/serialize/facade.py", line 58, in pack_apply_message
2024-06-14T20:17:34.2819100Z     b_func = serialize(func, buffer_threshold=buffer_threshold)
2024-06-14T20:17:34.2819460Z   File "/home/runner/work/parsl/parsl/parsl/serialize/facade.py", line 125, in serialize
2024-06-14T20:17:34.2819554Z     raise result
2024-06-14T20:17:34.2819903Z   File "/home/runner/work/parsl/parsl/parsl/serialize/facade.py", line 117, in serialize
2024-06-14T20:17:34.2820182Z     result = method.identifier + b'\n' + method.serialize(obj)
2024-06-14T20:17:34.2820558Z   File "/home/runner/work/parsl/parsl/parsl/serialize/concretes.py", line 61, in serialize
2024-06-14T20:17:34.2820747Z     return dill.dumps(data)
2024-06-14T20:17:34.2821259Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 280, in dumps
2024-06-14T20:17:34.2821495Z     dump(obj, file, protocol, byref, fmode, recurse, **kwds)#, strictio)
2024-06-14T20:17:34.2821982Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 252, in dump
2024-06-14T20:17:34.2822121Z     Pickler(file, protocol, **_kwds).dump(obj)
2024-06-14T20:17:34.2823029Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 420, in dump
2024-06-14T20:17:34.2823259Z     StockPickler.dump(self, obj)
2024-06-14T20:17:34.2823906Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 487, in dump
2024-06-14T20:17:34.2824088Z     self.save(obj)
2024-06-14T20:17:34.2825264Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2825594Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2826086Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2826286Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2826900Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1985, in save_function
2024-06-14T20:17:34.2827068Z     _save_with_postproc(pickler, (_create_function, (
2024-06-14T20:17:34.2827653Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1098, in _save_with_postproc
2024-06-14T20:17:34.2827801Z     pickler.save_reduce(*reduction, obj=obj)
2024-06-14T20:17:34.2828178Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 717, in save_reduce
2024-06-14T20:17:34.2828266Z     save(state)
2024-06-14T20:17:34.2828766Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2828935Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2829273Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2829527Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2830123Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 886, in save_tuple
2024-06-14T20:17:34.2830290Z     save(element)
2024-06-14T20:17:34.2831196Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2831390Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2831785Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2832111Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2833421Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict
2024-06-14T20:17:34.2833711Z     StockPickler.save_dict(pickler, obj)
2024-06-14T20:17:34.2834374Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 971, in save_dict
2024-06-14T20:17:34.2834603Z     self._batch_setitems(obj.items())
2024-06-14T20:17:34.2835313Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 997, in _batch_setitems
2024-06-14T20:17:34.2835429Z     save(v)
2024-06-14T20:17:34.2836004Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2836294Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2836765Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 603, in save
2024-06-14T20:17:34.2836988Z     self.save_reduce(obj=obj, *rv)
2024-06-14T20:17:34.2837468Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 692, in save_reduce
2024-06-14T20:17:34.2837727Z     save(args)
2024-06-14T20:17:34.2838270Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2838442Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2838786Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2838968Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2839350Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 886, in save_tuple
2024-06-14T20:17:34.2839440Z     save(element)
2024-06-14T20:17:34.2839946Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2840109Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2840546Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2840742Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2841327Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1985, in save_function
2024-06-14T20:17:34.2841494Z     _save_with_postproc(pickler, (_create_function, (
2024-06-14T20:17:34.2842078Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1098, in _save_with_postproc
2024-06-14T20:17:34.2842220Z     pickler.save_reduce(*reduction, obj=obj)
2024-06-14T20:17:34.2842594Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 717, in save_reduce
2024-06-14T20:17:34.2842682Z     save(state)
2024-06-14T20:17:34.2843491Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2843707Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2844069Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2844423Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2844814Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 886, in save_tuple
2024-06-14T20:17:34.2844905Z     save(element)
2024-06-14T20:17:34.2845431Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2845598Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2845928Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2846104Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2846670Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict
2024-06-14T20:17:34.2846800Z     StockPickler.save_dict(pickler, obj)
2024-06-14T20:17:34.2847536Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 971, in save_dict
2024-06-14T20:17:34.2847678Z     self._batch_setitems(obj.items())
2024-06-14T20:17:34.2848101Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 1002, in _batch_setitems
2024-06-14T20:17:34.2848185Z     save(v)
2024-06-14T20:17:34.2848704Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2848863Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2849193Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2849362Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2849967Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1985, in save_function
2024-06-14T20:17:34.2850196Z     _save_with_postproc(pickler, (_create_function, (
2024-06-14T20:17:34.2850790Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1098, in _save_with_postproc
2024-06-14T20:17:34.2851033Z     pickler.save_reduce(*reduction, obj=obj)
2024-06-14T20:17:34.2851404Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 692, in save_reduce
2024-06-14T20:17:34.2851499Z     save(args)
2024-06-14T20:17:34.2851999Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2852166Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2852516Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2852691Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2853075Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 901, in save_tuple
2024-06-14T20:17:34.2853165Z     save(element)
2024-06-14T20:17:34.2853666Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2853832Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2854168Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2854346Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2854715Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 886, in save_tuple
2024-06-14T20:17:34.2854807Z     save(element)
2024-06-14T20:17:34.2855289Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2855446Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2855774Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2855943Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2856314Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 931, in save_list
2024-06-14T20:17:34.2856421Z     self._batch_appends(obj)
2024-06-14T20:17:34.2856823Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 955, in _batch_appends
2024-06-14T20:17:34.2856909Z     save(x)
2024-06-14T20:17:34.2857397Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2857561Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2858048Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 603, in save
2024-06-14T20:17:34.2858193Z     self.save_reduce(obj=obj, *rv)
2024-06-14T20:17:34.2858590Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 717, in save_reduce
2024-06-14T20:17:34.2858687Z     save(state)
2024-06-14T20:17:34.2859187Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2859343Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2859766Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2859950Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2860533Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict
2024-06-14T20:17:34.2860658Z     StockPickler.save_dict(pickler, obj)
2024-06-14T20:17:34.2861033Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 971, in save_dict
2024-06-14T20:17:34.2861146Z     self._batch_setitems(obj.items())
2024-06-14T20:17:34.2861537Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 997, in _batch_setitems
2024-06-14T20:17:34.2861624Z     save(v)
2024-06-14T20:17:34.2862109Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2862271Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2862597Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2862838Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2863207Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 931, in save_list
2024-06-14T20:17:34.2863311Z     self._batch_appends(obj)
2024-06-14T20:17:34.2863705Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 958, in _batch_appends
2024-06-14T20:17:34.2863793Z     save(tmp[0])
2024-06-14T20:17:34.2864290Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2864446Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2864764Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 603, in save
2024-06-14T20:17:34.2864879Z     self.save_reduce(obj=obj, *rv)
2024-06-14T20:17:34.2865333Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 692, in save_reduce
2024-06-14T20:17:34.2865485Z     save(args)
2024-06-14T20:17:34.2866099Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2866262Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2866581Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2866749Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2867117Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 886, in save_tuple
2024-06-14T20:17:34.2867206Z     save(element)
2024-06-14T20:17:34.2867694Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2867848Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2868179Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2868352Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2869136Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1473, in save_instancemethod0
2024-06-14T20:17:34.2869396Z     pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj)
2024-06-14T20:17:34.2869920Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 692, in save_reduce
2024-06-14T20:17:34.2870042Z     save(args)
2024-06-14T20:17:34.2870562Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2870716Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2871042Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2871210Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2871694Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 886, in save_tuple
2024-06-14T20:17:34.2871792Z     save(element)
2024-06-14T20:17:34.2872284Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2872437Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2872756Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 603, in save
2024-06-14T20:17:34.2872868Z     self.save_reduce(obj=obj, *rv)
2024-06-14T20:17:34.2873236Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 717, in save_reduce
2024-06-14T20:17:34.2873327Z     save(state)
2024-06-14T20:17:34.2873802Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2873963Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2874285Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2874458Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2875102Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict
2024-06-14T20:17:34.2875277Z     StockPickler.save_dict(pickler, obj)
2024-06-14T20:17:34.2875791Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 971, in save_dict
2024-06-14T20:17:34.2875910Z     self._batch_setitems(obj.items())
2024-06-14T20:17:34.2876312Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 997, in _batch_setitems
2024-06-14T20:17:34.2876394Z     save(v)
2024-06-14T20:17:34.2876887Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2877046Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2877364Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 603, in save
2024-06-14T20:17:34.2877489Z     self.save_reduce(obj=obj, *rv)
2024-06-14T20:17:34.2877849Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 717, in save_reduce
2024-06-14T20:17:34.2877943Z     save(state)
2024-06-14T20:17:34.2878435Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2878595Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2878924Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2879179Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2880200Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict
2024-06-14T20:17:34.2880352Z     StockPickler.save_dict(pickler, obj)
2024-06-14T20:17:34.2880741Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 971, in save_dict
2024-06-14T20:17:34.2880857Z     self._batch_setitems(obj.items())
2024-06-14T20:17:34.2881261Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 997, in _batch_setitems
2024-06-14T20:17:34.2881356Z     save(v)
2024-06-14T20:17:34.2881876Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2882045Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2882377Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2882554Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2882921Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 886, in save_tuple
2024-06-14T20:17:34.2883010Z     save(element)
2024-06-14T20:17:34.2883509Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2883670Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2884122Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 603, in save
2024-06-14T20:17:34.2884443Z     self.save_reduce(obj=obj, *rv)
2024-06-14T20:17:34.2884837Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 717, in save_reduce
2024-06-14T20:17:34.2884968Z     save(state)
2024-06-14T20:17:34.2885704Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2885886Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2886230Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2886463Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2887124Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict
2024-06-14T20:17:34.2887254Z     StockPickler.save_dict(pickler, obj)
2024-06-14T20:17:34.2887634Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 971, in save_dict
2024-06-14T20:17:34.2887895Z     self._batch_setitems(obj.items())
2024-06-14T20:17:34.2888304Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 997, in _batch_setitems
2024-06-14T20:17:34.2888389Z     save(v)
2024-06-14T20:17:34.2888895Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2889060Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2889388Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 603, in save
2024-06-14T20:17:34.2889501Z     self.save_reduce(obj=obj, *rv)
2024-06-14T20:17:34.2889873Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 717, in save_reduce
2024-06-14T20:17:34.2889965Z     save(state)
2024-06-14T20:17:34.2890450Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2890717Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2891324Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 560, in save
2024-06-14T20:17:34.2891645Z     f(self, obj)  # Call unbound method with explicit self
2024-06-14T20:17:34.2892729Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict
2024-06-14T20:17:34.2892972Z     StockPickler.save_dict(pickler, obj)
2024-06-14T20:17:34.2893647Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 971, in save_dict
2024-06-14T20:17:34.2893875Z     self._batch_setitems(obj.items())
2024-06-14T20:17:34.2894325Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 997, in _batch_setitems
2024-06-14T20:17:34.2894418Z     save(v)
2024-06-14T20:17:34.2894976Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 414, in save
2024-06-14T20:17:34.2895154Z     StockPickler.save(self, obj, save_persistent_id)
2024-06-14T20:17:34.2895493Z   File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/pickle.py", line 578, in save
2024-06-14T20:17:34.2895605Z     rv = reduce(self.proto)
2024-06-14T20:17:34.2895828Z TypeError: cannot pickle '_queue.SimpleQueue' object
2024-06-14T20:17:34.2895837Z 
2024-06-14T20:17:34.2896068Z During handling of the above exception, another exception occurred:
2024-06-14T20:17:34.2896074Z 
2024-06-14T20:17:34.2896192Z Traceback (most recent call last):
2024-06-14T20:17:34.2896622Z   File "/home/runner/work/parsl/parsl/parsl/dataflow/dflow.py", line 677, in _launch_if_ready_async
2024-06-14T20:17:34.2896753Z     exec_fu = self.launch_task(task_record)
2024-06-14T20:17:34.2897113Z   File "/home/runner/work/parsl/parsl/parsl/dataflow/dflow.py", line 765, in launch_task
2024-06-14T20:17:34.2897507Z     exec_fu = executor.submit(function, task_record['resource_specification'], *args, **kwargs)
2024-06-14T20:17:34.2898295Z   File "/home/runner/work/parsl/parsl/parsl/executors/high_throughput/executor.py", line 672, in submit
2024-06-14T20:17:34.2898475Z     raise SerializationError(func.__name__)
2024-06-14T20:17:34.2899481Z parsl.serialize.errors.SerializationError: Failed to serialize objects for an invocation of function echo_launch_cmd. Refer https://parsl.readthedocs.io/en/latest/faq.html#addressing-serializationerror

@benclifford
Copy link
Collaborator

one thing that is suspicious from that stack is that ...

2024-06-14T20:17:34.2846670Z   File "/home/runner/work/parsl/parsl/.venv/lib/python3.8/site-packages/dill/_dill.py", line 1217, in save_module_dict

... it looks like the code is trying to serialize a module (probably the containing module for a defined function) which is almost always not what should be happening in Parsl, and that can sometimes lead to bringing in way more spurious stuff into the object graph...

So that's probably the first place I'll start poking.

@benclifford
Copy link
Collaborator

i'm able to recreate this locally by running these two test cases in a specific sequence:

$ pytest parsl/tests/test_bash_apps/test_inputs_default.py parsl/tests/test_mpi_apps/test_mpi_mode_enabled.py  --config local

something happening in this newly introduced test_inputs_default test is interacting badly with what's happening in that MPI test, to do with module and function definitions...

@benclifford
Copy link
Collaborator

another pairing that fails for me locally: pytest parsl/tests/test_bash_apps/test_inputs_default.py parsl/tests/test_staging/test_zip_out.py --config local

@benclifford
Copy link
Collaborator

ok, this is some "interesting" serialization stuff - @arhag23 I would leave this PR as it is and go do something else for now, and then let's look at this again when I've looked deeper, rather than you waiting on this.

@benclifford
Copy link
Collaborator

I made this change to a copy of your branch and it seems to make things work. I mostly understand what's going on there (and it's something that shouldn't have been happening in parsl, that just happens to have never apparently broken before...)

49a335f

I'll write up a proper pull request for just this change with more details.

benclifford added a commit that referenced this pull request Jun 19, 2024
This addresses behaviour subtle enough we've gone years without noticing
but is now causing problems for a test introduced in apparently-unrelated
PR #3489.

What's happening in the removed line is that update_wrapper is being used
accidentally in two ways:

i) a functional style: return a remote_side_bash_executor that looks like
func

and

ii) modify remote_side_bash_executor to look like func

That second step is problematic: it happens to every single bash_app
decoration - so remote_side_bash_executor accumulates "look-alike" context
(attributes?) from every function that is being decorated.

$ cat uw1.py
from functools import update_wrapper

def a():
  pass

def b():
  return 7

print("b looks like this:")
print(repr(b))

print("update_wrapper of b to look like a:")
print(update_wrapper(b, a))

print("b looks like this:")
print(repr(b))

$ python3 uw1.py
b looks like this:
<function b at 0x70fd0ff1e2a0>
update_wrapper of b to look like a:
<function a at 0x70fd0ff1e2a0>
b looks like this:
<function a at 0x70fd0ff1e2a0>

In the case of PR #3489, that PR introduces a bash_app that cannot be
serialized. That's fine, because it only tries to run it in a
ThreadPoolExecutor, and executor-specific apps are fine (see, for example,
the concept of join apps, which must run in the main DFK process)

However, context from that cannot-be-serialized app is accumulated in
remote_side_bash_executor, and once that has happened,
remote_side_bash_executor can never be serialized again in the same process,
meaning that any later defined bash_apps can never run in a serilalized
context.

In the PR #3489 vs CI case, with randomised test orders, that results in
`--config local` tests randomly failing, when they happen to be the first
bash_app+remote execution test that runs after the newly introduced PR #3489
tests.

Other problems with this update wrapper: it changes the name of the
function: parsl has multiple @wraps decorations, for a similar purpose,
to disguise wrapped functions as the original app. This is not so
necessary in modern times (although is in some subtle cases) - in most
cases, this is (I think, @yadudoc?) to get the overridden object to have
a name attribute that matches the underlying app because it was sometimes
used as the "name" of the app for example in logs. In this case, that isn't
so relevant: the remote_side_bash_executor wrapped code is then immediately
re-wrapped in a `partial` object, which has a __name__ attribute set on it
right after, based on the original func. So there's no need to do anything
to the remote_side_bash_executor.

Renaming the remote_side_bash_executor globally also causes very confusing
object representations when trying to debug: the remote_side_bash_executor
now claims to be an app function, and much more confusingly, it can
claim to be a *different* app function than is being invoked.
benclifford added a commit that referenced this pull request Jun 19, 2024
tl;dr bash_app unexpectedly mutates the global remote_side_bash_executor
function, which is bad. This PR makes it not do that.

This addresses behaviour subtle enough we've gone years without noticing
but is now causing problems for a test introduced in apparently-unrelated
PR #3489.

What was happening before this PR, in the removed line is that
update_wrapper is being used accidentally in two ways:

i) a functional style: return a remote_side_bash_executor that looks like
   self.func

and

ii) modify remote_side_bash_executor to look like self.func

That second step is problematic: it modifies a global object (the
remote_side_bash_executor callable object) on every bash_app decoration,
and so leaves it finally looking like the most recent bash_app decoration.

$ cat uw1.py
from functools import update_wrapper

def a():
  pass

def b():
  return 7

print("b looks like this:")
print(repr(b))

print("update_wrapper of b to look like a:")
print(update_wrapper(b, a))

print("b looks like this:")
print(repr(b))

$ python3 uw1.py
b looks like this:
<function b at 0x70fd0ff1e2a0>
update_wrapper of b to look like a:
<function a at 0x70fd0ff1e2a0>
b looks like this:
<function a at 0x70fd0ff1e2a0>

In the case of PR #3489, that PR introduces a bash_app that cannot be
serialized. That's fine, because it only tries to run it in a
ThreadPoolExecutor, and executor-specific apps are fine (see, for example,
the concept of join apps, which must run in the main DFK process)

However, context from that cannot-be-serialized app is accumulated in
remote_side_bash_executor, and once that has happened,
remote_side_bash_executor can never be serialized again in the same process,
meaning that any later defined bash_apps can never run in a serilalized
context.

The "context" here is specifically the __wrapped__ attribute of
remote_side_bash_executor: when remote_side_bash_executor is serialized
(as a code object, because it does not have a matching global __module__.__name__ due to the decoration), the attributes are serialized including the
__wrapped__ attribute, which contains the underlying function of the most
recent bash decoration (not the underlying function of the bash app
currently being invoked). That function is, in this case, the function
that cannot be serialized.

In the PR #3489 vs CI case, with randomised test orders, that results in
`--config local` tests randomly failing, when they happen to be the first
bash_app+remote execution test that runs after the newly introduced PR #3489
tests.

Other problems with this update wrapper: it changes the name of the
function: parsl has multiple @wraps decorations, for a similar purpose,
to disguise wrapped functions as the original app. This is not so
necessary in modern times (although is in some subtle cases) - in most
cases, this is (I think, @yadudoc?) to get the overridden object to have
a name attribute that matches the underlying app because it was sometimes
used as the "name" of the app for example in logs. In this case, that isn't
so relevant: the remote_side_bash_executor wrapped code is then immediately
re-wrapped in a `partial` object, which has a __name__ attribute set on it
right after, based on the original func. So there's no need to do anything
to the remote_side_bash_executor.

Renaming the remote_side_bash_executor globally also causes very confusing
object representations when trying to debug: the remote_side_bash_executor
now claims to be an app function, and much more confusingly, it can
claim to be a *different* app function than is being invoked.

Removing this rename probably has some effect on serialization: if the
remote_side_bash_executor has a __module__.__name__ that matches the
global definition of the same name, then it can be send as a pickle-style
name-of-function, rather than a dill-style code object. That's probably
good for efficiency.

TODO: test that serialization changes by manual observation. I wonder if
there is an automated test to check that these parsl internal functions
definitely get sent by reference? and are there other top-level functions
that are wrapped and so broken this way? (incidentally this is an argument
against using wrapper style coding in parsl vs partial style function
application... maybe theres a separate issue to note there?)
What's the test assertion here for "how things are serialized?" - plug
something into dill or the parsl serializer library to say that test
serialization must follow a particular code path? this is getting out of
scope for this PR, though - so maybe turn this TODO into an issue?
benclifford added a commit that referenced this pull request Jun 20, 2024
tl;dr bash_app unexpectedly mutates the global remote_side_bash_executor
function, which is bad. This PR makes it not do that.

This addresses behaviour subtle enough we've gone years without noticing
but is now causing problems for a test introduced in apparently-unrelated
PR #3489.

What was happening before this PR, in the removed line is that
update_wrapper is being used in two ways:

i) Deliberately, a functional style: return a remote_side_bash_executor
   that looks like self.func

and

ii) Accidentally, modify the global remote_side_bash_executor to look
    like self.func

That second step is problematic: it modifies a global object (the
remote_side_bash_executor callable object) on every bash_app decoration,
and so leaves it finally looking like the most recent bash_app decoration.

For example:

```
$ cat uw1.py
from functools import update_wrapper

def a():
  pass

def b():
  return 7

print("b looks like this:")
print(repr(b))

print("update_wrapper of b to look like a:")
print(update_wrapper(b, a))

print("b looks like this:")
print(repr(b))

$ python3 uw1.py
b looks like this:
<function b at 0x70fd0ff1e2a0>
update_wrapper of b to look like a:
<function a at 0x70fd0ff1e2a0>
b looks like this:
<function a at 0x70fd0ff1e2a0>
```

PR #3489 introduces a bash_app that cannot be serialized. That's fine in
the context of that PR, because it only tries to run it in a
ThreadPoolExecutor where serialization does not happen, and executor-specific
apps are fine - see, for example, the concept of join apps, which must run
in the main DFK process in a ThreadPoolExecutor.

However, in certain test case orders, the `__wrapped__` value of
remote_side_bash_executor points to that "bad" bash_app, and when that has
happened, remote_side_bash_executor cannot be serialized as part of an
app invocation to a remote worker in a different (for example, htex-using)
test.

This PR removes that update_wrapper, causing a few changes: because
__wrapped__ is now not set, the function for the last-decorated bash_app
is no longer sent along side every invocation of every other bash_app.
This removes the error in PR #3489.

Because the __name__ of remote_side_bash_executor is no longer mutated, the
default pickle pass-by-name serialization can happen, as pickle is able to
assume that it can import the function as a global on the remote side rather
than sending the modified definition of remote_side_bash_executor.

These two changes result in a reduction of the serialized form of an
example bash_app (measured in DillCallableSerializer.serialize) from
6940 bytes to 2305 bytes. Issue #3941 contains a feature request to look at
those remaining 2305 bytes to see if anything else can be removed here.

This change also removes some confusing repr() behaviour when debugging:
when update_wrapper is used, any reference in reprs to
remote_side_bash_executor are output as references to the most recently
decorated bash_app. After this PR, when update_wrapper is removed, references
are output correctly.
@benclifford
Copy link
Collaborator

@arhag23 @astro-friedel I'm hoping that PR #3492 fixes this test failure.

benclifford added a commit that referenced this pull request Jun 24, 2024
tl;dr bash_app unexpectedly mutates the global remote_side_bash_executor
function, which is bad. This PR makes it not do that.

This addresses behaviour subtle enough we've gone years without noticing
but is now causing problems for a test introduced in apparently-unrelated
PR #3489.

What was happening before this PR, in the removed line is that
update_wrapper is being used in two ways:

i) Deliberately, a functional style: return a remote_side_bash_executor
   that looks like self.func

and

ii) Accidentally, modify the global remote_side_bash_executor to look
    like self.func

That second step is problematic: it modifies a global object (the
remote_side_bash_executor callable object) on every bash_app decoration,
and so leaves it finally looking like the most recent bash_app decoration.

For example:

```
$ cat uw1.py
from functools import update_wrapper

def a():
  pass

def b():
  return 7

print("b looks like this:")
print(repr(b))

print("update_wrapper of b to look like a:")
print(update_wrapper(b, a))

print("b looks like this:")
print(repr(b))

$ python3 uw1.py
b looks like this:
<function b at 0x70fd0ff1e2a0>
update_wrapper of b to look like a:
<function a at 0x70fd0ff1e2a0>
b looks like this:
<function a at 0x70fd0ff1e2a0>
```

PR #3489 introduces a bash_app that cannot be serialized. That's fine in
the context of that PR, because it only tries to run it in a
ThreadPoolExecutor where serialization does not happen, and executor-specific
apps are fine - see, for example, the concept of join apps, which must run
in the main DFK process in a ThreadPoolExecutor.

However, in certain test case orders, the `__wrapped__` value of
remote_side_bash_executor points to that "bad" bash_app, and when that has
happened, remote_side_bash_executor cannot be serialized as part of an
app invocation to a remote worker in a different (for example, htex-using)
test.

This PR removes that update_wrapper, causing a few changes: because
__wrapped__ is now not set, the function for the last-decorated bash_app
is no longer sent along side every invocation of every other bash_app.
This removes the error in PR #3489.

Because the __name__ of remote_side_bash_executor is no longer mutated, the
default pickle pass-by-name serialization can happen, as pickle is able to
assume that it can import the function as a global on the remote side rather
than sending the modified definition of remote_side_bash_executor.

These two changes result in a reduction of the serialized form of an
example bash_app (measured in DillCallableSerializer.serialize) from
6940 bytes to 2305 bytes. Issue #3941 contains a feature request to look at
those remaining 2305 bytes to see if anything else can be removed here.

This change also removes some confusing repr() behaviour when debugging:
when update_wrapper is used, any reference in reprs to
remote_side_bash_executor are output as references to the most recently
decorated bash_app. After this PR, when update_wrapper is removed, references
are output correctly.

Co-authored-by: Kevin Hunter Kesling <kevin@globus.org>
@benclifford
Copy link
Collaborator

@arhag23 #3492 is merged and this PR passes tests now - so I think its OK to merge, if you're happy with it too

@arhag23 arhag23 marked this pull request as ready for review July 1, 2024 16:28
@arhag23
Copy link
Contributor Author

arhag23 commented Jul 1, 2024

Yes, I'm happy it in this state.

@benclifford benclifford changed the title Python bash app parity for handling inputs/outputs default arguments Treat input/output default arguments like other magic keywords Jul 1, 2024
@benclifford
Copy link
Collaborator

@arhag23 Can you amend your description "In a previous PR, some fields where the default values of outputs and inputs for AppBase were removed." to link to the PR that you are talking about?

@benclifford benclifford changed the title Treat input/output default arguments like other magic keywords Treat python_app input/output default arguments like other magic keywords, and like bash_app Jul 1, 2024
@arhag23
Copy link
Contributor Author

arhag23 commented Jul 1, 2024

I amended it.

@benclifford benclifford merged commit f62110d into Parsl:master Jul 2, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants