diff --git a/.github/workflows/tests-and-docs.yml b/.github/workflows/tests-and-docs.yml index 08301122b99..0f3b4bb0386 100644 --- a/.github/workflows/tests-and-docs.yml +++ b/.github/workflows/tests-and-docs.yml @@ -86,14 +86,12 @@ jobs: # Install askem pip install ".[all]" - - + # Install tree-sitter parser (for Python component unit tests) - name: Install tree-sitter parsers working-directory: . run: python skema/program_analysis/tree_sitter_parsers/build_parsers.py --ci --all - # docs (API) # generate python docs using pdoc - name: "Create documentation for Python components (API docs)" diff --git a/pyproject.toml b/pyproject.toml index 4704047cd71..779f3235795 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,11 +15,11 @@ dependencies=[ "numpy", "dill==0.3.7", "networkx==2.8.8", - "PyYAML", + "PyYAML==6.*", "tree-sitter==0.20.4", "neo4j==5.14.1", "requests", - "beautifulsoup4", # used to remove comments etc from pMML before sending to MORAE + "beautifulsoup4==4.12.*", # used to remove comments etc from pMML before sending to MORAE "typing_extensions", # see https://github.com/pydantic/pydantic/issues/5821#issuecomment-1559196859 "fastapi~=0.100.0", "starlette", @@ -27,7 +27,7 @@ dependencies=[ "pydantic>=2.0.0", "uvicorn", "python-multipart", - "func_timeout" + "func_timeout==4.3.5" ] # The Python program analysis pipeline does not currently work with Python 3.9 # or 3.10. This may change in the future. @@ -111,7 +111,7 @@ all = ["skema[core]", "skema[dev]", "skema[doc]", "skema[demo]", "skema[annotati [tool.setuptools.package-data] # needed to ensure models are included in package/discoverable -"*" = ["*.json", "vocab.txt", "*.pt", "*.png", "*.html", "*.yml", "*.yaml"] +"*" = ["*.json", "*vocab.txt", "*.pt", "*.png", "*.html", "*.yml", "*.yaml"] [tool.setuptools.dynamic] readme = {file = ["README.md"], content-type = "text/markdown"} diff --git a/skema/program_analysis/CAST/fortran/tests/test_compound_conditional_cast_fortran.py b/skema/program_analysis/CAST/fortran/tests/test_compound_conditional_cast_fortran.py new file mode 100644 index 00000000000..48137e6b37d --- /dev/null +++ b/skema/program_analysis/CAST/fortran/tests/test_compound_conditional_cast_fortran.py @@ -0,0 +1,101 @@ +import pytest +from tempfile import TemporaryDirectory +from pathlib import Path + +from skema.program_analysis.CAST.fortran.ts2cast import TS2CAST +from skema.program_analysis.CAST2FN.model.cast import ( + Assignment, + Var, + Name, + CASTLiteralValue, + ModelIf, + Operator, + ScalarType +) + +def cond_compound1(): + return """ +program cond_compound1 +integer :: a = 3 +if (a .gt. 1 .and. a .lt. 10) then + a = 40 +end if +end program cond_compound1 + """ + + +def generate_cast(test_file_string): + with TemporaryDirectory() as temp: + source_path = Path(temp) / "source.f95" + source_path.write_text(test_file_string) + out_cast = TS2CAST(str(source_path)).out_cast + + return out_cast[0] + +def test_cond_compound1(): + exp_cast = generate_cast(cond_compound1()) + + asg_node = exp_cast.nodes[0].body[0] + + assert isinstance(asg_node, Assignment) + assert isinstance(asg_node.left, Var) + assert isinstance(asg_node.left.val, Name) + assert asg_node.left.val.name == "a" + assert asg_node.left.val.id == 0 + + assert isinstance(asg_node.right, CASTLiteralValue) + assert asg_node.right.value_type == ScalarType.INTEGER + assert asg_node.right.value == '3' + + cond_node = exp_cast.nodes[0].body[1] + cond_expr = cond_node.expr + assert isinstance(cond_node, ModelIf) + assert isinstance(cond_expr, ModelIf) + + if_node = cond_expr + assert isinstance(if_node, ModelIf) + + expr = if_node.expr + assert isinstance(expr, Operator) + assert expr.op == ".gt." + assert len(expr.operands) == 2 + assert isinstance(expr.operands[1], CASTLiteralValue) + assert expr.operands[1].value_type == ScalarType.INTEGER + assert expr.operands[1].value == "1" + + assert isinstance(expr.operands[0], Name) + assert expr.operands[0].name == "a" + assert expr.operands[0].id == 0 + + assert len(if_node.body) == 1 + body = if_node.body[0] + assert isinstance(body, Operator) + assert body.op == ".lt." + assert len(body.operands) == 2 + assert isinstance(body.operands[0], Name) + assert body.operands[0].name == "a" + assert body.operands[0].id == 0 + + assert isinstance(body.operands[1], CASTLiteralValue) + assert body.operands[1].value_type == ScalarType.INTEGER + assert body.operands[1].value == "10" + + assert len(if_node.orelse) == 1 + orelse = if_node.orelse[0] + assert isinstance(orelse, CASTLiteralValue) + assert orelse.value_type == ScalarType.BOOLEAN + assert orelse.value == False + + cond_body = cond_node.body + assert len(cond_body) == 1 + assert isinstance(cond_body[0], Assignment) + assert isinstance(cond_body[0].left, Var) + assert cond_body[0].left.val.name == "a" + assert cond_body[0].left.val.id == 0 + + assert isinstance(cond_body[0].right, CASTLiteralValue) + assert cond_body[0].right.value_type == ScalarType.INTEGER + assert cond_body[0].right.value == '40' + + cond_else = cond_node.orelse + assert len(cond_else) == 0 diff --git a/skema/program_analysis/CAST/fortran/tests/test_conditional_cast_fortran.py b/skema/program_analysis/CAST/fortran/tests/test_conditional_cast_fortran.py index 2efd7784bab..c94a30b87d2 100644 --- a/skema/program_analysis/CAST/fortran/tests/test_conditional_cast_fortran.py +++ b/skema/program_analysis/CAST/fortran/tests/test_conditional_cast_fortran.py @@ -9,7 +9,8 @@ Name, CASTLiteralValue, ModelIf, - Operator + Operator, + ScalarType ) def cond1(): @@ -63,7 +64,7 @@ def test_cond1(): assert asg_node.left.val.name == "x" assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '2' assert isinstance(cond_node, ModelIf) @@ -103,7 +104,7 @@ def test_cond2(): assert asg_node.left.val.id == 0 assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '2' asg_node = exp_cast.nodes[0].body[1] @@ -114,7 +115,7 @@ def test_cond2(): assert asg_node.left.val.id == 1 assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '3' assert isinstance(cond_node, ModelIf) @@ -127,7 +128,7 @@ def test_cond2(): assert isinstance(cond_expr.operands[0], Name) assert cond_expr.operands[0].name == "x" assert isinstance(cond_expr.operands[1], CASTLiteralValue) - assert cond_expr.operands[1].value_type == "Integer" + assert cond_expr.operands[1].value_type == ScalarType.INTEGER assert cond_expr.operands[1].value == "5" assert len(cond_body) == 3 diff --git a/skema/program_analysis/CAST/fortran/tests/test_expression_cast_fortran.py b/skema/program_analysis/CAST/fortran/tests/test_expression_cast_fortran.py index 6713a169640..3e59647654e 100644 --- a/skema/program_analysis/CAST/fortran/tests/test_expression_cast_fortran.py +++ b/skema/program_analysis/CAST/fortran/tests/test_expression_cast_fortran.py @@ -7,7 +7,8 @@ Assignment, Var, Name, - CASTLiteralValue + CASTLiteralValue, + ScalarType ) def exp0(): @@ -44,7 +45,7 @@ def test_exp0(): assert asg_node.left.val.name == "x" assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '2' @@ -60,7 +61,7 @@ def test_exp1(): assert asg_node.left.val.id == 0 assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '2' # ------ @@ -72,7 +73,7 @@ def test_exp1(): assert asg_node.left.val.id == 1 assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '3' if __name__ == "__main__": diff --git a/skema/program_analysis/CAST/fortran/tests/test_for_cast_fortran.py b/skema/program_analysis/CAST/fortran/tests/test_for_cast_fortran.py index 1b4e96f2b1b..5b202981017 100644 --- a/skema/program_analysis/CAST/fortran/tests/test_for_cast_fortran.py +++ b/skema/program_analysis/CAST/fortran/tests/test_for_cast_fortran.py @@ -11,7 +11,9 @@ CASTLiteralValue, ModelIf, Loop, - Operator + Operator, + ScalarType, + StructureType ) def for1(): @@ -48,7 +50,7 @@ def test_for1(): assert asg_node.left.val.name == "x" assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '7' assert isinstance(loop_node, Loop) @@ -79,7 +81,7 @@ def test_for1(): assert isinstance(loop_pre[1], Assignment) assert isinstance(loop_pre[1].left, CASTLiteralValue) - assert loop_pre[1].left.value_type == "Tuple" + assert loop_pre[1].left.value_type == StructureType.TUPLE assert isinstance(loop_pre[1].left.value[0], Var) assert loop_pre[1].left.value[0].val.name == "i" @@ -101,7 +103,7 @@ def test_for1(): assert loop_test.operands[0].name == "sc_0" assert isinstance(loop_test.operands[1], CASTLiteralValue) - assert loop_test.operands[1].value_type == "Boolean" + assert loop_test.operands[1].value_type == ScalarType.BOOLEAN # Loop Body loop_body = loop_node.body diff --git a/skema/program_analysis/CAST/fortran/tests/test_identifier_cast_fortran.py b/skema/program_analysis/CAST/fortran/tests/test_identifier_cast_fortran.py index b6326a736a6..c532e4ac529 100644 --- a/skema/program_analysis/CAST/fortran/tests/test_identifier_cast_fortran.py +++ b/skema/program_analysis/CAST/fortran/tests/test_identifier_cast_fortran.py @@ -10,7 +10,8 @@ CASTLiteralValue, ModelIf, Loop, - Operator + Operator, + ScalarType ) def identifier1(): @@ -41,6 +42,6 @@ def test_identifier1(): assert asg_node.left.val.name == "x" assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '2' diff --git a/skema/program_analysis/CAST/fortran/tests/test_operation_cast_fortran.py b/skema/program_analysis/CAST/fortran/tests/test_operation_cast_fortran.py index ca95e64d78a..79291519e67 100644 --- a/skema/program_analysis/CAST/fortran/tests/test_operation_cast_fortran.py +++ b/skema/program_analysis/CAST/fortran/tests/test_operation_cast_fortran.py @@ -8,7 +8,8 @@ Var, Name, Operator, - CASTLiteralValue + CASTLiteralValue, + ScalarType ) def binop1(): @@ -74,11 +75,11 @@ def test_binop1(): assert isinstance(binop_node.right.operands[0], CASTLiteralValue) assert binop_node.right.operands[0].value == '2' - assert binop_node.right.operands[0].value_type == 'Integer' + assert binop_node.right.operands[0].value_type == ScalarType.INTEGER assert isinstance(binop_node.right.operands[1], CASTLiteralValue) assert binop_node.right.operands[1].value == '3' - assert binop_node.right.operands[1].value_type == 'Integer' + assert binop_node.right.operands[1].value_type == ScalarType.INTEGER def test_binop2(): exp_cast = generate_cast(binop2()) @@ -92,7 +93,7 @@ def test_binop2(): assert binop_node.left.val.id == 0 assert isinstance(binop_node.right, CASTLiteralValue) - assert binop_node.right.value_type == "Integer" + assert binop_node.right.value_type == ScalarType.INTEGER assert binop_node.right.value == '2' # ------ @@ -112,7 +113,7 @@ def test_binop2(): assert isinstance(binop_node.right.operands[1], CASTLiteralValue) assert binop_node.right.operands[1].value == '3' - assert binop_node.right.operands[1].value_type == 'Integer' + assert binop_node.right.operands[1].value_type == ScalarType.INTEGER def test_binop3(): exp_cast = generate_cast(binop3()) @@ -126,7 +127,7 @@ def test_binop3(): assert binop_node.left.val.id == 0 assert isinstance(binop_node.right, CASTLiteralValue) - assert binop_node.right.value_type == "Integer" + assert binop_node.right.value_type == ScalarType.INTEGER assert binop_node.right.value == '1' # ------ @@ -138,7 +139,7 @@ def test_binop3(): assert binop_node.left.val.id == 1 assert isinstance(binop_node.right, CASTLiteralValue) - assert binop_node.right.value_type == "Integer" + assert binop_node.right.value_type == ScalarType.INTEGER assert binop_node.right.value == '2' # ------ @@ -198,7 +199,7 @@ def test_unary1(): assert isinstance(unary_node.right.operands[0], CASTLiteralValue) assert unary_node.right.operands[0].value == '1' - assert unary_node.right.operands[0].value_type == 'Integer' + assert unary_node.right.operands[0].value_type == ScalarType.INTEGER def test_unary2(): exp_cast = generate_cast(unary2()) @@ -213,7 +214,7 @@ def test_unary2(): assert isinstance(unary_node.right, CASTLiteralValue) assert unary_node.right.value == '1' - assert unary_node.right.value_type == 'Integer' + assert unary_node.right.value_type == ScalarType.INTEGER unary_node = exp_cast.nodes[0].body[1] diff --git a/skema/program_analysis/CAST/fortran/tests/test_while_cast_fortran.py b/skema/program_analysis/CAST/fortran/tests/test_while_cast_fortran.py index 7cafe0caf58..cdfc8364e95 100644 --- a/skema/program_analysis/CAST/fortran/tests/test_while_cast_fortran.py +++ b/skema/program_analysis/CAST/fortran/tests/test_while_cast_fortran.py @@ -11,7 +11,8 @@ CASTLiteralValue, ModelIf, Loop, - Operator + Operator, + ScalarType ) def while1(): @@ -56,7 +57,7 @@ def test_while1(): assert asg_node.left.val.name == "x" assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '2' assert isinstance(loop_node, Loop) @@ -70,7 +71,7 @@ def test_while1(): assert loop_test.operands[0].name == "x" assert isinstance(loop_test.operands[1], CASTLiteralValue) - assert loop_test.operands[1].value_type == "Integer" + assert loop_test.operands[1].value_type == ScalarType.INTEGER assert loop_test.operands[1].value == "5" # Loop Body @@ -99,7 +100,7 @@ def test_while2(): assert asg_node.left.val.name == "x" assert isinstance(asg_node.right, CASTLiteralValue) - assert asg_node.right.value_type == "Integer" + assert asg_node.right.value_type == ScalarType.INTEGER assert asg_node.right.value == '2' assert isinstance(asg_node_2, Assignment) @@ -108,7 +109,7 @@ def test_while2(): assert asg_node_2.left.val.name == "y" assert isinstance(asg_node_2.right, CASTLiteralValue) - assert asg_node_2.right.value_type == "Integer" + assert asg_node_2.right.value_type == ScalarType.INTEGER assert asg_node_2.right.value == '3' assert isinstance(loop_node, Loop) @@ -122,7 +123,7 @@ def test_while2(): assert loop_test.operands[0].name == "x" assert isinstance(loop_test.operands[1], CASTLiteralValue) - assert loop_test.operands[1].value_type == "Integer" + assert loop_test.operands[1].value_type == ScalarType.INTEGER assert loop_test.operands[1].value == "5" # Loop Body diff --git a/skema/program_analysis/model_coverage_report/base.html b/skema/program_analysis/model_coverage_report/base.html index ad0189d2391..a997aa466ad 100644 --- a/skema/program_analysis/model_coverage_report/base.html +++ b/skema/program_analysis/model_coverage_report/base.html @@ -1,8 +1,8 @@
- - + +Note: AMR in this report is generated without the assistance of an LLM. Results may be less accurate.
+