Skip to content

Commit

Permalink
Add Beaker.experiment.rename() method (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
epwalsh authored Apr 11, 2022
1 parent 62fb2a4 commit ee2c046
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Added `Beaker.experiment.rename()`.

## [v0.5.5](https://github.com/allenai/beaker-py/releases/tag/v0.5.5) - 2022-04-10

### Added
Expand All @@ -20,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `Beaker.dataset.size()`.
- Added `Beaker.dataset.rename()`.
- Added `ExperimentSpec.from_file()`.
- Added `Beaker.cluster.filter_available()` method.
- Added `Beaker.cluster.filter_available()`.

## [v0.5.3](https://github.com/allenai/beaker-py/releases/tag/v0.5.3) - 2022-04-08

Expand Down
34 changes: 34 additions & 0 deletions beaker/services/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ def create(
:param workspace: The workspace to create the experiment under. If not specified,
:data:`Beaker.config.default_workspace <beaker.Config.default_workspace>` is used.
:raises ValueError: If the name is invalid.
:raises ExperimentConflict: If an experiment with the given name already exists.
:raises WorkspaceNotFound: If the workspace doesn't exist.
:raises WorkspaceNotSet: If neither ``workspace`` nor
:data:`Beaker.config.defeault_workspace <beaker.Config.default_workspace>` are set.
:raises HTTPError: Any other HTTP exception that can occur.
"""
self._validate_name(name)
json_spec: Dict[str, Any]
if isinstance(spec, ExperimentSpec):
json_spec = spec.to_json()
Expand Down Expand Up @@ -96,6 +98,30 @@ def delete(self, experiment: Union[str, Experiment]):
exceptions_for_status={404: ExperimentNotFound(self._not_found_err_msg(experiment_id))},
)

def rename(self, experiment: Union[str, Experiment], name: str) -> Experiment:
"""
Rename an experiment.
:param experiment: The experiment ID, full name, or object.
:param name: The new
:raises ValueError: If the new name is invalid.
:raises ExperimentNotFound: If the experiment can't be found.
:raises HTTPError: Any other HTTP exception that can occur.
"""
self._validate_name(name)
experiment_id = experiment if isinstance(experiment, str) else experiment.id
return Experiment.from_json(
self.request(
f"experiments/{self._url_quote(experiment_id)}",
method="PATCH",
data={"name": name},
exceptions_for_status={
404: ExperimentNotFound(self._not_found_err_msg(experiment_id))
},
).json()
)

def list(self, workspace: Optional[str] = None) -> List[Experiment]:
"""
:param workspace: The workspace to upload the dataset to. If not specified,
Expand Down Expand Up @@ -200,3 +226,11 @@ def _not_found_err_msg(self, experiment: str) -> str:
f"'{experiment}': Make sure you're using a valid Beaker experiment ID or the "
f"*full* name of the experiment (with the account prefix, e.g. 'username/experiment_name')"
)

def _validate_name(self, name: str) -> None:
err_msg = (
f"Invalid name '{name}'. Experiment names can only consist of "
"letters, digits, dashes, and underscores"
)
if not name.replace("-", "").replace("_", "").isalnum():
raise ValueError(err_msg)
10 changes: 10 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ def experiment_name(client: Beaker) -> Generator[str, None, None]:
pass


@pytest.fixture()
def alternate_experiment_name(client: Beaker) -> Generator[str, None, None]:
name = petname.generate() + "-" + str(uuid.uuid4())[:8]
yield name
try:
client.experiment.delete(f"{client.account.whoami().name}/{name}")
except ExperimentNotFound:
pass


@pytest.fixture()
def dataset_name(client: Beaker) -> Generator[str, None, None]:
name = petname.generate() + "-" + str(uuid.uuid4())[:8]
Expand Down
34 changes: 32 additions & 2 deletions tests/experiment_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
from beaker import Beaker, CurrentJobStatus
from beaker import (
Beaker,
CurrentJobStatus,
ExperimentSpec,
ImageSource,
ResultSpec,
TaskContext,
TaskSpec,
)


def test_experiment_get(client: Beaker, hello_world_experiment_id):
def test_experiment_get(client: Beaker, hello_world_experiment_id: str):
exp = client.experiment.get(hello_world_experiment_id)
assert exp.id == hello_world_experiment_id
assert exp.jobs
assert exp.jobs[0].status.current == CurrentJobStatus.finalized


def test_experiment_create_await_rename(
client: Beaker, experiment_name: str, alternate_experiment_name: str, beaker_cluster_name: str
):
spec = ExperimentSpec(
tasks=[
TaskSpec(
name="main",
image=ImageSource(docker="hello-world"),
context=TaskContext(cluster=beaker_cluster_name),
result=ResultSpec(path="/unused"), # required even if the task produces no output.
),
],
)
experiment = client.experiment.create(experiment_name, spec)
experiment = client.experiment.await_all(experiment, timeout=60 * 3)
logs = "".join([line.decode() for line in client.experiment.logs(experiment)])
assert logs

experiment = client.experiment.rename(experiment, alternate_experiment_name)
assert experiment.name == alternate_experiment_name

0 comments on commit ee2c046

Please sign in to comment.