Skip to content

Commit

Permalink
Implement new and update for goals
Browse files Browse the repository at this point in the history
  • Loading branch information
JoelCourtney committed Aug 15, 2024
1 parent e89c0d9 commit c2956d9
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 114 deletions.
42 changes: 32 additions & 10 deletions src/aerie_cli/aerie_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,20 +612,23 @@ def delete_plan(self, plan_id: int) -> str:

return resp["name"]

def upload_file(self, path: str) -> int:
upload_timestamp = arrow.utcnow().isoformat()
path_obj = Path(path)
server_side_path = (
path_obj.stem + "--" + upload_timestamp + path_obj.suffix
)
with open(path, "rb") as f:
resp = self.aerie_host.post_to_gateway_files(
server_side_path, f)
return resp["id"]

def upload_mission_model(
self, mission_model_path: str, project_name: str, mission: str, version: str
) -> int:

# Create unique jar identifier for server side
upload_timestamp = arrow.utcnow().isoformat()
server_side_jar_name = (
Path(mission_model_path).stem + "--" + upload_timestamp + ".jar"
)
with open(mission_model_path, "rb") as jar_file:
resp = self.aerie_host.post_to_gateway_files(
server_side_jar_name, jar_file)

jar_id = resp["id"]
jar_id = self.upload_file(mission_model_path)

create_model_mutation = """
mutation CreateModel($model: mission_model_insert_input!) {
Expand Down Expand Up @@ -1739,7 +1742,7 @@ def upload_scheduling_goals(self, upload_object):
"""

upload_scheduling_goals_query = """
mutation InsertGoal($input:[scheduling_goal_definition_insert_input]!){
mutation InsertGoal($input: [scheduling_goal_definition_insert_input!]!){
insert_scheduling_goal_definition(objects: $input){
returning {goal_id}
}
Expand Down Expand Up @@ -1767,6 +1770,25 @@ def get_scheduling_specification_for_plan(self, plan_id):
)
return resp[0]["id"]

def get_goal_id_for_name(self, name):
get_goal_id_for_name_query = """
query GetNameForGoalId($name: String!) {
scheduling_goal_metadata(where: {name: {_eq: $name}}) {
id
}
}
"""

resp = self.aerie_host.post_to_graphql(
get_goal_id_for_name_query,
name=name
)
if len(resp) == 0:
raise RuntimeError(f"No goals found with name {name}. Specify goal id manually with -g.")
elif len(resp) > 1:
raise RuntimeError(f"Multiple goals found with name {name}. Specify goal id manually with -g.")
return resp[0]["id"]

def add_goals_to_specifications(self, upload_object):
"""
Bulk operation to add goals to specification.
Expand Down
5 changes: 3 additions & 2 deletions src/aerie_cli/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
`app` is the CLI application with which all commands, subcommands, and callbacks are registered.
"""
import typer
from rich import print
from typing import Optional

from aerie_cli.commands import models
from aerie_cli.commands import plans
from aerie_cli.commands import configurations
from aerie_cli.commands import expansion
from aerie_cli.commands import constraints
from aerie_cli.commands import scheduling
from aerie_cli.commands import goals
from aerie_cli.commands import metadata

from aerie_cli.commands.command_context import CommandContext
Expand All @@ -32,7 +33,7 @@
app.add_typer(configurations.app, name="configurations")
app.add_typer(expansion.app, name="expansion")
app.add_typer(constraints.app, name="constraints")
app.add_typer(scheduling.app, name="scheduling")
app.add_typer(goals.app, name="goals")
app.add_typer(metadata.app, name="metadata")


Expand Down
126 changes: 126 additions & 0 deletions src/aerie_cli/commands/goals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import typer
import os
from typing import Optional

from aerie_cli.commands.command_context import CommandContext

app = typer.Typer()

def _get_name_and_ext(path: str):
path = path.strip()
filename = os.path.basename(path)
return os.path.splitext(filename)

@app.command()
def new(
path: str = typer.Argument(default=...),
description: Optional[str] = typer.Option(
None, '--description', '-d', help="Description metadata"
),
public: bool = typer.Option(False, '-pub', help="Indicates a public goal visible to all users (default false)"),
name: Optional[str] = typer.Option(
None, '--name', '-n', help="Name of the new goal (default is the file name without extension)"
),
model_id: Optional[int] = typer.Option(
None, '--model', '-m', help="Mission model ID of specification to add this to"
),
plan_id: Optional[int] = typer.Option(
None, '--plan', '-p', help="Plan ID of the specification to add this to"
)
):
client = CommandContext.get_client()
filename, extension = _get_name_and_ext(path)
if name is None:
name = filename
upload_obj = {}
if extension == '.ts':
with open(path, "r") as f:
upload_obj["definition"] = f.read()
upload_obj["type"] = "EDSL"
elif extension == '.jar':
jar_id = client.upload_file(path)
upload_obj["uploaded_jar_id"] = jar_id
upload_obj["parameter_schema"] = {}
upload_obj["type"] = "JAR"
else:
raise RuntimeError(f"Unsupported goal file extension: {extension}")
metadata = {"name": name}
if description is not None:
metadata["description"] = description
metadata["public"] = public
if model_id is not None:
metadata["models_using"] = {"data": {"model_id": model_id}}
if plan_id is not None:
spec_id = client.get_scheduling_specification_for_plan(plan_id)
metadata["plans_using"] = {"data": {"specification_id": spec_id}}
upload_obj["metadata"] = {"data": metadata}
resp = client.upload_scheduling_goals([upload_obj])
id = resp[0]["goal_id"]
typer.echo(f"Uploaded scheduling goal to venue. ID: {id}")


@app.command()
def update(
path: str = typer.Argument(default=...),
goal_id: Optional[int] = typer.Option(None, '--goal', '-g', help="Goal ID of goal to be updated (will search by name if omitted)"),
name: Optional[str] = typer.Option(None, '--name', '-n', help="Name of the goal to be updated (ignored if goal is provided, default is the file name without extension)"),
):
client = CommandContext.get_client()
filename, extension = _get_name_and_ext(path)
if goal_id is None:
if name is None:
name = filename
goal_id = client.get_goal_id_for_name(name)
upload_obj = {"goal_id": goal_id}
if extension == '.ts':
with open(path, "r") as f:
upload_obj["definition"] = f.read()
upload_obj["type"] = "EDSL"
elif extension == '.jar':
jar_id = client.upload_file(path)
upload_obj["uploaded_jar_id"] = jar_id
upload_obj["parameter_schema"] = {}
upload_obj["type"] = "JAR"
else:
raise RuntimeError(f"Unsupported goal file extension: {extension}")

resp = client.upload_scheduling_goals([upload_obj])
id = resp[0]["goal_id"]
typer.echo(f"Uploaded new version of scheduling goal to venue. ID: {id}")


@app.command()
def delete(
goal_id: int = typer.Option(
..., help="Goal ID of goal to be deleted", prompt=True
)
):
"""Delete scheduling goal"""
client = CommandContext.get_client()

resp = client.delete_scheduling_goal(goal_id)
typer.echo("Successfully deleted Goal ID: " + str(resp))

@app.command()
def delete_all_goals_for_plan(
plan_id: int = typer.Option(
..., help="Plan ID", prompt=True
),
):
client = CommandContext.get_client()

specification = client.get_scheduling_specification_for_plan(plan_id)
clear_goals = client.get_scheduling_goals_by_specification(specification) # response is in asc order

if len(clear_goals) == 0: # no goals to clear
typer.echo("No goals to delete.")
return

typer.echo("Deleting goals for Plan ID {plan}: ".format(plan=plan_id), nl=False)
goal_ids = []
for goal in clear_goals:
goal_ids.append(goal["goal_metadata"]["id"])
typer.echo(str(goal["goal_metadata"]["id"]) + " ", nl=False)
typer.echo()

client.delete_scheduling_goals(goal_ids)
97 changes: 0 additions & 97 deletions src/aerie_cli/commands/scheduling.py

This file was deleted.

4 changes: 2 additions & 2 deletions tests/integration_tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ Integration tests are automatically run by CI against all supported Aerie versio
- Test all `plans` commands
- Tests simulations and `plans download...` commands as well

### [Scheduling test](test_scheduling.py)
- Test all `scheduling` commands
### [Goals test](test_goals.py)
- Test all `goals` commands

### [Expansion test](test_expansion.py)
- Test all `expansion` commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def cli_schedule_upload():
fid.write(GOAL_PATH)
result = runner.invoke(
app,
["scheduling", "upload"],
["goals", "upload"],
input=str(model_id) + "\n" + str(plan_id) + "\n" + schedule_file_path + "\n",
catch_exceptions=False,
)
Expand All @@ -97,7 +97,7 @@ def test_schedule_delete():

result = runner.invoke(
app,
["scheduling", "delete"],
["goals", "delete"],
input=str(goal_id) + "\n",
catch_exceptions=False,
)
Expand All @@ -113,7 +113,7 @@ def test_schedule_delete_all():
# Delete all goals
result = runner.invoke(
app,
["scheduling", "delete-all-goals-for-plan"],
["goals", "delete-all-goals-for-plan"],
input=str(plan_id) + "\n",
catch_exceptions=False,
)
Expand Down

0 comments on commit c2956d9

Please sign in to comment.