Skip to content

Commit

Permalink
Pull out non-requested interpreters from spack.lock file and add to d…
Browse files Browse the repository at this point in the history
…ata passed to front-end. (#59)
  • Loading branch information
mjkw31 authored Oct 16, 2024
1 parent 282f5c0 commit 0de65ab
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 1 deletion.
6 changes: 6 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type Environment {
tags: [String!]!
hidden: Boolean!
cachedEnvs: [Environment!]!
interpreters: Interpreters!
requested: DateTime
buildStart: DateTime
buildDone: DateTime
Expand Down Expand Up @@ -80,6 +81,11 @@ type HiddenSuccess implements Success {
message: String!
}

type Interpreters {
r: String
python: String
}

type InvalidInputError implements Error {
message: String!
}
Expand Down
45 changes: 45 additions & 0 deletions softpack_core/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import itertools
import json
import shutil
import tempfile
from dataclasses import dataclass
Expand Down Expand Up @@ -49,6 +50,14 @@ def from_name(cls, name: str) -> 'Package':
return Package(name=name)


@strawberry.type
class Interpreters:
"""A Strawberry model representing the interpreters in an environment."""

r: Optional[str] = None
python: Optional[str] = None


@strawberry.enum
class State(Enum):
"""Environment states."""
Expand Down Expand Up @@ -77,6 +86,7 @@ class Artifacts:
module_file = "module"
readme_file = "README.md"
meta_file = "meta.yml"
spack_file = "spack.lock"
built_by_softpack_file = ".built_by_softpack"
built_by_softpack = Type.softpack.value
generated_from_module_file = ".generated_from_module"
Expand Down Expand Up @@ -168,6 +178,41 @@ def spec(self) -> Box:
info["hidden"] = getattr(metadata, "hidden", False)
info["force_hidden"] = getattr(metadata, "force_hidden", False)

info["interpreters"] = Interpreters()

if Artifacts.spack_file in self.obj:
hasR = False
hasPython = False

for pkg in cast(list[Package], info["packages"]):
if pkg.name == "r":
hasR = True

if pkg.name == "python":
hasPython = True

if hasR and hasPython:
break

if not hasR or not hasPython:
data = json.loads(self.obj[Artifacts.spack_file].data)

for hash in data.get("concrete_specs", {}):
spec = data["concrete_specs"][hash]

if not hasR and spec.get("name", "") == "r":
hasR = True
info["interpreters"].r = spec.get("version", "")

if not hasPython and spec.get("name", "") == "python":
hasPython = True
info["interpreters"].python = spec.get(
"version", ""
)

if hasR and hasPython:
break

return info

def metadata(self) -> Box:
Expand Down
11 changes: 10 additions & 1 deletion softpack_core/schemas/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@
from strawberry.file_uploads import Upload

from softpack_core.app import app
from softpack_core.artifacts import Artifacts, Package, State, Type, artifacts
from softpack_core.artifacts import (
Artifacts,
Interpreters,
Package,
State,
Type,
artifacts,
)
from softpack_core.module import GenerateEnvReadme, ToSoftpackYML
from softpack_core.schemas.base import BaseSchema

Expand Down Expand Up @@ -327,6 +334,7 @@ class Environment:
tags: list[str]
hidden: bool
cachedEnvs: list["Environment"] = field(default_factory=list)
interpreters: Interpreters = field(default_factory=Interpreters)

requested: Optional[datetime.datetime] = None
build_start: Optional[datetime.datetime] = None
Expand Down Expand Up @@ -409,6 +417,7 @@ def from_artifact(cls, obj: Artifacts.Object) -> Optional["Environment"]:
type=spec.get("type", ""),
tags=spec.tags,
hidden=spec.hidden,
interpreters=spec.get("interpreters", Interpreters()),
)
except KeyError:
return None
Expand Down
165 changes: 165 additions & 0 deletions tests/integration/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import datetime
import io
import json
from pathlib import Path
from typing import Optional

Expand All @@ -27,6 +28,7 @@
HiddenSuccess,
InvalidInputError,
Package,
PackageInput,
State,
UpdateEnvironmentSuccess,
WriteArtifactSuccess,
Expand Down Expand Up @@ -613,3 +615,166 @@ def test_environment_with_requested_recipe(
result = Environment.create(testable_env_input)
assert isinstance(result, CreateEnvironmentSuccess)
httpx_post.assert_not_called()


def test_interpreters(
httpx_post, testable_env_input: EnvironmentInput
) -> None:
env = EnvironmentInput.from_path("users/me/my_env-1")
env.packages = [
PackageInput.from_name("pkg@1"),
PackageInput.from_name("pkg@2"),
]

assert isinstance(Environment.create(env), CreateEnvironmentSuccess)

artifacts.commit_and_push(
artifacts.create_file(
Path(Artifacts.environments_root, env.path, env.name),
Artifacts.spack_file,
json.dumps(
{
"concrete_specs": {
"long_hash": {
"name": "python",
"version": "1.2.3",
}
}
}
),
False,
True,
),
"add spack.lock for environment",
)

env = Environment.from_artifact(artifacts.get(env.path, env.name))

assert env.interpreters.python == "1.2.3"
assert env.interpreters.r is None

artifacts.commit_and_push(
artifacts.create_file(
Path(Artifacts.environments_root, env.path, env.name),
Artifacts.spack_file,
json.dumps(
{
"concrete_specs": {
"long_hash": {
"name": "r",
"version": "4.5.6",
}
}
}
),
False,
True,
),
"add spack.lock for environment",
)

env = Environment.from_artifact(artifacts.get(env.path, env.name))

assert env.interpreters.python is None
assert env.interpreters.r == "4.5.6"

artifacts.commit_and_push(
artifacts.create_file(
Path(Artifacts.environments_root, env.path, env.name),
Artifacts.spack_file,
json.dumps(
{
"concrete_specs": {
"short_hash": {
"name": "python",
"version": "3.11.4",
},
"long_hash": {
"name": "r",
"version": "4.4.1",
},
}
}
),
False,
True,
),
"add spack.lock for environment",
)

env = Environment.from_artifact(artifacts.get(env.path, env.name))

assert env.interpreters.python == "3.11.4"
assert env.interpreters.r == "4.4.1"

env = EnvironmentInput.from_path("users/me/my_env-2")
env.packages = [
PackageInput.from_name("r@1"),
]

assert isinstance(Environment.create(env), CreateEnvironmentSuccess)

artifacts.commit_and_push(
artifacts.create_file(
Path(Artifacts.environments_root, env.path, env.name),
Artifacts.spack_file,
json.dumps(
{
"concrete_specs": {
"short_hash": {
"name": "python",
"version": "3.11.4",
},
"long_hash": {
"name": "r",
"version": "4.4.1",
},
}
}
),
False,
True,
),
"add spack.lock for environment",
)

env = Environment.from_artifact(artifacts.get(env.path, env.name))

assert env.interpreters.python == "3.11.4"
assert env.interpreters.r is None

env = EnvironmentInput.from_path("users/me/my_env-3")
env.packages = [
PackageInput.from_name("python@2"),
]

assert isinstance(Environment.create(env), CreateEnvironmentSuccess)

artifacts.commit_and_push(
artifacts.create_file(
Path(Artifacts.environments_root, env.path, env.name),
Artifacts.spack_file,
json.dumps(
{
"concrete_specs": {
"short_hash": {
"name": "python",
"version": "3.11.4",
},
"long_hash": {
"name": "r",
"version": "4.4.1",
},
}
}
),
False,
True,
),
"add spack.lock for environment",
)

env = Environment.from_artifact(artifacts.get(env.path, env.name))

assert env.interpreters.python is None
assert env.interpreters.r == "4.4.1"

0 comments on commit 0de65ab

Please sign in to comment.