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

Experiment Preview #447

Merged
merged 34 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5e32788
experiment preview method and tests
juliaputko Dec 19, 2023
6ab3dc7
mypy fix
juliaputko Dec 21, 2023
09285d2
lint error fix
juliaputko Dec 21, 2023
cf4adbc
experiment preview with jinja
juliaputko Jan 3, 2024
c4046c1
added jinja as dependency
juliaputko Jan 4, 2024
d9cf92b
addressing comments, and adding tests
juliaputko Jan 11, 2024
a2eace9
type change
juliaputko Jan 11, 2024
0d04640
ccreation of html templates and refactor of checking nto render function
juliaputko Jan 12, 2024
446bf98
Merge branch 'exppreview' of https://github.com/juliaputko/SmartSim i…
Jan 16, 2024
6323c7a
defining literals,changing loggin fmt, and docstring update
Jan 17, 2024
cb7691d
whitespace fix
Jan 17, 2024
745594e
Merge branch 'develop' of https://github.com/CrayLabs/SmartSim into e…
Jan 18, 2024
84e48e7
added doc strings, and check verbosity_level change
Jan 19, 2024
0ad027f
render and review updates, linting
juliaputko Jan 23, 2024
2449c0f
synch with develop
juliaputko Jan 23, 2024
2c97276
template fixes
Jan 30, 2024
757eea1
Merge branch 'develop' of https://github.com/CrayLabs/SmartSim into e…
Jan 31, 2024
c789f8e
isort fix
Feb 1, 2024
23f633a
black error fix
Feb 1, 2024
85ac57b
output forrmat doc + error handling
Feb 1, 2024
0662f0c
added previewformaterror to test-preview
Feb 1, 2024
8604992
mypy fix
Feb 1, 2024
27aef4c
entities in manifest addition for template check
Feb 6, 2024
0eb2442
mypy fix in manifest
Feb 6, 2024
a0a54f7
mypy fix
Feb 6, 2024
3595bd4
sync with develop
Feb 9, 2024
1577f39
added jinja to setup.py
Feb 9, 2024
56e852d
remove html from this branch
Feb 10, 2024
d261f20
mypy fix
Feb 12, 2024
4108181
Merge branch 'develop' into exppreview
Feb 12, 2024
10d7f89
added enums for verbosity
Feb 12, 2024
c42ac83
fixed wording on error message
Feb 12, 2024
ca84b72
black fix
Feb 12, 2024
7d48a1e
Merge branch 'develop' of https://github.com/CrayLabs/SmartSim into e…
Feb 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,11 @@

# check for compatible python versions
if not build_env.is_compatible_python(versions.PYTHON_MIN):
print("You are using Python {}. Python >={} is required.".format(build_env.python_version,
".".join((versions.PYTHON_MIN))))
print(
"You are using Python {}. Python >={} is required.".format(
build_env.python_version, ".".join((versions.PYTHON_MIN))
)
)
sys.exit(-1)

if build_env.is_windows():
Expand All @@ -120,9 +123,11 @@
# __version__ in smartsim/__init__.py
smartsim_version = versions.write_version(setup_path)


class BuildError(Exception):
pass


# Hacky workaround for solving CI build "purelib" issue
# see https://github.com/google/or-tools/issues/616
class InstallPlatlib(install):
Expand All @@ -131,15 +136,14 @@ def finalize_options(self):
if self.distribution.has_ext_modules():
self.install_lib = self.install_platlib

class SmartSimBuild(build_py):

class SmartSimBuild(build_py):
def run(self):
database_builder = builder.DatabaseBuilder(build_env(),
build_env.MALLOC,
build_env.JOBS)
database_builder = builder.DatabaseBuilder(
build_env(), build_env.MALLOC, build_env.JOBS
)
if not database_builder.is_built:
database_builder.build_from_git(versions.REDIS_URL,
versions.REDIS)
database_builder.build_from_git(versions.REDIS_URL, versions.REDIS)

database_builder.cleanup()

Expand All @@ -151,9 +155,10 @@ def run(self):
class BinaryDistribution(Distribution):
"""Distribution which always forces a binary package with platform name

We use this because we want to pre-package Redis for certain
platforms to use.
We use this because we want to pre-package Redis for certain
platforms to use.
"""

def has_ext_modules(_placeholder):
return True

Expand All @@ -168,6 +173,7 @@ def has_ext_modules(_placeholder):
"filelock>=3.4.2",
"protobuf~=3.20",
"watchdog>=3.0.0",
"jinja2",
]

# Add SmartRedis at specific version
Expand All @@ -192,7 +198,7 @@ def has_ext_modules(_placeholder):
"types-setuptools",
],
# see smartsim/_core/_install/buildenv.py for more details
**versions.ml_extras_required()
**versions.ml_extras_required(),
}


Expand All @@ -211,5 +217,5 @@ def has_ext_modules(_placeholder):
"console_scripts": [
"smart = smartsim._core._cli.__main__:main",
]
}
},
)
4 changes: 2 additions & 2 deletions smartsim/_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# 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 .control import Controller, Manifest
from .control import Controller, Manifest, Viewexp
from .generation import Generator

__all__ = ["Controller", "Manifest", "Generator"]
__all__ = ["Controller", "Manifest", "Generator", "Viewexp"]
1 change: 1 addition & 0 deletions smartsim/_core/control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@

from .controller import Controller
from .manifest import Manifest
from .view import Viewexp
43 changes: 43 additions & 0 deletions smartsim/_core/control/view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# BSD 2-Clause License
#
# Copyright (c) 2021-2023, 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 typing as t
import jinja2


class Viewexp:
def __init__(self, exp_entity: t.Any) -> None:
self.exp_entity = exp_entity

Check warning on line 32 in smartsim/_core/control/view.py

View check run for this annotation

Codecov / codecov/patch

smartsim/_core/control/view.py#L32

Added line #L32 was not covered by tests

def render(self) -> str:
"""
Render the template from the supplied entity
"""
loader = jinja2.PackageLoader("templates")
env = jinja2.Environment(loader=loader, autoescape=True)
tpl = env.get_template("master.pytpl")
template = tpl.render(exp_entity=self.exp_entity)

Check warning on line 41 in smartsim/_core/control/view.py

View check run for this annotation

Codecov / codecov/patch

smartsim/_core/control/view.py#L38-L41

Added lines #L38 - L41 were not covered by tests

return template

Check warning on line 43 in smartsim/_core/control/view.py

View check run for this annotation

Codecov / codecov/patch

smartsim/_core/control/view.py#L43

Added line #L43 was not covered by tests
55 changes: 52 additions & 3 deletions smartsim/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@
from os import getcwd

from tabulate import tabulate

from ._core import Controller, Generator, Manifest
from ._core import Controller, Generator, Manifest, Viewexp
from ._core.utils import init_default
from .database import Orchestrator
from .entity import Ensemble, Model, SmartSimEntity
from .error import SmartSimError
from .log import get_logger
from .settings import Container, base, settings
from .settings import settings, base, Container
from .wlm import detect_launcher

logger = get_logger(__name__)
Expand Down Expand Up @@ -797,6 +796,56 @@
logger.error(e)
raise

def preview(
self,
output_format: t.Optional[str] = None,
output_filename: t.Optional[str] = None,
verbosity_level: t.Optional[str] = None,
) -> str:
"""Preview entity information prior to launch. This method
aggregates multiple pieces of information to give users insight
into what and how entities will be launched. Any instance of
``Model``, ``Ensemble`` or ``Orchestrator`` created by the
Experiment can be passed as an argument to the preview method.
param output_format: Set output destination. The possible accepted
output formats are `json`, `xml`, `html`, `plain_text`, `color_text`.
A filename is required if an output format is specified. If no output
format is set, the preview will be output to stdout. Defaults to None.
type output_type: str
param output_filename: Specify name of path to write preview data to.
Only needed when an output format has been specified. Defaults to None.
type output_filename: str
param verbosity level: the verbosity level.
info: Display User defined fields and entities
debug: Display user defined field and entities and auto generated
fields.
developer: Display user defined field and entities, auto generated
fields, and run commands.
Defaults to info.
type verbosity_level: str
"""

if output_format:

Check warning on line 828 in smartsim/experiment.py

View check run for this annotation

Codecov / codecov/patch

smartsim/experiment.py#L828

Added line #L828 was not covered by tests
raise NotImplementedError
if output_filename:

Check warning on line 830 in smartsim/experiment.py

View check run for this annotation

Codecov / codecov/patch

smartsim/experiment.py#L830

Added line #L830 was not covered by tests
raise NotImplementedError
if verbosity_level:

Check warning on line 832 in smartsim/experiment.py

View check run for this annotation

Codecov / codecov/patch

smartsim/experiment.py#L832

Added line #L832 was not covered by tests
raise NotImplementedError

return self._preview()

Check warning on line 835 in smartsim/experiment.py

View check run for this annotation

Codecov / codecov/patch

smartsim/experiment.py#L835

Added line #L835 was not covered by tests

def _preview(self) -> str:
"""String formatting"""

preview = Viewexp(self).render()
logger.info(preview)

Check warning on line 841 in smartsim/experiment.py

View check run for this annotation

Codecov / codecov/patch

smartsim/experiment.py#L840-L841

Added lines #L840 - L841 were not covered by tests

return preview

Check warning on line 843 in smartsim/experiment.py

View check run for this annotation

Codecov / codecov/patch

smartsim/experiment.py#L843

Added line #L843 was not covered by tests

def get_launcher(self) -> str:
"""Get launcher"""
return self._launcher

Check warning on line 847 in smartsim/experiment.py

View check run for this annotation

Codecov / codecov/patch

smartsim/experiment.py#L847

Added line #L847 was not covered by tests

def summary(self, style: str = "github") -> str:
"""Return a summary of the ``Experiment``

Expand Down
4 changes: 4 additions & 0 deletions templates/templates/experiment.pytpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
=== Experiment Overview ===
Experiment: {{ exp_entity.name }}
Experiment Path: {{ exp_entity.exp_path }}
Launcher: {{ exp_entity.get_launcher() }}
2 changes: 2 additions & 0 deletions templates/templates/master.pytpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

{% extends "experiment.pytpl" %}
82 changes: 82 additions & 0 deletions tests/test_preview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# BSD 2-Clause License
#
# Copyright (c) 2021-2023, 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 import Experiment


def test_experiment_preview(test_dir, wlmutils):
"""Test correct preview output items for Experiment preview"""
test_launcher = wlmutils.get_test_launcher()
exp_name = "test_prefix"
exp = Experiment(exp_name, exp_path=test_dir, launcher=test_launcher)
# Call method for string formatting for testing
output = exp._preview().strip()
summary_lines = output.split("\n")
summary_lines = [item.replace("\t", "") for item in summary_lines[-3:]]
assert 3 == len(summary_lines)
summary_dict = dict(row.split(": ") for row in summary_lines)
assert set(["Experiment", "Experiment Path", "Launcher"]).issubset(summary_dict)


def test_experiment_preview_properties(test_dir, wlmutils):
"""Test correct preview output properties for Experiment preview"""
test_launcher = wlmutils.get_test_launcher()
exp_name = "test_experiment_preview_properties"
exp = Experiment(exp_name, exp_path=test_dir, launcher=test_launcher)
# Call method for string formatting for testing
output = exp._preview().strip()
summary_lines = output.split("\n")
summary_lines = [item.replace("\t", "") for item in summary_lines[-3:]]
assert 3 == len(summary_lines)
summary_dict = dict(row.split(": ") for row in summary_lines)
assert exp.name == summary_dict["Experiment"]
assert exp.exp_path == summary_dict["Experiment Path"]
assert exp.get_launcher() == summary_dict["Launcher"]

def test_output_format_error():
exp_name = "test_output_format"
exp = Experiment(exp_name)

with pytest.raises(NotImplementedError):
exp.preview(output_format="hello")


def test_output_filename_error():
exp_name = "test_output_filename"
exp = Experiment(exp_name)

with pytest.raises(NotImplementedError):
exp.preview(output_filename="hello")


def test_verbosity_level_error():
exp_name = "test_verbosity_level"
exp = Experiment(exp_name)

with pytest.raises(NotImplementedError):
exp.preview(verbosity_level="hello")
Loading