Skip to content

Commit 5527c9e

Browse files
authored
Merge pull request #252 from AgriculturalModelExchangeInitiative/issue251
Remove duplicated functions in pyx
2 parents 488a7b0 + 9584db1 commit 5527c9e

File tree

2 files changed

+87
-13
lines changed

2 files changed

+87
-13
lines changed

src/pycropml/render_cyml.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from datetime import datetime
1515
from pycropml.modelunit import ModelUnit
1616
from . import error
17+
from . import split_function
1718

1819
DATATYPE = {}
1920
DATATYPE['INT'] = "int"
@@ -70,6 +71,7 @@ def generate_package(self):
7071
self.dir = directory.mkdir()
7172

7273
files = []
74+
7375
count = 0
7476
for model in self.models:
7577
self.generate_component(model)
@@ -84,10 +86,13 @@ def generate_package(self):
8486

8587
def generate_component(self, model_unit):
8688
"""Todo"""
89+
90+
functions = []
8791
if model_unit.modelid.split(".")[0] != "function":
8892
func_name = f"model_{signature(model_unit)}"
8993
else:
9094
func_name = signature(model_unit)
95+
9196
types = [inp.datatype for inp in model_unit.inputs] + [out.datatype for out in model_unit.outputs]
9297
self.code = "import numpy\n"
9398
self.code += "from math import *\n"
@@ -99,19 +104,15 @@ def generate_component(self, model_unit):
99104

100105
self.code += self.generate_function_signature(func_name, model_unit.inputs) + "\n"
101106
self.code += self.generate_function_doc(model_unit) + "\n"
102-
if sys.version_info[0] >= 3:
103-
self.code += self.generate_algorithm(model_unit) + "\n"
104-
else:
105-
self.code += self.generate_algorithm(model_unit).decode("utf-8") + "\n"
106-
107-
if model_unit.function:
108-
for function in model_unit.function:
109-
if function.language in ("Cyml", "cyml"):
110-
filefunc = Path(os.path.join(model_unit.path, "crop2ml", function.filename))
111-
with open(filefunc.encode('utf-8'), 'r') as f:
112-
source = f.read()
113-
self.code += source
114-
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"
115116

116117
return self.code
117118

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+

0 commit comments

Comments
 (0)