Skip to content

Commit 2656c8a

Browse files
committed
dur
Signed-off-by: Ayush Kamat <[email protected]>
1 parent 04ebe01 commit 2656c8a

File tree

6 files changed

+76
-27
lines changed

6 files changed

+76
-27
lines changed

src/latch_cli/constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
class Units(int, Enum):
77
KiB = 2**10
8-
kB = 10**3
8+
kB = 10**3 # noqa: N815
99

1010
MiB = 2**20
1111
MB = 10**6
@@ -22,7 +22,7 @@ class LatchConstants:
2222
base_image: str = (
2323
"812206152185.dkr.ecr.us-west-2.amazonaws.com/latch-base:cb01-main"
2424
)
25-
nextflow_latest_version: str = "v2.3.0"
25+
nextflow_latest_version: str = "v3.0.5"
2626

2727
file_max_size: int = 4 * Units.MiB
2828
file_chunk_size: int = 64 * Units.MiB

src/latch_cli/docker_utils/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,13 @@ def generate_dockerignore(
425425
click.secho(f"Successfully generated .dockerignore `{dest}`", fg="green")
426426

427427

428-
def get_default_dockerfile(pkg_root: Path, *, wf_type: WorkflowType, overwrite: bool = False):
428+
def get_default_dockerfile(
429+
pkg_root: Path, *, wf_type: WorkflowType, overwrite: bool = False
430+
):
429431
default_dockerfile = pkg_root / "Dockerfile"
430432

431433
config = get_or_create_workflow_config(
432-
pkg_root=pkg_root,
434+
pkg_root / ".latch" / "config",
433435
base_image_type=BaseImageOptions.nextflow
434436
if wf_type == WorkflowType.nextflow
435437
else BaseImageOptions.default,

src/latch_cli/main.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ def init(
239239
type=click.Path(exists=True, dir_okay=False, path_type=Path),
240240
help="Path to a direnv file (.env) containing environment variables to inject into the container.",
241241
)
242+
@click.option(
243+
"--output",
244+
"-o",
245+
type=click.Path(exists=True, dir_okay=False, path_type=Path),
246+
help="Where to write the result Dockerfile. Default is Dockerfile in the root of the workflow directory.",
247+
)
242248
def dockerfile(
243249
pkg_root: Path,
244250
snakemake: bool = False,
@@ -250,6 +256,7 @@ def dockerfile(
250256
pyproject: Optional[Path] = None,
251257
pip_requirements: Optional[Path] = None,
252258
direnv: Optional[Path] = None,
259+
output: Optional[Path] = None,
253260
):
254261
"""Generates a user editable dockerfile for a workflow and saves under `pkg_root/Dockerfile`.
255262
@@ -275,8 +282,11 @@ def dockerfile(
275282
workflow_type = WorkflowType.nextflow
276283
base_image = BaseImageOptions.nextflow
277284

285+
if output is None:
286+
output = pkg_root / "Dockerfile"
287+
278288
config = get_or_create_workflow_config(
279-
pkg_root=pkg_root, base_image_type=base_image
289+
output.parent / ".latch" / "config", base_image_type=base_image
280290
)
281291

282292
builder = DockerfileBuilder(
@@ -290,7 +300,7 @@ def dockerfile(
290300
pip_requirements=pip_requirements,
291301
direnv=direnv,
292302
)
293-
builder.generate(overwrite=force)
303+
builder.generate(dest=output, overwrite=force)
294304

295305
if not click.confirm("Generate a .dockerignore?"):
296306
return

src/latch_cli/nextflow/parse_schema.py

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from dataclasses import dataclass
33
from pathlib import Path
44
from textwrap import indent
5-
from typing import Generic, Literal, Optional, TypedDict, TypeVar, Union
5+
from typing import Literal, Optional, TypedDict, Union
66

77
import click
88
from typing_extensions import NotRequired, TypeAlias
@@ -63,17 +63,33 @@ class NfBooleanType(TypedDict):
6363
metadata: CommonMetadata
6464

6565

66-
EnumT = TypeVar("EnumT", str, int, float)
66+
class NfStringEnumType(TypedDict):
67+
type: Literal["enum"]
68+
flavor: Literal["string"]
69+
values: list[str]
70+
default: NotRequired[str]
71+
metadata: CommonMetadata
72+
73+
74+
class NfIntegerEnumType(TypedDict):
75+
type: Literal["enum"]
76+
flavor: Literal["integer"]
77+
values: list[int]
78+
default: NotRequired[int]
79+
metadata: CommonMetadata
6780

6881

69-
class NfEnumType(TypedDict, Generic[EnumT]):
82+
class NfNumberEnumType(TypedDict):
7083
type: Literal["enum"]
71-
flavor: Literal["string", "integer", "number"]
72-
values: list[EnumT]
73-
default: NotRequired[EnumT]
84+
flavor: Literal["number"]
85+
values: list[float]
86+
default: NotRequired[float]
7487
metadata: CommonMetadata
7588

7689

90+
NfEnumType: TypeAlias = Union[NfStringEnumType, NfIntegerEnumType, NfNumberEnumType]
91+
92+
7793
class NfArrayType(TypedDict):
7894
type: Literal["array"]
7995
default: NotRequired[list]
@@ -106,9 +122,7 @@ class NfBlobType(TypedDict):
106122
NfStringType,
107123
NfIntegerType,
108124
NfFloatType,
109-
NfEnumType[str],
110-
NfEnumType[float],
111-
NfEnumType[int],
125+
NfEnumType,
112126
NfBooleanType,
113127
NfArrayType,
114128
NfObjectType,
@@ -261,7 +275,7 @@ def parse_bool(
261275

262276
def parse_enum(
263277
param_name: str, properties: dict[str, object], required_set: set[str]
264-
) -> Union[NfEnumType[str], NfEnumType[int], NfEnumType[float]]:
278+
) -> NfEnumType:
265279
typ = properties["type"]
266280
assert "enum" in properties
267281

@@ -277,13 +291,37 @@ def parse_enum(
277291
assert values is not None, "enum parameter must specify a set of `values`"
278292
assert isinstance(values, list), "`values` must be a list"
279293

280-
# todo(ayush): fix type errors here
281-
return NfEnumType(
294+
if typ == "string":
295+
assert default is None or isinstance(default, str), "default must be a string"
296+
297+
return NfStringEnumType(
298+
type="enum",
299+
flavor="string",
300+
values=values,
301+
metadata=metadata,
302+
**({"default": default} if default is not None else {}),
303+
)
304+
if typ == "integer":
305+
assert default is None or isinstance(default, int), "default must be an integer"
306+
307+
return NfIntegerEnumType(
308+
type="enum",
309+
flavor="integer",
310+
values=values,
311+
metadata=metadata,
312+
**({"default": default} if default is not None else {}),
313+
)
314+
315+
assert default is None or isinstance(default, (int, float)), (
316+
"default must be a number"
317+
)
318+
319+
return NfNumberEnumType(
282320
type="enum",
283-
flavor=typ,
321+
flavor="number",
284322
values=values,
285323
metadata=metadata,
286-
**({"default": default} if default is not None else {}),
324+
**({"default": float(default)} if default is not None else {}),
287325
)
288326

289327

src/latch_cli/services/init/init.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,9 @@ def init(
379379

380380
template_func(pkg_root)
381381

382-
config = get_or_create_workflow_config(pkg_root, base_image_type)
382+
config = get_or_create_workflow_config(
383+
pkg_root / ".latch" / "config", base_image_type
384+
)
383385

384386
wf_type = WorkflowType.latchbiosdk
385387
if chosen_template == "Snakemake Example":

src/latch_cli/workflow_config.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ class LatchWorkflowConfig:
3131

3232

3333
def get_or_create_workflow_config(
34-
pkg_root: Path, base_image_type: BaseImageOptions = BaseImageOptions.default
34+
config_path: Path, base_image_type: BaseImageOptions = BaseImageOptions.default
3535
) -> LatchWorkflowConfig:
36-
config_path = pkg_root / latch_constants.pkg_config
3736
if config_path.exists() and config_path.is_file():
3837
try:
3938
return LatchWorkflowConfig(**json.loads(config_path.read_text()))
@@ -60,9 +59,7 @@ def get_or_create_workflow_config(
6059
date=datetime.now(timezone.utc).isoformat(),
6160
)
6261

63-
(pkg_root / ".latch").mkdir(exist_ok=True)
64-
65-
with (pkg_root / latch_constants.pkg_config).open("w") as f:
66-
f.write(json.dumps(asdict(config)))
62+
config_path.parent.mkdir(parents=True, exist_ok=True)
63+
config_path.write_text(json.dumps(asdict(config)))
6764

6865
return config

0 commit comments

Comments
 (0)