Skip to content

Commit

Permalink
Fixes #109: Simple type check unified
Browse files Browse the repository at this point in the history
Signed-off-by: Manuel Boehm <[email protected]>
Signed-off-by: Gunnar Andersson <[email protected]>
  • Loading branch information
mnlbm authored and gunnar-mb committed Mar 18, 2024
1 parent 8bf3997 commit fa2c6f8
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 6 deletions.
10 changes: 6 additions & 4 deletions ifex/model/ifex_ast_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

from collections import OrderedDict
from dataclasses import is_dataclass, fields
from datetime import date, datetime
from ifex.model import ifex_ast
from ifex.model.type_checking_constructor_mixin import add_constructor

Expand All @@ -67,6 +68,8 @@ def is_empty(node) -> bool:
else:
return node is None

def is_simple_type(t) -> bool:
return t in [str, int, float, bool, date, datetime]

def ifex_ast_to_dict(node, debug_context="") -> OrderedDict:

Expand All @@ -76,7 +79,7 @@ def ifex_ast_to_dict(node, debug_context="") -> OrderedDict:
raise TypeError(f"None-value should not be passed to function, {debug_context=}")

# Strings and Ints are directly understood by the YAML output printer so just put them in.
if type(node) in [str, int]:
if is_simple_type(type(node)):
return node

# In addition to dicts, we might have python lists, which will be output as lists in YAML
Expand All @@ -95,13 +98,13 @@ def ifex_ast_to_dict(node, debug_context="") -> OrderedDict:
# we skip them. Note that empty items can happen only on fields that are
# Optional, otherwise the type-checking constructor would have caught the
# error.

for f in fields(node):
item = getattr(node, f.name)
if not is_empty(item):
ret[f.name] = ifex_ast_to_dict(item, debug_context=str(f))

return ret
return ret


def ifex_ast_as_yaml(node):
Expand All @@ -126,4 +129,3 @@ def ifex_ast_as_yaml(node):
print(ifex_ast_to_dict(root))
print("\n--- Test objects as YAML: ---")
print(ifex_ast_as_yaml(root))

14 changes: 13 additions & 1 deletion ifex/schema/ifex_to_json_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"""

from dataclasses import fields
from datetime import datetime, date

from ifex.model.ifex_ast_construction import is_simple_type

from ifex.model.ifex_ast import AST
from ifex.model.ifex_ast_introspect import actual_type, field_actual_type, field_inner_type, inner_type, is_forwardref, is_list, type_name, field_is_list, field_is_optional, field_referenced_type
from typing import Any
Expand All @@ -29,10 +33,18 @@
def get_type_name(t):
if t is Any:
return "Any"
if t is bool:
return "boolean"
elif t is datetime:
return "string"
elif t is date:
return "string"
elif t is str:
return "string"
elif t is int:
return "integer"
elif t is float:
return "number"
else: # "complex type"
return type_name(actual_type(t))

Expand Down Expand Up @@ -109,7 +121,7 @@ def collect_type_info(t, collection={}, seen={}):

# We don't need to gather information about primitive types because they
# will not have any member fields below them.
if t in [str, int, Any]:
if is_simple_type(t):
return

# ForwardRef will fail if we try to recurse over its children. However,
Expand Down
57 changes: 56 additions & 1 deletion tests/gen_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@
# Test code for code generator part of IFEX
# ----------------------------------------------------------------------------
# This is maybe not ideal way but seems efficient enough
from dataclasses import dataclass
from datetime import date, datetime
from typing import Optional

import yaml

from ifex.model import ifex_ast, ifex_parser, ifex_generator
import dacite, pytest
import os

from ifex.model.ifex_ast import Argument, AST, Namespace, Interface, Method
from ifex.model.ifex_ast_construction import ifex_ast_as_yaml

TestPath = os.path.dirname(os.path.realpath(__file__))

def test_x():
Expand Down Expand Up @@ -70,8 +79,54 @@ def test_expected_raised_exceptions():
with pytest.raises(dacite.UnexpectedDataError) as ee:
ast_root = ifex_parser.get_ast_from_yaml_file(os.path.join(path, 'input.yaml'))

@dataclass
class Argument(Argument):
name: str
simple_type_str: Optional[str] = None
simple_type_int: Optional[int] = None
simple_type_bool: Optional[bool] = None
simple_type_float: Optional[float] = None
simple_type_date: Optional[date] = None
simple_type_datetime: Optional[datetime] = None


def test_simple_types():
simple_types = yaml.safe_load(ifex_ast_as_yaml(AST(namespaces=[
Namespace(
name="namespace1",
interface=Interface(
name="interface1",
methods=[
Method(
name="method1",
input=[
Argument(
name="argument1",
datatype="mixed",
simple_type_str="string",
simple_type_int=123,
simple_type_bool=True,
simple_type_float=123.45,
simple_type_date=date.today(),
simple_type_datetime=datetime.now()
)
]
)
]
)
)
])))["namespaces"][0]["interface"]["methods"][0]["input"][0]

assert type(simple_types["simple_type_str"]) == str
assert type(simple_types["simple_type_int"]) == int
assert type(simple_types["simple_type_bool"]) == bool
assert type(simple_types["simple_type_float"]) == float
assert type(simple_types["simple_type_date"]) == date
assert type(simple_types["simple_type_datetime"]) == datetime


# Unused
default_templates = {}

# TODO: Loop over subdirectories in tests to perform tests for different
# 'input.yaml/template/result' files
# 'input.yaml/template/result' files

0 comments on commit fa2c6f8

Please sign in to comment.