Skip to content

Commit 7c01d70

Browse files
Merge pull request #32 from AgriculturalModelExchangeInitiative/master
update newb
2 parents f51b6c3 + 5527c9e commit 7c01d70

18 files changed

+221
-98
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,6 @@ nosetests.xml
7171

7272
# Jupyter
7373
.ipynb_checkpoints
74+
75+
# VS Code
76+
.vscode

conda/meta.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ requirements:
2222
run:
2323
- python {{PY_VER}}
2424
- antlr4-python3-runtime ==4.8
25-
- cython
25+
- cython ==0.29.21
2626
- xmlformatter
2727
- path
2828
- numpy ==1.16.6

src/pycropml/cyml.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
@author: midingoy
66
"""
77
import os
8+
from os.path import isdir
89
from path import Path
910
import pycropml
1011
from pycropml.transpiler.main import Main
@@ -72,31 +73,31 @@ def transpile_package(package, language):
7273
dir_doc = Path(os.path.join(pkg, 'doc'))
7374

7475
# Generate packages if the directories does not exists.
75-
if not output.isdir():
76+
if not isdir(output):
7677
output.mkdir()
77-
if not dir_test.isdir():
78+
if not isdir(dir_test):
7879
dir_test.mkdir()
79-
if not dir_doc.isdir():
80+
if not isdir(dir_doc):
8081
dir_doc.mkdir()
8182

8283
dir_images = Path(os.path.join(dir_doc, 'images'))
83-
if not dir_images.isdir():
84+
if not isdir(dir_images):
8485
dir_images.mkdir()
8586

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

91-
if not tg_rep1.isdir():
92+
if not isdir(tg_rep1):
9293
tg_rep1.mkdir()
9394

9495
namep_ = namep.replace("-", "_")
9596
tg_rep = Path(os.path.join(tg_rep1, namep_))
96-
if not tg_rep.isdir():
97+
if not isdir(tg_rep):
9798
tg_rep.mkdir()
9899

99-
if not dir_test_lang.isdir(): #Create if it doesn't exist
100+
if not isdir(dir_test_lang): #Create if it doesn't exist
100101
dir_test_lang.mkdir()
101102

102103
m2p.write_tests()
@@ -154,7 +155,7 @@ def transpile_package(package, language):
154155

155156
# create computing algorithm
156157
if language == "py":
157-
simulation = PythonSimulation(T.model)
158+
simulation = PythonSimulation(T.model, package_name=namep)
158159
simulation.generate()
159160
code = ''.join(simulation.result)
160161
filename = Path(os.path.join(tg_rep, "simulation.py"))
@@ -163,10 +164,13 @@ def transpile_package(package, language):
163164
tg_file.write(code.encode("utf-8"))
164165
with open(initfile, "wb") as tg_file:
165166
tg_file.write("".encode("utf-8"))
166-
setup = PythonSimulation(T.model)
167-
setup.generate_setup()
167+
168+
setup = PythonSimulation(T.model, package_name=namep)
169+
#setup.generate_setup()
170+
setup.generate_pyproject()
168171
code = ''.join(setup.result)
169-
setupfile = Path(os.path.join(tg_rep1, "setup.py"))
172+
#setupfile = Path(os.path.join(tg_rep1, "setup.py"))
173+
setupfile = Path(os.path.join(tg_rep1, "pyproject.toml"))
170174
with open(setupfile, "wb") as tg_file:
171175
tg_file.write(code.encode("utf-8"))
172176

src/pycropml/render_cyml.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55
"""
66
from __future__ import print_function
77
from __future__ import absolute_import
8-
from path import Path
9-
from datetime import datetime
108
import os.path
11-
from pycropml.modelunit import ModelUnit
9+
from os.path import isdir
10+
import sys
11+
from path import Path
1212
import six
1313
import shutil
14+
from datetime import datetime
15+
from pycropml.modelunit import ModelUnit
1416
from . import error
15-
import sys
17+
from . import split_function
1618

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

6567
directory = Path(os.path.join(self.cwd, 'pyx'))
66-
if directory.isdir():
68+
if isdir(directory):
6769
self.dir = directory
6870
else:
6971
self.dir = directory.mkdir()
7072

7173
files = []
74+
7275
count = 0
7376
for model in self.models:
7477
self.generate_component(model)
@@ -83,10 +86,13 @@ def generate_package(self):
8386

8487
def generate_component(self, model_unit):
8588
"""Todo"""
89+
90+
functions = []
8691
if model_unit.modelid.split(".")[0] != "function":
8792
func_name = f"model_{signature(model_unit)}"
8893
else:
8994
func_name = signature(model_unit)
95+
9096
types = [inp.datatype for inp in model_unit.inputs] + [out.datatype for out in model_unit.outputs]
9197
self.code = "import numpy\n"
9298
self.code += "from math import *\n"
@@ -98,19 +104,15 @@ def generate_component(self, model_unit):
98104

99105
self.code += self.generate_function_signature(func_name, model_unit.inputs) + "\n"
100106
self.code += self.generate_function_doc(model_unit) + "\n"
101-
if sys.version_info[0] >= 3:
102-
self.code += self.generate_algorithm(model_unit) + "\n"
103-
else:
104-
self.code += self.generate_algorithm(model_unit).decode("utf-8") + "\n"
105-
106-
if model_unit.function:
107-
for function in model_unit.function:
108-
if function.language in ("Cyml", "cyml"):
109-
filefunc = Path(os.path.join(model_unit.path, "crop2ml", function.filename))
110-
with open(filefunc.encode('utf-8'), 'r') as f:
111-
source = f.read()
112-
self.code += source
113-
self.code += "\n\n\n"
107+
self.code += self.generate_algorithm(model_unit) + "\n"
108+
109+
if model_unit.function:
110+
function_files = [Path(os.path.join(model_unit.path, "crop2ml", function.filename))
111+
for function in model_unit.function if function.language.lower() == "cyml"]
112+
113+
content = split_function.unique_functions(function_files)
114+
self.code += content
115+
self.code += "\n"
114116

115117
return self.code
116118

@@ -335,7 +337,7 @@ def write_tests(self):
335337
TODO: Manage several models rather than just one.
336338
"""
337339
self.rep = Path(os.path.join(self.rep, 'test', 'pyx'))
338-
if not self.rep.isdir():
340+
if not isdir(self.rep):
339341
self.rep.mkdir()
340342
files = []
341343
count = 0

src/pycropml/render_notebook.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
"""
88
from __future__ import print_function
99
from __future__ import absolute_import
10+
import six
11+
import os
12+
from os.path import isdir
1013
from path import Path
1114

1215
# The package used to generate Notebook
1316
import nbformat as nbf
1417

1518
from . import render_python as rp
16-
import six
1719

1820

1921

@@ -48,7 +50,7 @@ def generate_notebook(self):
4850
# Create a directory (mymodel)
4951
cwd = Path(self.dir)
5052
directory=cwd/'python_notebook'
51-
if (directory).isdir() :
53+
if isdir(directory):
5254
_dir = directory
5355
else:
5456
_dir = directory.mkdir()

src/pycropml/render_notebook_csharp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"""
99
from __future__ import print_function
1010
from __future__ import absolute_import
11+
import os
12+
from os.path import isdir
1113
from path import Path
1214

1315
# The package used to generate Notebook
@@ -51,7 +53,7 @@ def generate_notebook(self):
5153
# Create a directory (mymodel)
5254
cwd = Path(self.dir)
5355
directory=cwd/'csharp_notebook'
54-
if (directory).isdir() :
56+
if isdir(directory):
5557
_dir = directory
5658
else:
5759
_dir = directory.mkdir()

src/pycropml/render_notebook_java.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"""
99
from __future__ import print_function
1010
from __future__ import absolute_import
11+
import os
12+
from os.path import isdir
1113
from path import Path
1214

1315
# The package used to generate Notebook
@@ -48,7 +50,7 @@ def generate_notebook(self):
4850
# Create a directory (mymodel)
4951
cwd = Path(self.dir)
5052
directory=cwd/'java_notebook'
51-
if (directory).isdir() :
53+
if isdir(directory):
5254
_dir = directory
5355
else:
5456
_dir = directory.mkdir()

src/pycropml/render_python.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
"""
99
from __future__ import print_function
1010
from __future__ import absolute_import
11-
from path import Path
12-
import numpy
13-
from datetime import datetime
1411
import os.path
12+
from os.path import isdir
1513
import six
14+
from datetime import datetime
15+
from path import Path
16+
import numpy
1617

1718
try:
1819
from openalea.core import interface as inter
@@ -78,7 +79,7 @@ def generate_package(self):
7879
# Create a directory (mymodel)
7980
cwd = Path(self.dir)
8081
directory=cwd/'python_model'
81-
if (directory).isdir() :
82+
if isdir(directory):
8283
self.dir = directory
8384
else:
8485
self.dir = directory.mkdir()
@@ -458,7 +459,8 @@ def generate_doc(model):
458459
Institution: %s
459460
ExtendedDescription: %s
460461
ShortDescription: %s
461-
""" %(desc.Title, "-Version: " + model.version + " -Time step: " + model.timestep, desc.Authors, desc.Reference, desc.Institution, desc.ExtendedDescription, desc.ShortDescription)
462+
""" %(desc.Title, "-Version: " + model.version + " -Time step: " + model.timestep,
463+
desc.Authors, desc.Reference, desc.Institution, desc.ExtendedDescription, desc.ShortDescription)
462464

463465
code = '\n'
464466
code += _doc

src/pycropml/split_function.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
""" Merge files into one file with unique functions.
2+
3+
Render a set of pyx files containing the same function several into one file containing one and only one function of each name.
4+
5+
"""
6+
import re
7+
8+
def function_names(code):
9+
# Regular expression pattern to match function names
10+
# It assumes functions start with 'def' or 'cpdef'
11+
pattern = r'\b(?:def|cpdef)\s+([a-zA-Z_]\w*)\s*\('
12+
13+
# Find all function names using regex
14+
function_names = re.findall(pattern, code)
15+
16+
# Remove duplicates by converting to a set
17+
unique_function_names = list(function_names)
18+
19+
return unique_function_names
20+
21+
# Define a function to retrieve the code of a specific function
22+
def get_function_code(content, function_name):
23+
# Regex to capture function definition
24+
function_pattern = rf'(def|cpdef)\s+{function_name}\s*\((?:[^()]*(?:\([^()]*\))?)*\)\s*:[\s\S]*?'
25+
26+
# Position of the function
27+
match = re.search(function_pattern, content, re.MULTILINE)
28+
29+
if not match:
30+
return ''
31+
32+
start = match.start()
33+
lines = content[start:].splitlines()
34+
function_lines = []
35+
36+
# Iter on the next lines from the function
37+
# First line is the function definition
38+
count = 0
39+
for line in lines:
40+
if (line.startswith('def ') or line.startswith('cpdef ')) and count != 0:
41+
# Stop after the first line begining with def without indent
42+
break
43+
function_lines.append(line)
44+
count +=1
45+
46+
function_lines.append('')
47+
return '\n'.join(function_lines)
48+
49+
50+
51+
def unique_functions(files):
52+
unique_functions = []
53+
54+
codes = []
55+
for fn in files:
56+
with open(fn.encode('utf-8'), 'r') as file:
57+
content = file.read()
58+
59+
funs = function_names(content)
60+
for fun in funs:
61+
if fun in unique_functions:
62+
print(f'{fun} is duplicated')
63+
else:
64+
unique_functions.append(fun)
65+
function_code = get_function_code(content, fun)
66+
#print(function_code)
67+
codes.append(function_code)
68+
69+
content = '\n'.join(codes)
70+
71+
return content
72+
73+

src/pycropml/transpiler/antlr_py/bioma/run.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@
22

33
from __future__ import absolute_import
44
from __future__ import print_function
5-
from path import Path
65
import os
6+
from os.path import isdir
7+
from copy import deepcopy
8+
from typing import *
9+
from path import Path
10+
11+
import networkx as nx
12+
import itertools
13+
714
from pycropml.transpiler.antlr_py.to_CASG import to_dictASG, to_CASG
815
from pycropml.transpiler.antlr_py.bioma.biomaExtraction import BiomaExtraction
916
from pycropml.transpiler.pseudo_tree import Node
@@ -13,8 +20,6 @@
1320
from pycropml.transpiler.antlr_py.generateCyml import writeCyml
1421
from pycropml.transpiler.antlr_py.createXml import Pl2Crop2ml
1522
from pycropml.transpiler.antlr_py import repowalk
16-
from copy import deepcopy
17-
from typing import *
1823

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

5964
def create_package(output):
6065
crop2ml_rep = Path(os.path.join(output, 'crop2ml'))
61-
if not crop2ml_rep.isdir():
66+
if not isdir(crop2ml_rep):
6267
crop2ml_rep.mkdir()
6368
algo_rep = Path(os.path.join(crop2ml_rep, 'algo'))
64-
if not algo_rep.isdir():
69+
if not isdir(algo_rep):
6570
algo_rep.mkdir()
6671
cyml_rep = Path(os.path.join(algo_rep, 'pyx'))
67-
if not cyml_rep.isdir():
72+
if not isdir(cyml_rep):
6873
cyml_rep.mkdir()
6974
return crop2ml_rep, cyml_rep
7075

7176

72-
import networkx as nx
73-
import itertools
77+
7478

7579
def function_dependency(st, f):
7680
r = [f]

0 commit comments

Comments
 (0)