Skip to content

Commit

Permalink
Merge pull request #32 from AgriculturalModelExchangeInitiative/master
Browse files Browse the repository at this point in the history
update newb
  • Loading branch information
cyrillemidingoyi authored Oct 27, 2024
2 parents f51b6c3 + 5527c9e commit 7c01d70
Show file tree
Hide file tree
Showing 18 changed files with 221 additions and 98 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ nosetests.xml

# Jupyter
.ipynb_checkpoints

# VS Code
.vscode
2 changes: 1 addition & 1 deletion conda/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ requirements:
run:
- python {{PY_VER}}
- antlr4-python3-runtime ==4.8
- cython
- cython ==0.29.21
- xmlformatter
- path
- numpy ==1.16.6
Expand Down
26 changes: 15 additions & 11 deletions src/pycropml/cyml.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@author: midingoy
"""
import os
from os.path import isdir
from path import Path
import pycropml
from pycropml.transpiler.main import Main
Expand Down Expand Up @@ -72,31 +73,31 @@ def transpile_package(package, language):
dir_doc = Path(os.path.join(pkg, 'doc'))

# Generate packages if the directories does not exists.
if not output.isdir():
if not isdir(output):
output.mkdir()
if not dir_test.isdir():
if not isdir(dir_test):
dir_test.mkdir()
if not dir_doc.isdir():
if not isdir(dir_doc):
dir_doc.mkdir()

dir_images = Path(os.path.join(dir_doc, 'images'))
if not dir_images.isdir():
if not isdir(dir_images):
dir_images.mkdir()

m2p = render_cyml.Model2Package(models, dir=output)
m2p.generate_package() # generate cyml models in "pyx" directory
tg_rep1 = Path(os.path.join(output, language)) # target language models directory in output
dir_test_lang = Path(os.path.join(dir_test, language))

if not tg_rep1.isdir():
if not isdir(tg_rep1):
tg_rep1.mkdir()

namep_ = namep.replace("-", "_")
tg_rep = Path(os.path.join(tg_rep1, namep_))
if not tg_rep.isdir():
if not isdir(tg_rep):
tg_rep.mkdir()

if not dir_test_lang.isdir(): #Create if it doesn't exist
if not isdir(dir_test_lang): #Create if it doesn't exist
dir_test_lang.mkdir()

m2p.write_tests()
Expand Down Expand Up @@ -154,7 +155,7 @@ def transpile_package(package, language):

# create computing algorithm
if language == "py":
simulation = PythonSimulation(T.model)
simulation = PythonSimulation(T.model, package_name=namep)
simulation.generate()
code = ''.join(simulation.result)
filename = Path(os.path.join(tg_rep, "simulation.py"))
Expand All @@ -163,10 +164,13 @@ def transpile_package(package, language):
tg_file.write(code.encode("utf-8"))
with open(initfile, "wb") as tg_file:
tg_file.write("".encode("utf-8"))
setup = PythonSimulation(T.model)
setup.generate_setup()

setup = PythonSimulation(T.model, package_name=namep)
#setup.generate_setup()
setup.generate_pyproject()
code = ''.join(setup.result)
setupfile = Path(os.path.join(tg_rep1, "setup.py"))
#setupfile = Path(os.path.join(tg_rep1, "setup.py"))
setupfile = Path(os.path.join(tg_rep1, "pyproject.toml"))
with open(setupfile, "wb") as tg_file:
tg_file.write(code.encode("utf-8"))

Expand Down
40 changes: 21 additions & 19 deletions src/pycropml/render_cyml.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
"""
from __future__ import print_function
from __future__ import absolute_import
from path import Path
from datetime import datetime
import os.path
from pycropml.modelunit import ModelUnit
from os.path import isdir
import sys
from path import Path
import six
import shutil
from datetime import datetime
from pycropml.modelunit import ModelUnit
from . import error
import sys
from . import split_function

DATATYPE = {}
DATATYPE['INT'] = "int"
Expand Down Expand Up @@ -63,12 +65,13 @@ def generate_package(self):
# Create a directory (mymodel)

directory = Path(os.path.join(self.cwd, 'pyx'))
if directory.isdir():
if isdir(directory):
self.dir = directory
else:
self.dir = directory.mkdir()

files = []

count = 0
for model in self.models:
self.generate_component(model)
Expand All @@ -83,10 +86,13 @@ def generate_package(self):

def generate_component(self, model_unit):
"""Todo"""

functions = []
if model_unit.modelid.split(".")[0] != "function":
func_name = f"model_{signature(model_unit)}"
else:
func_name = signature(model_unit)

types = [inp.datatype for inp in model_unit.inputs] + [out.datatype for out in model_unit.outputs]
self.code = "import numpy\n"
self.code += "from math import *\n"
Expand All @@ -98,19 +104,15 @@ def generate_component(self, model_unit):

self.code += self.generate_function_signature(func_name, model_unit.inputs) + "\n"
self.code += self.generate_function_doc(model_unit) + "\n"
if sys.version_info[0] >= 3:
self.code += self.generate_algorithm(model_unit) + "\n"
else:
self.code += self.generate_algorithm(model_unit).decode("utf-8") + "\n"

if model_unit.function:
for function in model_unit.function:
if function.language in ("Cyml", "cyml"):
filefunc = Path(os.path.join(model_unit.path, "crop2ml", function.filename))
with open(filefunc.encode('utf-8'), 'r') as f:
source = f.read()
self.code += source
self.code += "\n\n\n"
self.code += self.generate_algorithm(model_unit) + "\n"

if model_unit.function:
function_files = [Path(os.path.join(model_unit.path, "crop2ml", function.filename))
for function in model_unit.function if function.language.lower() == "cyml"]

content = split_function.unique_functions(function_files)
self.code += content
self.code += "\n"

return self.code

Expand Down Expand Up @@ -335,7 +337,7 @@ def write_tests(self):
TODO: Manage several models rather than just one.
"""
self.rep = Path(os.path.join(self.rep, 'test', 'pyx'))
if not self.rep.isdir():
if not isdir(self.rep):
self.rep.mkdir()
files = []
count = 0
Expand Down
6 changes: 4 additions & 2 deletions src/pycropml/render_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
"""
from __future__ import print_function
from __future__ import absolute_import
import six
import os
from os.path import isdir
from path import Path

# The package used to generate Notebook
import nbformat as nbf

from . import render_python as rp
import six



Expand Down Expand Up @@ -48,7 +50,7 @@ def generate_notebook(self):
# Create a directory (mymodel)
cwd = Path(self.dir)
directory=cwd/'python_notebook'
if (directory).isdir() :
if isdir(directory):
_dir = directory
else:
_dir = directory.mkdir()
Expand Down
4 changes: 3 additions & 1 deletion src/pycropml/render_notebook_csharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"""
from __future__ import print_function
from __future__ import absolute_import
import os
from os.path import isdir
from path import Path

# The package used to generate Notebook
Expand Down Expand Up @@ -51,7 +53,7 @@ def generate_notebook(self):
# Create a directory (mymodel)
cwd = Path(self.dir)
directory=cwd/'csharp_notebook'
if (directory).isdir() :
if isdir(directory):
_dir = directory
else:
_dir = directory.mkdir()
Expand Down
4 changes: 3 additions & 1 deletion src/pycropml/render_notebook_java.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"""
from __future__ import print_function
from __future__ import absolute_import
import os
from os.path import isdir
from path import Path

# The package used to generate Notebook
Expand Down Expand Up @@ -48,7 +50,7 @@ def generate_notebook(self):
# Create a directory (mymodel)
cwd = Path(self.dir)
directory=cwd/'java_notebook'
if (directory).isdir() :
if isdir(directory):
_dir = directory
else:
_dir = directory.mkdir()
Expand Down
12 changes: 7 additions & 5 deletions src/pycropml/render_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
"""
from __future__ import print_function
from __future__ import absolute_import
from path import Path
import numpy
from datetime import datetime
import os.path
from os.path import isdir
import six
from datetime import datetime
from path import Path
import numpy

try:
from openalea.core import interface as inter
Expand Down Expand Up @@ -78,7 +79,7 @@ def generate_package(self):
# Create a directory (mymodel)
cwd = Path(self.dir)
directory=cwd/'python_model'
if (directory).isdir() :
if isdir(directory):
self.dir = directory
else:
self.dir = directory.mkdir()
Expand Down Expand Up @@ -458,7 +459,8 @@ def generate_doc(model):
Institution: %s
ExtendedDescription: %s
ShortDescription: %s
""" %(desc.Title, "-Version: " + model.version + " -Time step: " + model.timestep, desc.Authors, desc.Reference, desc.Institution, desc.ExtendedDescription, desc.ShortDescription)
""" %(desc.Title, "-Version: " + model.version + " -Time step: " + model.timestep,
desc.Authors, desc.Reference, desc.Institution, desc.ExtendedDescription, desc.ShortDescription)

code = '\n'
code += _doc
Expand Down
73 changes: 73 additions & 0 deletions src/pycropml/split_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
""" Merge files into one file with unique functions.
Render a set of pyx files containing the same function several into one file containing one and only one function of each name.
"""
import re

def function_names(code):
# Regular expression pattern to match function names
# It assumes functions start with 'def' or 'cpdef'
pattern = r'\b(?:def|cpdef)\s+([a-zA-Z_]\w*)\s*\('

# Find all function names using regex
function_names = re.findall(pattern, code)

# Remove duplicates by converting to a set
unique_function_names = list(function_names)

return unique_function_names

# Define a function to retrieve the code of a specific function
def get_function_code(content, function_name):
# Regex to capture function definition
function_pattern = rf'(def|cpdef)\s+{function_name}\s*\((?:[^()]*(?:\([^()]*\))?)*\)\s*:[\s\S]*?'

# Position of the function
match = re.search(function_pattern, content, re.MULTILINE)

if not match:
return ''

start = match.start()
lines = content[start:].splitlines()
function_lines = []

# Iter on the next lines from the function
# First line is the function definition
count = 0
for line in lines:
if (line.startswith('def ') or line.startswith('cpdef ')) and count != 0:
# Stop after the first line begining with def without indent
break
function_lines.append(line)
count +=1

function_lines.append('')
return '\n'.join(function_lines)



def unique_functions(files):
unique_functions = []

codes = []
for fn in files:
with open(fn.encode('utf-8'), 'r') as file:
content = file.read()

funs = function_names(content)
for fun in funs:
if fun in unique_functions:
print(f'{fun} is duplicated')
else:
unique_functions.append(fun)
function_code = get_function_code(content, fun)
#print(function_code)
codes.append(function_code)

content = '\n'.join(codes)

return content


20 changes: 12 additions & 8 deletions src/pycropml/transpiler/antlr_py/bioma/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@

from __future__ import absolute_import
from __future__ import print_function
from path import Path
import os
from os.path import isdir
from copy import deepcopy
from typing import *
from path import Path

import networkx as nx
import itertools

from pycropml.transpiler.antlr_py.to_CASG import to_dictASG, to_CASG
from pycropml.transpiler.antlr_py.bioma.biomaExtraction import BiomaExtraction
from pycropml.transpiler.pseudo_tree import Node
Expand All @@ -13,8 +20,6 @@
from pycropml.transpiler.antlr_py.generateCyml import writeCyml
from pycropml.transpiler.antlr_py.createXml import Pl2Crop2ml
from pycropml.transpiler.antlr_py import repowalk
from copy import deepcopy
from typing import *

from pycropml.transpiler.antlr_py.csharp.csharp_preprocessing import ExprStatNode, TransformLocal, CheckingInOut, Custom_call, Declarations,Assignment, Member_access, Binary_op, Index, Local
from pycropml.transpiler.antlr_py.codeExtraction import extraction
Expand Down Expand Up @@ -58,19 +63,18 @@

def create_package(output):
crop2ml_rep = Path(os.path.join(output, 'crop2ml'))
if not crop2ml_rep.isdir():
if not isdir(crop2ml_rep):
crop2ml_rep.mkdir()
algo_rep = Path(os.path.join(crop2ml_rep, 'algo'))
if not algo_rep.isdir():
if not isdir(algo_rep):
algo_rep.mkdir()
cyml_rep = Path(os.path.join(algo_rep, 'pyx'))
if not cyml_rep.isdir():
if not isdir(cyml_rep):
cyml_rep.mkdir()
return crop2ml_rep, cyml_rep


import networkx as nx
import itertools


def function_dependency(st, f):
r = [f]
Expand Down
Loading

0 comments on commit 7c01d70

Please sign in to comment.