Skip to content

Commit

Permalink
[code2fn] Various bug fixes and documentation updates (#878)
Browse files Browse the repository at this point in the history
## Summary of Changes
- Adds unit testing for Fortran compound-conditional
- Adds missing files for consumer mode model coverage reports
- Fixes circular dependency issue between model coverage reports and
img2mml
- Pins code2fn related libraries in pyproject.toml
- Pins all tree-sitter grammar versions to prevent a breaking change in
the future.

### Related issues

Resolves #663
Resolves #876
  • Loading branch information
vincentraymond-ua authored Apr 19, 2024
1 parent 67506c1 commit 482b768
Show file tree
Hide file tree
Showing 15 changed files with 363 additions and 128 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests-and-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ jobs:
# retrieve latest model for img2mml component
curl -L https://artifacts.askem.lum.ai/skema/img2mml/models/cnn_xfmer_arxiv_im2mml_with_fonts_boldface_best.pt > skema/img2mml/trained_models/cnn_xfmer_arxiv_im2mml_with_fonts_boldface_best.pt
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)"
Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ 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",
"httpx",
"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.
Expand Down Expand Up @@ -110,7 +110,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"}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
Name,
CASTLiteralValue,
ModelIf,
Operator
Operator,
ScalarType
)

def cond1():
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand All @@ -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)
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
Assignment,
Var,
Name,
CASTLiteralValue
CASTLiteralValue,
ScalarType
)

def exp0():
Expand Down Expand Up @@ -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'


Expand All @@ -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'

# ------
Expand All @@ -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__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
CASTLiteralValue,
ModelIf,
Loop,
Operator
Operator,
ScalarType,
StructureType
)

def for1():
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
CASTLiteralValue,
ModelIf,
Loop,
Operator
Operator,
ScalarType
)

def identifier1():
Expand Down Expand Up @@ -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'

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
Var,
Name,
Operator,
CASTLiteralValue
CASTLiteralValue,
ScalarType
)

def binop1():
Expand Down Expand Up @@ -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())
Expand All @@ -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'

# ------
Expand All @@ -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())
Expand All @@ -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'

# ------
Expand All @@ -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'

# ------
Expand Down Expand Up @@ -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())
Expand All @@ -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]

Expand Down
Loading

0 comments on commit 482b768

Please sign in to comment.