Skip to content

Commit 2926cca

Browse files
authored
Changes to FmuBuilder.build_FMU. 1. Unload the script module after th… (#247)
* Changes to FmuBuilder.build_FMU. 1. Unload the script module after the FMU is built to avoid that the cached script is used when using the FMU 2. Optionally allow non-default names for the resulting FMU file 3. Check that the script file is not among the project files 4. Add a documentation text to the function. * Review of logic to decide if 'dest' is a file name
1 parent 3e97227 commit 2926cca

1 file changed

Lines changed: 24 additions & 4 deletions

File tree

pythonfmu/builder.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ def get_model_description(filepath: Path, module_name: str, class_name: str) ->
189189
# Produce the xml
190190
return instance.modelName, instance.to_xml()
191191

192-
193192
class FmuBuilder:
194193

195194
@staticmethod
@@ -201,13 +200,31 @@ def build_FMU(
201200
newargs: dict | None = None,
202201
**options,
203202
) -> Path:
203+
""" Build the FMU from the Python script, additional project files and documentatiion.
204+
205+
Args:
206+
script_file (FilePath): The main Python script containing the Python model class
207+
dest (FilePath)='.': Optional destination path.
208+
If this is a full file name with '.fmu' extension, it is used as FMU file name.
209+
Otherwise the FMU file name is constructed automatically from the script file name.
210+
project_files (Iterable[FilePath]): Optional list/tuple of additional project files needed to run model
211+
documentation_folder (FilePath): Optional additional documentation (beyond modelDescription)
212+
newargs (dict): Optional dict of replacements of model class __init__() arguments.
213+
"""
204214
script_file = Path(script_file)
205215
if not script_file.exists():
206216
raise ValueError(f"No such file {script_file!s}")
207217
if not script_file.suffix.endswith(".py"):
208218
raise ValueError(f"File {script_file!s} must have extension '.py'!")
209-
219+
210220
dest = Path(dest)
221+
if ( dest.suffix == '.fmu' and # explicit FMU file name shall always have suffix '.fmu'
222+
( dest.is_file() or # Note that .is_file() returns False if the file does not yet exist
223+
not dest.is_dir())): # if dest represents an (existing) directory we cannot interpret as file!
224+
dest_file = dest
225+
dest = dest.parent
226+
else:
227+
dest_file = "" # FMU file name is automatically generated below
211228
if not dest.exists():
212229
dest.mkdir(parents=True)
213230
project_files = set(map(Path, project_files))
@@ -261,13 +278,14 @@ def build_FMU(
261278
temp_dest = temp_dir / file_.name
262279
shutil.copytree(file_, temp_dest)
263280
else:
281+
assert file_.name != script_file.name, ( # avoid the inclusion of the script in project files
282+
"It seems that the script file is included a second time in the project_files")
264283
shutil.copy2(file_, temp_dir)
265284

266285
model_identifier, xml = get_model_description(
267286
temp_dir.absolute() / script_file.name, module_name, model_class.__name__
268287
)
269-
270-
dest_file = dest / f"{model_identifier}.fmu"
288+
dest_file = dest / f"{model_identifier}.fmu" if dest_file == "" else dest_file
271289

272290
type_node = xml.find("CoSimulation")
273291
option_names = [opt.name for opt in FMI2_MODEL_OPTIONS]
@@ -317,6 +335,8 @@ def build_FMU(
317335
zip_fmu.writestr(
318336
"modelDescription.xml", xml_str.toprettyxml(encoding="UTF-8")
319337
)
338+
if newargs is not None:
339+
sys.modules.pop(Path(script_file).stem) # otherwise old script may be active when loading the FMU!
320340

321341
return dest_file
322342

0 commit comments

Comments
 (0)