From da078ce32d6c0659246ebe42b434aefdbb598ff0 Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Wed, 18 Sep 2024 14:03:21 -0700 Subject: [PATCH 01/10] allow for sequences into exp.start() --- smartsim/experiment.py | 21 +++++- tests/test_experiment.py | 155 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 3 deletions(-) diff --git a/smartsim/experiment.py b/smartsim/experiment.py index 24709ccfd..2cf1fe3ee 100644 --- a/smartsim/experiment.py +++ b/smartsim/experiment.py @@ -55,6 +55,17 @@ logger = get_logger(__name__) +def _unpack(jobs: t.Sequence[t.Tuple[Job]] | t.Sequence[str]) -> t.Iterator[str]: + """Unpack any iterable input into exp.start in order to obtain a + single sequence of jobs that can be launched""" + for item in jobs: + + if isinstance(item, t.Iterable): + yield from _unpack(item) + else: + yield item + + def _exp_path_map(exp: "Experiment") -> str: """Mapping function for use by method contextualizer to place the path of the currently-executing experiment into context for log enrichment""" @@ -151,7 +162,10 @@ def __init__(self, name: str, exp_path: str | None = None): experiment """ - def start(self, *jobs: Job) -> tuple[LaunchedJobID, ...]: + # + def start( + self, *jobs: Job | t.Sequence[t.Tuple[Job]] | t.Sequence[Job] + ) -> tuple[LaunchedJobID, ...]: """Execute a collection of `Job` instances. :param jobs: A collection of other job instances to start @@ -159,6 +173,9 @@ def start(self, *jobs: Job) -> tuple[LaunchedJobID, ...]: jobs that can be used to query or alter the status of that particular execution of the job. """ + # If item is instance iterable then unpack and extend the list + if isinstance(jobs, t.Iterable): + jobs = list(tuple(_unpack(jobs))) # Create the run id run_id = datetime.datetime.now().replace(microsecond=0).isoformat() # Generate the root path @@ -170,7 +187,7 @@ def _dispatch( generator: Generator, dispatcher: dispatch.Dispatcher, job: Job, - *jobs: Job, + *jobs: Job | t.Sequence[t.Tuple[Job]], ) -> tuple[LaunchedJobID, ...]: """Dispatch a series of jobs with a particular dispatcher diff --git a/tests/test_experiment.py b/tests/test_experiment.py index aff32604c..0863151ab 100644 --- a/tests/test_experiment.py +++ b/tests/test_experiment.py @@ -34,14 +34,16 @@ import time import typing as t import uuid +from os import path as osp import pytest from smartsim._core import dispatch -from smartsim._core.control.interval import SynchronousTimeInterval from smartsim._core.control.launch_history import LaunchHistory from smartsim._core.utils.launcher import LauncherProtocol, create_job_id from smartsim.entity import entity +from smartsim.entity.application import Application +from smartsim.entity.ensemble import Ensemble from smartsim.error import errors from smartsim.experiment import Experiment from smartsim.launchable import job @@ -51,6 +53,17 @@ pytestmark = pytest.mark.group_a +_ID_GENERATOR = (str(i) for i in itertools.count()) + + +@pytest.fixture +def get_gen_symlink_dir(fileutils): + yield fileutils.get_test_conf_path(osp.join("generator_files", "to_symlink_dir")) + + +def random_id(): + return next(_ID_GENERATOR) + @pytest.fixture def experiment(monkeypatch, test_dir, dispatcher): @@ -611,3 +624,143 @@ def test_experiment_stop_does_not_raise_on_unknown_job_id( assert stat == InvalidJobStatus.NEVER_STARTED after_cancel = exp.get_status(*all_known_ids) assert before_cancel == after_cancel + + +def test_start_sequence_5( + test_dir, + wlmutils, + monkeypatch, +): + monkeypatch.setattr( + "smartsim._core.dispatch._LauncherAdapter.start", + lambda launch, exe, job_execution_path, env, out, err: random_id(), + ) + """Test the unpacking of a tuple of tuples + exp.start(job1, (job2, job3)) + """ + ensemble = Ensemble("ensemble-name", "echo", replicas=2) + + launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) + job_list = ensemble.as_jobs(launch_settings) + + exp = Experiment(name="exp_name", exp_path=test_dir) + + exp.start(job_list) + + +def test_start_with_two_element_tuple( + test_dir, + wlmutils, + monkeypatch, +): + """Test unpacking a tuple of two jobs""" + + monkeypatch.setattr( + "smartsim._core.dispatch._LauncherAdapter.start", + lambda launch, exe, job_execution_path, env, out, err: random_id(), + ) + ensemble = Ensemble("ensemble-name", "echo", replicas=2) + + application = Application( + "test_name", + exe="echo", + exe_args=["spam", "eggs"], + ) + + launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) + job_list = ensemble.as_jobs(launch_settings) + + job2 = job.Job(application, launch_settings) + exp = Experiment(name="exp_name", exp_path=test_dir) + + exp.start((job2, job_list)) + + +def test_start_with_nested_tuple( + test_dir, + wlmutils, + monkeypatch, +): + """Test unpacking a nested tuple""" + monkeypatch.setattr( + "smartsim._core.dispatch._LauncherAdapter.start", + lambda launch, exe, job_execution_path, env, out, err: random_id(), + ) + ensemble = Ensemble("ensemble-name", "echo", replicas=2) + + launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) + job_list = ensemble.as_jobs(launch_settings) + + application = Application( + "test_name", + exe="echo", + exe_args=["spam", "eggs"], + ) + + job2 = job.Job(application, launch_settings) + + application_2 = Application( + "test_name_2", + exe="echo", + exe_args=["spam", "eggs"], + ) + job_3 = job.Job(application_2, launch_settings) + + exp = Experiment(name="exp_name", exp_path=test_dir) + + exp.start((job2, (job_list, job_3))) + + +def test_start_with_one_element_tuple( + test_dir, + wlmutils, + monkeypatch, +): + """Test unpacking a tuple of one job""" + monkeypatch.setattr( + "smartsim._core.dispatch._LauncherAdapter.start", + lambda launch, exe, job_execution_path, env, out, err: random_id(), + ) + ensemble = Ensemble("ensemble-name", "echo", replicas=2) + + launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) + job_list = ensemble.as_jobs(launch_settings) + + exp = Experiment(name="exp_name", exp_path=test_dir) + + exp.start((job_list)) + + +def test_start_list_of_jobs( + test_dir, + wlmutils, + monkeypatch, +): + """Test unpacking a list of tuples""" + monkeypatch.setattr( + "smartsim._core.dispatch._LauncherAdapter.start", + lambda launch, exe, job_execution_path, env, out, err: random_id(), + ) + ensemble = Ensemble("ensemble-name", "echo", replicas=2) + + launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) + job_list = ensemble.as_jobs(launch_settings) + + application = Application( + "test_name", + exe="echo", + exe_args=["spam", "eggs"], + ) + + job2 = job.Job(application, launch_settings) + + application_2 = Application( + "test_name_2", + exe="echo", + exe_args=["spam", "eggs"], + ) + job_3 = job.Job(application_2, launch_settings) + + exp = Experiment(name="exp_name", exp_path=test_dir) + + exp.start([job2, (job_list, job_3)]) From 6b54a9a81129f9b555f0db5a8026fd879365c422 Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Wed, 18 Sep 2024 14:05:19 -0700 Subject: [PATCH 02/10] cleanuo --- smartsim/experiment.py | 1 - 1 file changed, 1 deletion(-) diff --git a/smartsim/experiment.py b/smartsim/experiment.py index 2cf1fe3ee..6d435206a 100644 --- a/smartsim/experiment.py +++ b/smartsim/experiment.py @@ -162,7 +162,6 @@ def __init__(self, name: str, exp_path: str | None = None): experiment """ - # def start( self, *jobs: Job | t.Sequence[t.Tuple[Job]] | t.Sequence[Job] ) -> tuple[LaunchedJobID, ...]: From fe15a2723110ccc88d3b1cb25ac0343748cb541b Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Wed, 25 Sep 2024 10:32:00 -0700 Subject: [PATCH 03/10] type fixes, param tests --- smartsim/_core/utils/helpers.py | 17 +++ smartsim/experiment.py | 24 +--- tests/test_experiment.py | 222 +++++++++++++++----------------- 3 files changed, 124 insertions(+), 139 deletions(-) diff --git a/smartsim/_core/utils/helpers.py b/smartsim/_core/utils/helpers.py index 1133358a6..06ceb28df 100644 --- a/smartsim/_core/utils/helpers.py +++ b/smartsim/_core/utils/helpers.py @@ -43,11 +43,15 @@ from datetime import datetime from shutil import which +from typing_extensions import TypeAlias + if t.TYPE_CHECKING: from types import FrameType from typing_extensions import TypeVarTuple, Unpack + from smartsim.launchable.job import Job + _Ts = TypeVarTuple("_Ts") @@ -55,6 +59,19 @@ _HashableT = t.TypeVar("_HashableT", bound=t.Hashable) _TSignalHandlerFn = t.Callable[[int, t.Optional["FrameType"]], object] +_nested_seq: TypeAlias = "t.Sequence[Job | _nested_seq]" + + +def unpack(value: _nested_seq) -> t.Generator[Job, None, None]: + """Unpack any iterable input in order to obtain a + single sequence of values""" + + for item in value: + if isinstance(item, t.Iterable): + yield from unpack(item) + else: + yield item + def check_name(name: str) -> None: """ diff --git a/smartsim/experiment.py b/smartsim/experiment.py index 6d435206a..0861cc1ed 100644 --- a/smartsim/experiment.py +++ b/smartsim/experiment.py @@ -55,17 +55,6 @@ logger = get_logger(__name__) -def _unpack(jobs: t.Sequence[t.Tuple[Job]] | t.Sequence[str]) -> t.Iterator[str]: - """Unpack any iterable input into exp.start in order to obtain a - single sequence of jobs that can be launched""" - for item in jobs: - - if isinstance(item, t.Iterable): - yield from _unpack(item) - else: - yield item - - def _exp_path_map(exp: "Experiment") -> str: """Mapping function for use by method contextualizer to place the path of the currently-executing experiment into context for log enrichment""" @@ -162,9 +151,7 @@ def __init__(self, name: str, exp_path: str | None = None): experiment """ - def start( - self, *jobs: Job | t.Sequence[t.Tuple[Job]] | t.Sequence[Job] - ) -> tuple[LaunchedJobID, ...]: + def start(self, *jobs: Job | t.Sequence[Job]) -> tuple[LaunchedJobID, ...]: """Execute a collection of `Job` instances. :param jobs: A collection of other job instances to start @@ -173,20 +160,21 @@ def start( particular execution of the job. """ # If item is instance iterable then unpack and extend the list - if isinstance(jobs, t.Iterable): - jobs = list(tuple(_unpack(jobs))) + + jobs_ = list(tuple(_helpers.unpack(jobs))) + # jobs = list(tuple(_helpers.unpack(jobs))) # Create the run id run_id = datetime.datetime.now().replace(microsecond=0).isoformat() # Generate the root path root = pathlib.Path(self.exp_path, run_id) - return self._dispatch(Generator(root), dispatch.DEFAULT_DISPATCHER, *jobs) + return self._dispatch(Generator(root), dispatch.DEFAULT_DISPATCHER, *jobs_) def _dispatch( self, generator: Generator, dispatcher: dispatch.Dispatcher, job: Job, - *jobs: Job | t.Sequence[t.Tuple[Job]], + *jobs: Job, ) -> tuple[LaunchedJobID, ...]: """Dispatch a series of jobs with a particular dispatcher diff --git a/tests/test_experiment.py b/tests/test_experiment.py index 0863151ab..8034a1738 100644 --- a/tests/test_experiment.py +++ b/tests/test_experiment.py @@ -56,11 +56,6 @@ _ID_GENERATOR = (str(i) for i in itertools.count()) -@pytest.fixture -def get_gen_symlink_dir(fileutils): - yield fileutils.get_test_conf_path(osp.join("generator_files", "to_symlink_dir")) - - def random_id(): return next(_ID_GENERATOR) @@ -626,141 +621,126 @@ def test_experiment_stop_does_not_raise_on_unknown_job_id( assert before_cancel == after_cancel -def test_start_sequence_5( - test_dir, - wlmutils, - monkeypatch, -): - monkeypatch.setattr( - "smartsim._core.dispatch._LauncherAdapter.start", - lambda launch, exe, job_execution_path, env, out, err: random_id(), - ) - """Test the unpacking of a tuple of tuples - exp.start(job1, (job2, job3)) +def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list): + """Test the unpacking of a tuple of tuples + exp.start(job1, (job2, job3)) """ - ensemble = Ensemble("ensemble-name", "echo", replicas=2) - - launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) - job_list = ensemble.as_jobs(launch_settings) - - exp = Experiment(name="exp_name", exp_path=test_dir) - - exp.start(job_list) - - -def test_start_with_two_element_tuple( - test_dir, - wlmutils, - monkeypatch, -): - """Test unpacking a tuple of two jobs""" - monkeypatch.setattr( "smartsim._core.dispatch._LauncherAdapter.start", lambda launch, exe, job_execution_path, env, out, err: random_id(), ) - ensemble = Ensemble("ensemble-name", "echo", replicas=2) - - application = Application( - "test_name", - exe="echo", - exe_args=["spam", "eggs"], - ) - - launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) - job_list = ensemble.as_jobs(launch_settings) - - job2 = job.Job(application, launch_settings) - exp = Experiment(name="exp_name", exp_path=test_dir) - - exp.start((job2, job_list)) - -def test_start_with_nested_tuple( - test_dir, - wlmutils, - monkeypatch, -): - """Test unpacking a nested tuple""" - monkeypatch.setattr( - "smartsim._core.dispatch._LauncherAdapter.start", - lambda launch, exe, job_execution_path, env, out, err: random_id(), - ) ensemble = Ensemble("ensemble-name", "echo", replicas=2) launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) job_list = ensemble.as_jobs(launch_settings) - application = Application( - "test_name", - exe="echo", - exe_args=["spam", "eggs"], - ) - - job2 = job.Job(application, launch_settings) - - application_2 = Application( - "test_name_2", - exe="echo", - exe_args=["spam", "eggs"], - ) - job_3 = job.Job(application_2, launch_settings) - exp = Experiment(name="exp_name", exp_path=test_dir) - exp.start((job2, (job_list, job_3))) - - -def test_start_with_one_element_tuple( - test_dir, - wlmutils, - monkeypatch, -): - """Test unpacking a tuple of one job""" - monkeypatch.setattr( - "smartsim._core.dispatch._LauncherAdapter.start", - lambda launch, exe, job_execution_path, env, out, err: random_id(), - ) - ensemble = Ensemble("ensemble-name", "echo", replicas=2) - - launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) - job_list = ensemble.as_jobs(launch_settings) - - exp = Experiment(name="exp_name", exp_path=test_dir) + exp.start(job_list) - exp.start((job_list)) +@pytest.mark.parametrize( + "job_list", + ( + pytest.param( + [ + ( + job.Job( + Application( + "test_name", + exe="echo", + exe_args=["spam", "eggs"], + ), + launchSettings.LaunchSettings("local"), + ), + Ensemble("ensemble-name", "echo", replicas=2).as_jobs( + launchSettings.LaunchSettings("local") + ), + ) + ], + id="(job1, job2)", + ), + pytest.param( + [ + ( + Ensemble("ensemble-name", "echo", replicas=2).as_jobs( + launchSettings.LaunchSettings("local") + ), + ( + job.Job( + Application( + "test_name", + exe="echo", + exe_args=["spam", "eggs"], + ), + launchSettings.LaunchSettings("local"), + ), + job.Job( + Application( + "test_name_2", + exe="echo", + exe_args=["spam", "eggs"], + ), + launchSettings.LaunchSettings("local"), + ), + ), + ) + ], + id="(job1, (job2, job3))", + ), + pytest.param( + [ + ( + job.Job( + Application( + "test_name", + exe="echo", + exe_args=["spam", "eggs"], + ), + launchSettings.LaunchSettings("local"), + ), + ) + ], + id="(job,)", + ), + pytest.param( + [ + [ + job.Job( + Application( + "test_name", + exe="echo", + exe_args=["spam", "eggs"], + ), + launchSettings.LaunchSettings("local"), + ), + ( + Ensemble("ensemble-name", "echo", replicas=2).as_jobs( + launchSettings.LaunchSettings("local") + ), + job.Job( + Application( + "test_name_2", + exe="echo", + exe_args=["spam", "eggs"], + ), + launchSettings.LaunchSettings("local"), + ), + ), + ] + ], + id="[job_1, (job_2, job_3)]", + ), + ), +) +def test_start_unpack(test_dir, wlmutils, monkeypatch, job_list): + """Test unpacking a sequences of jobs""" -def test_start_list_of_jobs( - test_dir, - wlmutils, - monkeypatch, -): - """Test unpacking a list of tuples""" monkeypatch.setattr( "smartsim._core.dispatch._LauncherAdapter.start", lambda launch, exe, job_execution_path, env, out, err: random_id(), ) - ensemble = Ensemble("ensemble-name", "echo", replicas=2) - - launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) - job_list = ensemble.as_jobs(launch_settings) - - application = Application( - "test_name", - exe="echo", - exe_args=["spam", "eggs"], - ) - - job2 = job.Job(application, launch_settings) - - application_2 = Application( - "test_name_2", - exe="echo", - exe_args=["spam", "eggs"], - ) - job_3 = job.Job(application_2, launch_settings) exp = Experiment(name="exp_name", exp_path=test_dir) - - exp.start([job2, (job_list, job_3)]) + exp.start(*job_list) From 840a8d95d7b2df9340736d67996f65344479842d Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Wed, 25 Sep 2024 13:22:23 -0700 Subject: [PATCH 04/10] merge with core branch; import fixes --- tests/test_experiment.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/test_experiment.py b/tests/test_experiment.py index 0b9914e53..eb95727bc 100644 --- a/tests/test_experiment.py +++ b/tests/test_experiment.py @@ -41,15 +41,16 @@ from smartsim._core import dispatch from smartsim._core.control.launch_history import LaunchHistory from smartsim._core.utils.launcher import LauncherProtocol, create_job_id +from smartsim.builders.ensemble import Ensemble from smartsim.entity import entity from smartsim.entity.application import Application -from smartsim.entity.ensemble import Ensemble from smartsim.error import errors from smartsim.experiment import Experiment from smartsim.launchable import job from smartsim.settings import launch_settings from smartsim.settings.arguments import launch_arguments from smartsim.status import InvalidJobStatus, JobStatus +from smartsim.types import LaunchedJobID pytestmark = pytest.mark.group_a @@ -632,8 +633,8 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) ensemble = Ensemble("ensemble-name", "echo", replicas=2) - launch_settings = launchSettings.LaunchSettings(wlmutils.get_test_launcher()) - job_list = ensemble.as_jobs(launch_settings) + launch_settings = launch_settings.LaunchSettings(wlmutils.get_test_launcher()) + job_list = ensemble.build_jobs(launch_settings) exp = Experiment(name="exp_name", exp_path=test_dir) @@ -652,10 +653,10 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) exe="echo", exe_args=["spam", "eggs"], ), - launchSettings.LaunchSettings("local"), + launch_settings.LaunchSettings("local"), ), - Ensemble("ensemble-name", "echo", replicas=2).as_jobs( - launchSettings.LaunchSettings("local") + Ensemble("ensemble-name", "echo", replicas=2).build_jobs( + launch_settings.LaunchSettings("local") ), ) ], @@ -664,8 +665,8 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) pytest.param( [ ( - Ensemble("ensemble-name", "echo", replicas=2).as_jobs( - launchSettings.LaunchSettings("local") + Ensemble("ensemble-name", "echo", replicas=2).build_jobs( + launch_settings.LaunchSettings("local") ), ( job.Job( @@ -674,7 +675,7 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) exe="echo", exe_args=["spam", "eggs"], ), - launchSettings.LaunchSettings("local"), + launch_settings.LaunchSettings("local"), ), job.Job( Application( @@ -682,7 +683,7 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) exe="echo", exe_args=["spam", "eggs"], ), - launchSettings.LaunchSettings("local"), + launch_settings.LaunchSettings("local"), ), ), ) @@ -698,7 +699,7 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) exe="echo", exe_args=["spam", "eggs"], ), - launchSettings.LaunchSettings("local"), + launch_settings.LaunchSettings("local"), ), ) ], @@ -713,11 +714,11 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) exe="echo", exe_args=["spam", "eggs"], ), - launchSettings.LaunchSettings("local"), + launch_settings.LaunchSettings("local"), ), ( - Ensemble("ensemble-name", "echo", replicas=2).as_jobs( - launchSettings.LaunchSettings("local") + Ensemble("ensemble-name", "echo", replicas=2).build_jobs( + launch_settings.LaunchSettings("local") ), job.Job( Application( @@ -725,7 +726,7 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) exe="echo", exe_args=["spam", "eggs"], ), - launchSettings.LaunchSettings("local"), + launch_settings.LaunchSettings("local"), ), ), ] From ac3a32f53367ebfe71843810438f03fb35e45dc3 Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Tue, 1 Oct 2024 14:20:35 -0700 Subject: [PATCH 05/10] removed comments; added types to test; type fixes --- smartsim/_core/utils/helpers.py | 10 +++++++--- smartsim/experiment.py | 7 +------ tests/test_experiment.py | 23 +++-------------------- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/smartsim/_core/utils/helpers.py b/smartsim/_core/utils/helpers.py index 06ceb28df..cd1ce65c4 100644 --- a/smartsim/_core/utils/helpers.py +++ b/smartsim/_core/utils/helpers.py @@ -59,12 +59,16 @@ _HashableT = t.TypeVar("_HashableT", bound=t.Hashable) _TSignalHandlerFn = t.Callable[[int, t.Optional["FrameType"]], object] -_nested_seq: TypeAlias = "t.Sequence[Job | _nested_seq]" +_NestedJobSequenceType: TypeAlias = "t.Sequence[Job | _NestedJobSequenceType]" -def unpack(value: _nested_seq) -> t.Generator[Job, None, None]: +def unpack(value: _NestedJobSequenceType) -> t.Generator[Job, None, None]: """Unpack any iterable input in order to obtain a - single sequence of values""" + single sequence of values + + :param: Sequence containing elements of type Job or other + sequences that are also of type _NestedJobSequenceType + :return: flattened list of Jobs""" for item in value: if isinstance(item, t.Iterable): diff --git a/smartsim/experiment.py b/smartsim/experiment.py index e42176c6e..cda91c4d1 100644 --- a/smartsim/experiment.py +++ b/smartsim/experiment.py @@ -159,13 +159,8 @@ def start(self, *jobs: Job | t.Sequence[Job]) -> tuple[LaunchedJobID, ...]: jobs that can be used to query or alter the status of that particular execution of the job. """ - # If item is instance iterable then unpack and extend the list - - jobs_ = list(tuple(_helpers.unpack(jobs))) - # jobs = list(tuple(_helpers.unpack(jobs))) - # Create the run id + jobs_ = list(_helpers.unpack(jobs)) run_id = datetime.datetime.now().replace(microsecond=0).isoformat() - # Generate the root path root = pathlib.Path(self.exp_path, run_id) return self._dispatch(Generator(root), dispatch.DEFAULT_DISPATCHER, *jobs_) diff --git a/tests/test_experiment.py b/tests/test_experiment.py index eb95727bc..96c6f12df 100644 --- a/tests/test_experiment.py +++ b/tests/test_experiment.py @@ -622,25 +622,6 @@ def test_experiment_stop_does_not_raise_on_unknown_job_id( assert before_cancel == after_cancel -def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list): - """Test the unpacking of a tuple of tuples - exp.start(job1, (job2, job3)) - """ - monkeypatch.setattr( - "smartsim._core.dispatch._LauncherAdapter.start", - lambda launch, exe, job_execution_path, env, out, err: random_id(), - ) - - ensemble = Ensemble("ensemble-name", "echo", replicas=2) - - launch_settings = launch_settings.LaunchSettings(wlmutils.get_test_launcher()) - job_list = ensemble.build_jobs(launch_settings) - - exp = Experiment(name="exp_name", exp_path=test_dir) - - exp.start(job_list) - - @pytest.mark.parametrize( "job_list", ( @@ -735,7 +716,9 @@ def test_start_sequences_of_jobs_good(test_dir, wlmutils, monkeypatch, job_list) ), ), ) -def test_start_unpack(test_dir, wlmutils, monkeypatch, job_list): +def test_start_unpack( + test_dir: str, wlmutils, monkeypatch: pytest.MonkeyPatch, job_list: job.Job +): """Test unpacking a sequences of jobs""" monkeypatch.setattr( From c7c8e4712e87494f729aa069dd07870b9a6cccef Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:00:04 -0700 Subject: [PATCH 06/10] Update tests/test_experiment.py Co-authored-by: Matt Drozt --- tests/test_experiment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_experiment.py b/tests/test_experiment.py index 96c6f12df..2b7bb13bf 100644 --- a/tests/test_experiment.py +++ b/tests/test_experiment.py @@ -641,7 +641,7 @@ def test_experiment_stop_does_not_raise_on_unknown_job_id( ), ) ], - id="(job1, job2)", + id="(job1, (job2, job_3))", ), pytest.param( [ From a40d197c4a5cc07b57a51aa962fdf648e2f7fce5 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:00:13 -0700 Subject: [PATCH 07/10] Update tests/test_experiment.py Co-authored-by: Matt Drozt --- tests/test_experiment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_experiment.py b/tests/test_experiment.py index 2b7bb13bf..3d83c79e6 100644 --- a/tests/test_experiment.py +++ b/tests/test_experiment.py @@ -712,7 +712,7 @@ def test_experiment_stop_does_not_raise_on_unknown_job_id( ), ] ], - id="[job_1, (job_2, job_3)]", + id="[job_1, ((job_2, job_3), job_4)]", ), ), ) From a6e03bac9c8afe002f25a5a654259213fcd6f875 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:00:22 -0700 Subject: [PATCH 08/10] Update tests/test_experiment.py Co-authored-by: Matt Drozt --- tests/test_experiment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_experiment.py b/tests/test_experiment.py index 3d83c79e6..d88abeb20 100644 --- a/tests/test_experiment.py +++ b/tests/test_experiment.py @@ -669,7 +669,7 @@ def test_experiment_stop_does_not_raise_on_unknown_job_id( ), ) ], - id="(job1, (job2, job3))", + id="((job1, job2), (job3, job4))", ), pytest.param( [ From 6ea237112f4042981b63353ac67042cb3e4d76f3 Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Wed, 2 Oct 2024 13:19:14 -0700 Subject: [PATCH 09/10] add test to helpers --- tests/_legacy/test_helpers.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/_legacy/test_helpers.py b/tests/_legacy/test_helpers.py index 523ed7191..7b453905c 100644 --- a/tests/_legacy/test_helpers.py +++ b/tests/_legacy/test_helpers.py @@ -30,12 +30,32 @@ import pytest from smartsim._core.utils import helpers -from smartsim._core.utils.helpers import cat_arg_and_value +from smartsim._core.utils.helpers import cat_arg_and_value, unpack +from smartsim.entity.application import Application +from smartsim.launchable.job import Job +from smartsim.settings.launch_settings import LaunchSettings # The tests in this file belong to the group_a group pytestmark = pytest.mark.group_a +def test_unpack_iterates_over_nested_jobs_in_expected_order(wlmutils): + launch_settings = LaunchSettings(wlmutils.get_test_launcher()) + app = Application("app_name", exe="python") + job_1 = Job(app, launch_settings) + job_2 = Job(app, launch_settings) + job_3 = Job(app, launch_settings) + job_4 = Job(app, launch_settings) + job_5 = Job(app, launch_settings) + + assert ( + [job_1, job_2, job_3, job_4, job_5] + == list(unpack([job_1, [job_2, job_3], job_4, [job_5]])) + == list(unpack([job_1, job_2, [job_3, job_4], job_5])) + == list(unpack([job_1, [job_2, [job_3, job_4], job_5]])) + ) + + def test_double_dash_concat(): result = cat_arg_and_value("--foo", "FOO") assert result == "--foo=FOO" From 0d6016458549bde3694bdb1f684bfd6372594d8b Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Thu, 3 Oct 2024 16:00:40 -0700 Subject: [PATCH 10/10] function description update --- smartsim/_core/utils/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smartsim/_core/utils/helpers.py b/smartsim/_core/utils/helpers.py index cd1ce65c4..fef1e792f 100644 --- a/smartsim/_core/utils/helpers.py +++ b/smartsim/_core/utils/helpers.py @@ -66,7 +66,7 @@ def unpack(value: _NestedJobSequenceType) -> t.Generator[Job, None, None]: """Unpack any iterable input in order to obtain a single sequence of values - :param: Sequence containing elements of type Job or other + :param value: Sequence containing elements of type Job or other sequences that are also of type _NestedJobSequenceType :return: flattened list of Jobs"""