From af5a169831e7bae824aa44fa772663fabd8d81a8 Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 13:05:47 +1000 Subject: [PATCH 01/12] Add command line interface with crash function --- pydra/scripts/cli.py | 57 ++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 5 +++- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 pydra/scripts/cli.py diff --git a/pydra/scripts/cli.py b/pydra/scripts/cli.py new file mode 100644 index 0000000000..0a69cc18d2 --- /dev/null +++ b/pydra/scripts/cli.py @@ -0,0 +1,57 @@ +from pathlib import Path +import pdb +import sys + +from IPython.core import ultratb +import click +import cloudpickle as cp + +CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) +ExistingFilePath = click.Path(exists=True, dir_okay=False, resolve_path=True) + + +@click.group(context_settings=CONTEXT_SETTINGS) +def cli(): + pass + + +@cli.command(context_settings=CONTEXT_SETTINGS) +@click.argument("crashfile", type=ExistingFilePath) +@click.option( + "-r", "--rerun", is_flag=True, flag_value=True, help="Rerun crashed code." +) +@click.option( + "-d", + "--debugger", + type=click.Choice([None, "ipython", "pdb"]), + help="Debugger to use when rerunning", +) +def crash(crashfile, rerun, debugger=None): + """Display a crash file and rerun if required.""" + if crashfile.endswith(("pkl", "pklz")): + with open(crashfile, "rb") as f: + crash_content = cp.load(f) + print("".join(crash_content["error message"])) + + if rerun: + jobfile = Path(crashfile).parent / "_job.pklz" + if jobfile.exists(): + with open(jobfile, "rb") as f: + job_obj = cp.load(f) + + if debugger == "ipython": + sys.excepthook = ultratb.FormattedTB( + mode="Verbose", theme_name="Linux", call_pdb=True + ) + + try: + job_obj.run(rerun=True) + except Exception: # noqa: E722 + if debugger == "pdb": + pdb.post_mortem() + elif debugger == "ipython": + raise + else: + raise FileNotFoundError(f"Job file {jobfile} not found") + else: + raise ValueError("Only pickled crashfiles are supported") diff --git a/pyproject.toml b/pyproject.toml index e93f75dc94..0c638c2b6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ dependencies = [ "filelock >=3.0.0", "fileformats >=0.15.0a7", "platformdirs >=2", + "ipython", ] license = { file = "LICENSE" } authors = [{ name = "Nipype developers", email = "neuroimaging@python.org" }] @@ -43,7 +44,6 @@ doc = [ "fileformats-medimage >= v0.10.0a2", "fileformats-medimage-extras >= v0.10.0a2", "furo>=2022.2.14.1", - "ipython", "ipykernel", "ipywidgets", "matplotlib", @@ -114,6 +114,9 @@ documentation = "https://nipype.github.io/pydra/" homepage = "https://nipype.github.io/pydra/" repository = "https://github.com/nipype/pydra.git" +[project.scripts] +pydracli = "pydra.scripts.cli:cli" + [tool.hatch.build] packages = ["pydra"] exclude = ["tests"] From 3358a408130f7565cd579d6265e7f6e9a4be381d Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 13:27:26 +1000 Subject: [PATCH 02/12] Add pydracli crash section in tutorial --- docs/source/tutorial/3-troubleshooting.ipynb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/source/tutorial/3-troubleshooting.ipynb b/docs/source/tutorial/3-troubleshooting.ipynb index 126280e349..3f87a19fca 100644 --- a/docs/source/tutorial/3-troubleshooting.ipynb +++ b/docs/source/tutorial/3-troubleshooting.ipynb @@ -141,7 +141,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The error pickle files can be loaded using the `cloudpickle` library, noting that it is\n", + "The error pickle files can be viewed using the `pydracli crash` command, with the possibility of rerunning and debugging the job. Note that it is\n", "important to use the same Python version to load the files that was used to run the Pydra\n", "workflow" ] @@ -152,17 +152,9 @@ "metadata": {}, "outputs": [], "source": [ - "from pydra.utils.general import default_run_cache_root\n", - "import cloudpickle as cp\n", - "from pprint import pprint\n", - "from pydra.tasks.testing import Divide\n", - "\n", - "with open(\n", - " default_run_cache_root / Divide(x=15, y=0)._checksum / \"_error.pklz\", \"rb\"\n", - ") as f:\n", - " error = cp.load(f)\n", + "%%bash\n", "\n", - "pprint(error)" + "pydracli crash _error.pklz --rerun --debugger pdb" ] }, { From 75b0e33d994bc42f777de30e9eae15aaccb68173 Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 13:41:46 +1000 Subject: [PATCH 03/12] Only require user to have Ipython installed for using the ipython debugger --- pydra/scripts/cli.py | 14 ++++++++++---- pyproject.toml | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pydra/scripts/cli.py b/pydra/scripts/cli.py index 0a69cc18d2..b7ee1d408a 100644 --- a/pydra/scripts/cli.py +++ b/pydra/scripts/cli.py @@ -2,7 +2,6 @@ import pdb import sys -from IPython.core import ultratb import click import cloudpickle as cp @@ -40,9 +39,16 @@ def crash(crashfile, rerun, debugger=None): job_obj = cp.load(f) if debugger == "ipython": - sys.excepthook = ultratb.FormattedTB( - mode="Verbose", theme_name="Linux", call_pdb=True - ) + try: + from IPython.core import ultratb + + sys.excepthook = ultratb.FormattedTB( + mode="Verbose", theme_name="Linux", call_pdb=True + ) + except ImportError: + raise ImportError( + "'Ipython' needs to be installed to use the 'ipython' debugger" + ) try: job_obj.run(rerun=True) diff --git a/pyproject.toml b/pyproject.toml index 0c638c2b6e..72f4ccabdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ dependencies = [ "filelock >=3.0.0", "fileformats >=0.15.0a7", "platformdirs >=2", - "ipython", ] license = { file = "LICENSE" } authors = [{ name = "Nipype developers", email = "neuroimaging@python.org" }] @@ -44,6 +43,7 @@ doc = [ "fileformats-medimage >= v0.10.0a2", "fileformats-medimage-extras >= v0.10.0a2", "furo>=2022.2.14.1", + "ipython", "ipykernel", "ipywidgets", "matplotlib", From c3b7832a16903369b25f8bc2676bb2c4df216bce Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 15:05:44 +1000 Subject: [PATCH 04/12] Add test for pydracli crash --- pydra/conftest.py | 38 +++++++++++++++++++++++++------ pydra/scripts/tests/test_crash.py | 24 +++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 pydra/scripts/tests/test_crash.py diff --git a/pydra/conftest.py b/pydra/conftest.py index 2214399084..f552736a86 100644 --- a/pydra/conftest.py +++ b/pydra/conftest.py @@ -1,6 +1,8 @@ import shutil import os import pytest +import typing as ty +from click.testing import CliRunner, Result as CliResult os.environ["NO_ET"] = "true" @@ -41,17 +43,39 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("any_worker", available_workers) +@pytest.fixture +def cli_runner(catch_cli_exceptions: bool) -> ty.Callable[..., ty.Any]: + def invoke( + *args: ty.Any, catch_exceptions: bool = catch_cli_exceptions, **kwargs: ty.Any + ) -> CliResult: + runner = CliRunner() + result = runner.invoke(*args, catch_exceptions=catch_exceptions, **kwargs) # type: ignore[misc] + return result + + return invoke + + # For debugging in IDE's don't catch raised exceptions and let the IDE # break at it -if os.getenv("_PYTEST_RAISE", "0") != "0": # pragma: no cover +if os.getenv("_PYTEST_RAISE", "0") != "0": + + @pytest.hookimpl(tryfirst=True) + def pytest_exception_interact(call: pytest.CallInfo[ty.Any]) -> None: + if call.excinfo is not None: + raise call.excinfo.value + + @pytest.hookimpl(tryfirst=True) + def pytest_internalerror(excinfo: pytest.ExceptionInfo[BaseException]) -> None: + raise excinfo.value + + CATCH_CLI_EXCEPTIONS = False +else: + CATCH_CLI_EXCEPTIONS = True - @pytest.hookimpl(tryfirst=True) # pragma: no cover - def pytest_exception_interact(call): # pragma: no cover - raise call.excinfo.value # pragma: no cover - @pytest.hookimpl(tryfirst=True) # pragma: no cover - def pytest_internalerror(excinfo): # pragma: no cover - raise excinfo.value # pragma: no cover +@pytest.fixture +def catch_cli_exceptions() -> bool: + return CATCH_CLI_EXCEPTIONS # Example VSCode launch configuration for debugging unittests diff --git a/pydra/scripts/tests/test_crash.py b/pydra/scripts/tests/test_crash.py new file mode 100644 index 0000000000..fc845d267a --- /dev/null +++ b/pydra/scripts/tests/test_crash.py @@ -0,0 +1,24 @@ +from pydra.scripts.cli import crash +from pydra.utils.general import default_run_cache_root +from pydra.tasks.testing import Divide +from traceback import format_exception +import typing as ty + + +# @pytest.mark.xfail(reason="Need to fix a couple of things after syntax changes") +def test_crash_cli(cli_runner): + result = cli_runner( + crash, + [ + f"{default_run_cache_root}/{Divide(x=15, y=0)._checksum}/_error.pklz", + "--rerun", + "--debugger", + "pdb", + ], + ) + assert result.exit_code == 0, show_cli_trace(result) + + +def show_cli_trace(result: ty.Any) -> str: + "Used in testing to show traceback of CLI output" + return "".join(format_exception(*result.exc_info)) From 93b331023ea09004b83a394699d8168f6b598fbe Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 15:56:13 +1000 Subject: [PATCH 05/12] Make sure to generate error file in test_crash --- pydra/scripts/tests/test_crash.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pydra/scripts/tests/test_crash.py b/pydra/scripts/tests/test_crash.py index fc845d267a..dd55c05b26 100644 --- a/pydra/scripts/tests/test_crash.py +++ b/pydra/scripts/tests/test_crash.py @@ -1,16 +1,20 @@ +import pytest from pydra.scripts.cli import crash -from pydra.utils.general import default_run_cache_root from pydra.tasks.testing import Divide from traceback import format_exception import typing as ty # @pytest.mark.xfail(reason="Need to fix a couple of things after syntax changes") -def test_crash_cli(cli_runner): +def test_crash_cli(cli_runner, tmp_path): + divide = Divide(x=15, y=0) + with pytest.raises(ZeroDivisionError): + divide(cache_root=tmp_path) + result = cli_runner( crash, [ - f"{default_run_cache_root}/{Divide(x=15, y=0)._checksum}/_error.pklz", + f"{tmp_path}/{divide._checksum}/_error.pklz", "--rerun", "--debugger", "pdb", From 9327cbf272061c51d7562163387c9a91e421ae40 Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 13:05:47 +1000 Subject: [PATCH 06/12] Add command line interface with crash function --- pydra/scripts/cli.py | 57 ++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 5 +++- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 pydra/scripts/cli.py diff --git a/pydra/scripts/cli.py b/pydra/scripts/cli.py new file mode 100644 index 0000000000..0a69cc18d2 --- /dev/null +++ b/pydra/scripts/cli.py @@ -0,0 +1,57 @@ +from pathlib import Path +import pdb +import sys + +from IPython.core import ultratb +import click +import cloudpickle as cp + +CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) +ExistingFilePath = click.Path(exists=True, dir_okay=False, resolve_path=True) + + +@click.group(context_settings=CONTEXT_SETTINGS) +def cli(): + pass + + +@cli.command(context_settings=CONTEXT_SETTINGS) +@click.argument("crashfile", type=ExistingFilePath) +@click.option( + "-r", "--rerun", is_flag=True, flag_value=True, help="Rerun crashed code." +) +@click.option( + "-d", + "--debugger", + type=click.Choice([None, "ipython", "pdb"]), + help="Debugger to use when rerunning", +) +def crash(crashfile, rerun, debugger=None): + """Display a crash file and rerun if required.""" + if crashfile.endswith(("pkl", "pklz")): + with open(crashfile, "rb") as f: + crash_content = cp.load(f) + print("".join(crash_content["error message"])) + + if rerun: + jobfile = Path(crashfile).parent / "_job.pklz" + if jobfile.exists(): + with open(jobfile, "rb") as f: + job_obj = cp.load(f) + + if debugger == "ipython": + sys.excepthook = ultratb.FormattedTB( + mode="Verbose", theme_name="Linux", call_pdb=True + ) + + try: + job_obj.run(rerun=True) + except Exception: # noqa: E722 + if debugger == "pdb": + pdb.post_mortem() + elif debugger == "ipython": + raise + else: + raise FileNotFoundError(f"Job file {jobfile} not found") + else: + raise ValueError("Only pickled crashfiles are supported") diff --git a/pyproject.toml b/pyproject.toml index e93f75dc94..0c638c2b6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ dependencies = [ "filelock >=3.0.0", "fileformats >=0.15.0a7", "platformdirs >=2", + "ipython", ] license = { file = "LICENSE" } authors = [{ name = "Nipype developers", email = "neuroimaging@python.org" }] @@ -43,7 +44,6 @@ doc = [ "fileformats-medimage >= v0.10.0a2", "fileformats-medimage-extras >= v0.10.0a2", "furo>=2022.2.14.1", - "ipython", "ipykernel", "ipywidgets", "matplotlib", @@ -114,6 +114,9 @@ documentation = "https://nipype.github.io/pydra/" homepage = "https://nipype.github.io/pydra/" repository = "https://github.com/nipype/pydra.git" +[project.scripts] +pydracli = "pydra.scripts.cli:cli" + [tool.hatch.build] packages = ["pydra"] exclude = ["tests"] From cee8682d18ef04a52ef3fd1c505a9ee97266e423 Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 13:27:26 +1000 Subject: [PATCH 07/12] Add pydracli crash section in tutorial --- docs/source/tutorial/3-troubleshooting.ipynb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/source/tutorial/3-troubleshooting.ipynb b/docs/source/tutorial/3-troubleshooting.ipynb index 126280e349..3f87a19fca 100644 --- a/docs/source/tutorial/3-troubleshooting.ipynb +++ b/docs/source/tutorial/3-troubleshooting.ipynb @@ -141,7 +141,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The error pickle files can be loaded using the `cloudpickle` library, noting that it is\n", + "The error pickle files can be viewed using the `pydracli crash` command, with the possibility of rerunning and debugging the job. Note that it is\n", "important to use the same Python version to load the files that was used to run the Pydra\n", "workflow" ] @@ -152,17 +152,9 @@ "metadata": {}, "outputs": [], "source": [ - "from pydra.utils.general import default_run_cache_root\n", - "import cloudpickle as cp\n", - "from pprint import pprint\n", - "from pydra.tasks.testing import Divide\n", - "\n", - "with open(\n", - " default_run_cache_root / Divide(x=15, y=0)._checksum / \"_error.pklz\", \"rb\"\n", - ") as f:\n", - " error = cp.load(f)\n", + "%%bash\n", "\n", - "pprint(error)" + "pydracli crash _error.pklz --rerun --debugger pdb" ] }, { From e0af48fa3a40b8d7c579024fa99c0f399caec09c Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 13:41:46 +1000 Subject: [PATCH 08/12] Only require user to have Ipython installed for using the ipython debugger --- pydra/scripts/cli.py | 14 ++++++++++---- pyproject.toml | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pydra/scripts/cli.py b/pydra/scripts/cli.py index 0a69cc18d2..b7ee1d408a 100644 --- a/pydra/scripts/cli.py +++ b/pydra/scripts/cli.py @@ -2,7 +2,6 @@ import pdb import sys -from IPython.core import ultratb import click import cloudpickle as cp @@ -40,9 +39,16 @@ def crash(crashfile, rerun, debugger=None): job_obj = cp.load(f) if debugger == "ipython": - sys.excepthook = ultratb.FormattedTB( - mode="Verbose", theme_name="Linux", call_pdb=True - ) + try: + from IPython.core import ultratb + + sys.excepthook = ultratb.FormattedTB( + mode="Verbose", theme_name="Linux", call_pdb=True + ) + except ImportError: + raise ImportError( + "'Ipython' needs to be installed to use the 'ipython' debugger" + ) try: job_obj.run(rerun=True) diff --git a/pyproject.toml b/pyproject.toml index 0c638c2b6e..72f4ccabdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ dependencies = [ "filelock >=3.0.0", "fileformats >=0.15.0a7", "platformdirs >=2", - "ipython", ] license = { file = "LICENSE" } authors = [{ name = "Nipype developers", email = "neuroimaging@python.org" }] @@ -44,6 +43,7 @@ doc = [ "fileformats-medimage >= v0.10.0a2", "fileformats-medimage-extras >= v0.10.0a2", "furo>=2022.2.14.1", + "ipython", "ipykernel", "ipywidgets", "matplotlib", From f8988b7ec1968cad554eef56addbd1cbe19ee59e Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 15:05:44 +1000 Subject: [PATCH 09/12] Add test for pydracli crash --- pydra/conftest.py | 38 +++++++++++++++++++++++++------ pydra/scripts/tests/test_crash.py | 24 +++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 pydra/scripts/tests/test_crash.py diff --git a/pydra/conftest.py b/pydra/conftest.py index 2214399084..f552736a86 100644 --- a/pydra/conftest.py +++ b/pydra/conftest.py @@ -1,6 +1,8 @@ import shutil import os import pytest +import typing as ty +from click.testing import CliRunner, Result as CliResult os.environ["NO_ET"] = "true" @@ -41,17 +43,39 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("any_worker", available_workers) +@pytest.fixture +def cli_runner(catch_cli_exceptions: bool) -> ty.Callable[..., ty.Any]: + def invoke( + *args: ty.Any, catch_exceptions: bool = catch_cli_exceptions, **kwargs: ty.Any + ) -> CliResult: + runner = CliRunner() + result = runner.invoke(*args, catch_exceptions=catch_exceptions, **kwargs) # type: ignore[misc] + return result + + return invoke + + # For debugging in IDE's don't catch raised exceptions and let the IDE # break at it -if os.getenv("_PYTEST_RAISE", "0") != "0": # pragma: no cover +if os.getenv("_PYTEST_RAISE", "0") != "0": + + @pytest.hookimpl(tryfirst=True) + def pytest_exception_interact(call: pytest.CallInfo[ty.Any]) -> None: + if call.excinfo is not None: + raise call.excinfo.value + + @pytest.hookimpl(tryfirst=True) + def pytest_internalerror(excinfo: pytest.ExceptionInfo[BaseException]) -> None: + raise excinfo.value + + CATCH_CLI_EXCEPTIONS = False +else: + CATCH_CLI_EXCEPTIONS = True - @pytest.hookimpl(tryfirst=True) # pragma: no cover - def pytest_exception_interact(call): # pragma: no cover - raise call.excinfo.value # pragma: no cover - @pytest.hookimpl(tryfirst=True) # pragma: no cover - def pytest_internalerror(excinfo): # pragma: no cover - raise excinfo.value # pragma: no cover +@pytest.fixture +def catch_cli_exceptions() -> bool: + return CATCH_CLI_EXCEPTIONS # Example VSCode launch configuration for debugging unittests diff --git a/pydra/scripts/tests/test_crash.py b/pydra/scripts/tests/test_crash.py new file mode 100644 index 0000000000..fc845d267a --- /dev/null +++ b/pydra/scripts/tests/test_crash.py @@ -0,0 +1,24 @@ +from pydra.scripts.cli import crash +from pydra.utils.general import default_run_cache_root +from pydra.tasks.testing import Divide +from traceback import format_exception +import typing as ty + + +# @pytest.mark.xfail(reason="Need to fix a couple of things after syntax changes") +def test_crash_cli(cli_runner): + result = cli_runner( + crash, + [ + f"{default_run_cache_root}/{Divide(x=15, y=0)._checksum}/_error.pklz", + "--rerun", + "--debugger", + "pdb", + ], + ) + assert result.exit_code == 0, show_cli_trace(result) + + +def show_cli_trace(result: ty.Any) -> str: + "Used in testing to show traceback of CLI output" + return "".join(format_exception(*result.exc_info)) From 72fb2402cab658b848d34f31ff3be2ae563e257c Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Sun, 22 Jun 2025 15:56:13 +1000 Subject: [PATCH 10/12] Make sure to generate error file in test_crash --- pydra/scripts/tests/test_crash.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pydra/scripts/tests/test_crash.py b/pydra/scripts/tests/test_crash.py index fc845d267a..dd55c05b26 100644 --- a/pydra/scripts/tests/test_crash.py +++ b/pydra/scripts/tests/test_crash.py @@ -1,16 +1,20 @@ +import pytest from pydra.scripts.cli import crash -from pydra.utils.general import default_run_cache_root from pydra.tasks.testing import Divide from traceback import format_exception import typing as ty # @pytest.mark.xfail(reason="Need to fix a couple of things after syntax changes") -def test_crash_cli(cli_runner): +def test_crash_cli(cli_runner, tmp_path): + divide = Divide(x=15, y=0) + with pytest.raises(ZeroDivisionError): + divide(cache_root=tmp_path) + result = cli_runner( crash, [ - f"{default_run_cache_root}/{Divide(x=15, y=0)._checksum}/_error.pklz", + f"{tmp_path}/{divide._checksum}/_error.pklz", "--rerun", "--debugger", "pdb", From 5d2117ee998559877a32eb888768f776d220772f Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Mon, 23 Jun 2025 10:37:14 +1000 Subject: [PATCH 11/12] Make sure to generate error file in docs --- docs/source/tutorial/3-troubleshooting.ipynb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/source/tutorial/3-troubleshooting.ipynb b/docs/source/tutorial/3-troubleshooting.ipynb index 3f87a19fca..7c3eee8222 100644 --- a/docs/source/tutorial/3-troubleshooting.ipynb +++ b/docs/source/tutorial/3-troubleshooting.ipynb @@ -152,9 +152,19 @@ "metadata": {}, "outputs": [], "source": [ - "%%bash\n", + "from pydra.tasks.testing import Divide\n", + "from pydra.utils.general import default_run_cache_root\n", + "import subprocess\n", "\n", - "pydracli crash _error.pklz --rerun --debugger pdb" + "if __name__ == \"__main__\":\n", + " divide = Divide(x=15, y=0)\n", + " try:\n", + " divide(cache_root=default_run_cache_root)\n", + " except Exception:\n", + " pass\n", + "\n", + " errorfile = default_run_cache_root / divide._checksum / \"_error.pklz\"\n", + " subprocess.run([\"pydracli\", \"crash\", str(errorfile)])" ] }, { From 864a3865f1493e24845438b4ad1927139d3cbe2b Mon Sep 17 00:00:00 2001 From: Wu Jianxiao Date: Mon, 23 Jun 2025 10:55:57 +1000 Subject: [PATCH 12/12] Use bash cell for cli command in docs --- docs/source/tutorial/3-troubleshooting.ipynb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/source/tutorial/3-troubleshooting.ipynb b/docs/source/tutorial/3-troubleshooting.ipynb index 7c3eee8222..d6c67c864c 100644 --- a/docs/source/tutorial/3-troubleshooting.ipynb +++ b/docs/source/tutorial/3-troubleshooting.ipynb @@ -154,7 +154,6 @@ "source": [ "from pydra.tasks.testing import Divide\n", "from pydra.utils.general import default_run_cache_root\n", - "import subprocess\n", "\n", "if __name__ == \"__main__\":\n", " divide = Divide(x=15, y=0)\n", @@ -163,8 +162,18 @@ " except Exception:\n", " pass\n", "\n", - " errorfile = default_run_cache_root / divide._checksum / \"_error.pklz\"\n", - " subprocess.run([\"pydracli\", \"crash\", str(errorfile)])" + " errorfile = default_run_cache_root / divide._checksum / \"_error.pklz\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%bash -s \"$errorfile\"\n", + "\n", + "pydracli crash $1" ] }, {