diff --git a/smartsim/entity/entity.py b/smartsim/entity/entity.py index 3f5a9eabd0..a75b470921 100644 --- a/smartsim/entity/entity.py +++ b/smartsim/entity/entity.py @@ -29,7 +29,6 @@ import abc import typing as t -from smartsim.launchable.job_group import JobGroup if t.TYPE_CHECKING: from smartsim.launchable.job import Job @@ -136,5 +135,3 @@ class CompoundEntity(abc.ABC): @abc.abstractmethod def build_jobs(self, settings: LaunchSettings) -> t.Collection[Job]: ... - def as_job_group(self, settings: LaunchSettings) -> JobGroup: - return JobGroup(list(self.build_jobs(settings))) diff --git a/smartsim/experiment.py b/smartsim/experiment.py index 2af726959d..5f9be0ae14 100644 --- a/smartsim/experiment.py +++ b/smartsim/experiment.py @@ -87,10 +87,10 @@ def _on_disable(self) -> None: # pylint: disable=no-self-use class Experiment: """The Experiment class is used to schedule, launch, track, and manage - jobs and job groups. Also, it is the SmartSim class that manages + jobs. Also, it is the SmartSim class that manages internal data structures, processes, and infrastructure for interactive capabilities such as the SmartSim dashboard and historical lookback on - launched jobs and job groups. The Experiment class is designed to be + launched jobs. The Experiment class is designed to be initialized once and utilized throughout the entirety of a workflow. """ diff --git a/smartsim/launchable/__init__.py b/smartsim/launchable/__init__.py index 383b458f09..e0ad38176d 100644 --- a/smartsim/launchable/__init__.py +++ b/smartsim/launchable/__init__.py @@ -25,10 +25,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from .base_job import BaseJob -from .base_job_group import BaseJobGroup -from .colocated_job_group import ColocatedJobGroup from .job import Job -from .job_group import JobGroup from .launchable import Launchable from .mpmd_job import MPMDJob from .mpmd_pair import MPMDPair diff --git a/smartsim/launchable/base_job_group.py b/smartsim/launchable/base_job_group.py deleted file mode 100644 index 9031705f39..0000000000 --- a/smartsim/launchable/base_job_group.py +++ /dev/null @@ -1,91 +0,0 @@ -# BSD 2-Clause License -# -# Copyright (c) 2021-2024, Hewlett Packard Enterprise -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from __future__ import annotations - -import typing as t -from abc import ABC, abstractmethod -from collections.abc import MutableSequence -from copy import deepcopy - -from smartsim.launchable.launchable import Launchable - -from .base_job import BaseJob - - -class BaseJobGroup(Launchable, MutableSequence[BaseJob], ABC): - """Highest level ABC of a group of jobs that can be - launched - """ - - @property - @abstractmethod - def jobs(self) -> t.List[BaseJob]: - """This property method returns a list of BaseJob objects. - It represents the collection of jobs associated with an - instance of the BaseJobGroup abstract class. - """ - pass - - def insert(self, idx: int, value: BaseJob) -> None: - """Inserts the given value at the specified index (idx) in - the list of jobs. If the index is out of bounds, the method - prints an error message. - """ - self.jobs.insert(idx, value) - - def __iter__(self) -> t.Iterator[BaseJob]: - """Allows iteration over the jobs in the collection.""" - return iter(self.jobs) - - @t.overload - def __setitem__(self, idx: int, value: BaseJob) -> None: ... - @t.overload - def __setitem__(self, idx: slice, value: t.Iterable[BaseJob]) -> None: ... - def __setitem__( - self, idx: int | slice, value: BaseJob | t.Iterable[BaseJob] - ) -> None: - """Sets the job at the specified index (idx) to the given value.""" - if isinstance(idx, int): - if not isinstance(value, BaseJob): - raise TypeError("Can only assign a `BaseJob`") - self.jobs[idx] = deepcopy(value) - else: - if not isinstance(value, t.Iterable): - raise TypeError("Can only assign an iterable") - self.jobs[idx] = (deepcopy(val) for val in value) - - def __delitem__(self, idx: int | slice) -> None: - """Deletes the job at the specified index (idx).""" - del self.jobs[idx] - - def __len__(self) -> int: - """Returns the total number of jobs in the collection.""" - return len(self.jobs) - - def __str__(self) -> str: # pragma: no-cover - """Returns a string representation of the collection of jobs.""" - return f"Jobs: {self.jobs}" diff --git a/smartsim/launchable/colocated_job_group.py b/smartsim/launchable/colocated_job_group.py deleted file mode 100644 index db187a46c0..0000000000 --- a/smartsim/launchable/colocated_job_group.py +++ /dev/null @@ -1,75 +0,0 @@ -# BSD 2-Clause License -# -# Copyright (c) 2021-2024, Hewlett Packard Enterprise -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from __future__ import annotations - -import typing as t -from copy import deepcopy - -from .base_job import BaseJob -from .base_job_group import BaseJobGroup - -if t.TYPE_CHECKING: - from typing_extensions import Self - - -class ColocatedJobGroup(BaseJobGroup): - """A colocated job group holds references to multiple jobs that - will be executed all at the same time when resources - permit. Execution is blocked until resources are available. - """ - - def __init__( - self, - jobs: t.List[BaseJob], - ) -> None: - super().__init__() - self._jobs = deepcopy(jobs) - - @property - def jobs(self) -> t.List[BaseJob]: - """This property method returns a list of BaseJob objects. - It represents the collection of jobs associated with an - instance of the BaseJobGroup abstract class. - """ - return self._jobs - - @t.overload - def __getitem__(self, idx: int) -> BaseJob: ... - @t.overload - def __getitem__(self, idx: slice) -> Self: ... - def __getitem__(self, idx: int | slice) -> BaseJob | Self: - """Retrieves the job at the specified index (idx).""" - jobs = self.jobs[idx] - if isinstance(jobs, BaseJob): - return jobs - return type(self)(jobs) - - def __str__(self) -> str: # pragma: no-cover - """Returns a string representation of the collection of - colocated job groups. - """ - return f"Colocated Jobs: {self.jobs}" diff --git a/smartsim/launchable/job_group.py b/smartsim/launchable/job_group.py deleted file mode 100644 index f06313dd8d..0000000000 --- a/smartsim/launchable/job_group.py +++ /dev/null @@ -1,96 +0,0 @@ -# BSD 2-Clause License -# -# Copyright (c) 2021-2024, Hewlett Packard Enterprise -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from __future__ import annotations - -import typing as t -from copy import deepcopy - -from smartsim.log import get_logger - -from .._core.utils.helpers import check_name -from .base_job import BaseJob -from .base_job_group import BaseJobGroup - -logger = get_logger(__name__) - -if t.TYPE_CHECKING: - from typing_extensions import Self - - -@t.final -class JobGroup(BaseJobGroup): - """A job group holds references to multiple jobs that - will be executed all at the same time when resources - permit. Execution is blocked until resources are available. - """ - - def __init__( - self, - jobs: t.List[BaseJob], - name: str = "job_group", - ) -> None: - super().__init__() - self._jobs = deepcopy(jobs) - self._name = name - check_name(self._name) - - @property - def name(self) -> str: - """Retrieves the name of the JobGroup.""" - return self._name - - @name.setter - def name(self, name: str) -> None: - """Sets the name of the JobGroup.""" - check_name(name) - logger.debug(f'Overwriting Job name from "{self._name}" to "{name}"') - self._name = name - - @property - def jobs(self) -> t.List[BaseJob]: - """This property method returns a list of BaseJob objects. - It represents the collection of jobs associated with an - instance of the BaseJobGroup abstract class. - """ - return self._jobs - - @t.overload - def __getitem__(self, idx: int) -> BaseJob: ... - @t.overload - def __getitem__(self, idx: slice) -> Self: ... - def __getitem__(self, idx: int | slice) -> BaseJob | Self: - """Retrieves the job at the specified index (idx).""" - jobs = self.jobs[idx] - if isinstance(jobs, BaseJob): - return jobs - return type(self)(jobs) - - def __str__(self) -> str: # pragma: no-cover - """Returns a string representation of the collection of - job groups. - """ - return f"Job Groups: {self.jobs}" diff --git a/tests/temp_tests/test_colocatedJobGroup.py b/tests/temp_tests/test_colocatedJobGroup.py deleted file mode 100644 index d6d17fc8ae..0000000000 --- a/tests/temp_tests/test_colocatedJobGroup.py +++ /dev/null @@ -1,95 +0,0 @@ -# BSD 2-Clause License -# -# Copyright (c) 2021-2024, Hewlett Packard Enterprise -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import pytest - -from smartsim.entity.application import Application -from smartsim.launchable.base_job import BaseJob -from smartsim.launchable.colocated_job_group import ColocatedJobGroup -from smartsim.launchable.job import Job -from smartsim.settings import LaunchSettings - -pytestmark = pytest.mark.group_a - -app_1 = Application("app_1", "python") -app_2 = Application("app_2", "python") -app_3 = Application("app_3", "python") - - -class MockJob(BaseJob): - def get_launch_steps(self): - raise NotImplementedError - - -def test_create_ColocatedJobGroup(): - job_1 = MockJob() - job_group = ColocatedJobGroup([job_1]) - assert len(job_group) == 1 - - -def test_getitem_ColocatedJobGroup(): - job_1 = Job(app_1, LaunchSettings("slurm")) - job_2 = Job(app_2, LaunchSettings("slurm")) - job_group = ColocatedJobGroup([job_1, job_2]) - get_value = job_group[0].entity.name - assert get_value == job_1.entity.name - - -def test_setitem_JobGroup(): - job_1 = Job(app_1, LaunchSettings("slurm")) - job_2 = Job(app_2, LaunchSettings("slurm")) - job_group = ColocatedJobGroup([job_1, job_2]) - job_3 = Job(app_3, LaunchSettings("slurm")) - job_group[1] = job_3 - assert len(job_group) == 2 - get_value = job_group[1].entity.name - assert get_value == job_3.entity.name - - -def test_delitem_ColocatedJobGroup(): - job_1 = MockJob() - job_2 = MockJob() - job_group = ColocatedJobGroup([job_1, job_2]) - assert len(job_group) == 2 - del job_group[1] - assert len(job_group) == 1 - - -def test_len_ColocatedJobGroup(): - job_1 = MockJob() - job_2 = MockJob() - job_group = ColocatedJobGroup([job_1, job_2]) - assert len(job_group) == 2 - - -def test_insert_ColocatedJobGroup(): - job_1 = MockJob() - job_2 = MockJob() - job_group = ColocatedJobGroup([job_1, job_2]) - job_3 = MockJob() - job_group.insert(0, job_3) - get_value = job_group[0] - assert get_value == job_3 diff --git a/tests/temp_tests/test_jobGroup.py b/tests/temp_tests/test_jobGroup.py deleted file mode 100644 index f735162609..0000000000 --- a/tests/temp_tests/test_jobGroup.py +++ /dev/null @@ -1,110 +0,0 @@ -# BSD 2-Clause License -# -# Copyright (c) 2021-2024, Hewlett Packard Enterprise -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import pytest - -from smartsim.entity.application import Application -from smartsim.launchable.base_job import BaseJob -from smartsim.launchable.job import Job -from smartsim.launchable.job_group import JobGroup -from smartsim.settings.launch_settings import LaunchSettings - -pytestmark = pytest.mark.group_a - -app_1 = Application("app_1", "python") -app_2 = Application("app_2", "python") -app_3 = Application("app_3", "python") - - -class MockJob(BaseJob): - def get_launch_steps(self): - raise NotImplementedError - - -def test_invalid_job_name(wlmutils): - job_1 = Job(app_1, LaunchSettings("slurm")) - job_2 = Job(app_2, LaunchSettings("slurm")) - with pytest.raises(ValueError): - _ = JobGroup([job_1, job_2], name="name/not/allowed") - - -def test_create_JobGroup(): - job_1 = MockJob() - job_group = JobGroup([job_1]) - assert len(job_group) == 1 - - -def test_name_setter(wlmutils): - job_1 = Job(app_1, LaunchSettings("slurm")) - job_2 = Job(app_2, LaunchSettings("slurm")) - job_group = JobGroup([job_1, job_2]) - job_group.name = "new_name" - assert job_group.name == "new_name" - - -def test_getitem_JobGroup(wlmutils): - job_1 = Job(app_1, LaunchSettings("slurm")) - job_2 = Job(app_2, LaunchSettings("slurm")) - job_group = JobGroup([job_1, job_2]) - get_value = job_group[0].entity.name - assert get_value == job_1.entity.name - - -def test_setitem_JobGroup(wlmutils): - job_1 = Job(app_1, LaunchSettings("slurm")) - job_2 = Job(app_2, LaunchSettings("slurm")) - job_group = JobGroup([job_1, job_2]) - job_3 = Job(app_3, LaunchSettings("slurm")) - job_group[1] = job_3 - assert len(job_group) == 2 - get_value = job_group[1] - assert get_value.entity.name == job_3.entity.name - - -def test_delitem_JobGroup(): - job_1 = MockJob() - job_2 = MockJob() - job_group = JobGroup([job_1, job_2]) - assert len(job_group) == 2 - del job_group[1] - assert len(job_group) == 1 - - -def test_len_JobGroup(): - job_1 = MockJob() - job_2 = MockJob() - job_group = JobGroup([job_1, job_2]) - assert len(job_group) == 2 - - -def test_insert_JobGroup(): - job_1 = MockJob() - job_2 = MockJob() - job_group = JobGroup([job_1, job_2]) - job_3 = MockJob() - job_group.insert(0, job_3) - get_value = job_group[0] - assert get_value == job_3