diff --git a/jeeves/cli/cli.py b/jeeves/cli/cli.py index 52e0461..fd5f693 100644 --- a/jeeves/cli/cli.py +++ b/jeeves/cli/cli.py @@ -1,3 +1,5 @@ +import os.path + import click from jeeves.cli.echo import info, error, title, success @@ -20,9 +22,15 @@ def main(): help="Display output for flow", ) def execute(defintinion_file, print_output): + extension = os.path.splitext(defintinion_file.name)[1][1:] + + if not hasattr(FlowParser, f"from_{extension}"): + error(f"Extension {extension} is not supported") + exit(1) + info(f"Running flow from {defintinion_file.name}") - flow = FlowParser.from_json(defintinion_file.read()) + flow = getattr(FlowParser, f"from_{extension}")(defintinion_file.read()) title(f"Running flow: {flow.name}") executor = Executor(flow) diff --git a/jeeves/core/objects.py b/jeeves/core/objects.py index 16e160d..15e20a6 100644 --- a/jeeves/core/objects.py +++ b/jeeves/core/objects.py @@ -1,12 +1,12 @@ from typing import Any, Dict, List, Text, Optional from dataclasses import field -from pydantic import BaseModel +import pydantic from jeeves.core.registry import ActionRegistry -class BaseObject(BaseModel): +class BaseObject(pydantic.BaseModel): pass @@ -18,7 +18,7 @@ class Result(BaseObject): class Task(BaseObject): name: Text type: Text - parameters: Dict[Any, Any] + parameters: Optional[Dict[Any, Any]] = None @property def action(self): diff --git a/jeeves/core/parsers.py b/jeeves/core/parsers.py index 7ba75c6..40a5679 100644 --- a/jeeves/core/parsers.py +++ b/jeeves/core/parsers.py @@ -1,4 +1,6 @@ +import json from typing import Any, Text, MutableMapping +from pathlib import Path import toml @@ -8,13 +10,25 @@ from jeeves.core.objects import Flow, BaseObject class ObjectParser: object: BaseObject = None + @classmethod + def from_dict(cls, serialized: MutableMapping[str, Any]) -> BaseObject: + return cls.object.parse_obj(serialized) + + @classmethod + def to_dict(cls, obj: BaseObject) -> dict: + return obj.dict() + @classmethod def from_json(cls, serialized: Text) -> BaseObject: return cls.object.parse_raw(serialized) @classmethod - def from_dict(cls, serialized: MutableMapping[str, Any]) -> BaseObject: - return cls.object.parse_obj(serialized) + def from_json_file(cls, path: Path) -> BaseObject: + return cls.object.parse_file(path) + + @classmethod + def to_json(cls, obj: BaseObject) -> Text: + return json.dumps(cls.to_dict(obj)) @classmethod def from_toml(cls, serialized: Text) -> BaseObject: @@ -27,8 +41,8 @@ class ObjectParser: return cls.from_dict(dct) @classmethod - def to_dict(cls, obj: BaseObject) -> dict: - return obj.dict() + def to_toml(cls, obj: BaseObject) -> Text: + return toml.dumps(cls.to_dict(obj)) class FlowParser(ObjectParser): diff --git a/jeeves/core/tests/test_parsers.py b/jeeves/core/tests/test_parsers.py index 87a4c16..431bee3 100644 --- a/jeeves/core/tests/test_parsers.py +++ b/jeeves/core/tests/test_parsers.py @@ -1,4 +1,11 @@ -from jeeves.core.objects import BaseObject +# pylint: disable=no-member +import os +import json +import tempfile + +import toml + +from jeeves.core.objects import Flow, BaseObject from jeeves.core.parsers import FlowParser from .factories import FlowFactory @@ -15,11 +22,59 @@ EXPORTED_FLOW = { def test_parser_object_to_dict_ok(): - obj = FlowFactory() + obj: Flow = FlowFactory() result = FlowParser.to_dict(obj) - obj = FlowParser.from_dict(result) + assert set(obj.fields).issubset(set(result)) def test_parser_dict_to_object_ok(): obj = FlowParser.from_dict(EXPORTED_FLOW) + assert isinstance(obj, Flow) + + +######## +# JSON # +######## +def test_parser_json_to_object_ok(): + obj = FlowParser.from_json(json.dumps(EXPORTED_FLOW)) assert isinstance(obj, BaseObject) + + +def test_parser_json_file_to_object_ok(): + export_file = tempfile.NamedTemporaryFile(delete=False, mode="w") + with export_file as handler: + handler.write(json.dumps(EXPORTED_FLOW)) + + obj = FlowParser.from_json_file(export_file.name) + assert isinstance(obj, BaseObject) + os.unlink(export_file.name) + + +def test_parser_obj_to_json_ok(): + obj: Flow = FlowFactory() + result = FlowParser.to_json(obj) + assert set(obj.fields).issubset(set(json.loads(result))) + + +######## +# TOML # +######## +def test_parser_toml_to_object_ok(): + obj = FlowParser.from_toml(toml.dumps(EXPORTED_FLOW)) + assert isinstance(obj, BaseObject) + + +def test_parser_toml_file_to_object_ok(): + export_file = tempfile.NamedTemporaryFile(delete=False, mode="w") + with export_file as handler: + handler.write(toml.dumps(EXPORTED_FLOW)) + + obj = FlowParser.from_toml_file(export_file.name) + assert isinstance(obj, BaseObject) + os.unlink(export_file.name) + + +def test_parser_obj_to_toml_ok(): + obj: Flow = FlowFactory() + result = FlowParser.to_toml(obj) + assert set(obj.fields).issubset(set(toml.loads(result)))