pythonfmu3 0.3.2__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. {pythonfmu3-0.3.2/pythonfmu3.egg-info → pythonfmu3-0.3.3}/PKG-INFO +2 -1
  2. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/README.md +1 -0
  3. pythonfmu3-0.3.3/pythonfmu3/_version.py +1 -0
  4. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/builder.py +29 -7
  5. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/fmi3slave.py +20 -9
  6. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll +0 -0
  7. pythonfmu3-0.3.3/pythonfmu3/tests/test_docs.py +98 -0
  8. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3/pythonfmu3.egg-info}/PKG-INFO +2 -1
  9. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3.egg-info/SOURCES.txt +1 -0
  10. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/setup.cfg +1 -0
  11. pythonfmu3-0.3.2/pythonfmu3/_version.py +0 -1
  12. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/LICENSE +0 -0
  13. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/MANIFEST.in +0 -0
  14. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/__init__.py +0 -0
  15. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/__main__.py +0 -0
  16. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/cosimulation.py +0 -0
  17. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/default_experiment.py +0 -0
  18. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/deploy.py +0 -0
  19. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/enums.py +0 -0
  20. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/logmsg.py +0 -0
  21. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/modelexchange.py +0 -0
  22. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/osutil.py +0 -0
  23. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/.clang-format +0 -0
  24. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/CMakeLists.txt +0 -0
  25. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/build_unix.sh +0 -0
  26. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/build_win.sh +0 -0
  27. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/CMakeLists.txt +0 -0
  28. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_common.hpp +0 -0
  29. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp +0 -0
  30. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp +0 -0
  31. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp +0 -0
  32. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/fmi/fmi3FunctionTypes.h +0 -0
  33. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/fmi/fmi3Functions.h +0 -0
  34. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/fmi/fmi3PlatformTypes.h +0 -0
  35. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/pythonfmu/IPyState.hpp +0 -0
  36. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp +0 -0
  37. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp +0 -0
  38. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/pythonfmu-export/src/pythonfmu/PyState.hpp +0 -0
  39. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so +0 -0
  40. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/__init__.py +0 -0
  41. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/conftest.py +0 -0
  42. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/data/csvdemo.csv +0 -0
  43. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/data/hello.txt +0 -0
  44. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/slaves/PythonSlaveWithException.py +0 -0
  45. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/slaves/localmodule.py +0 -0
  46. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/slaves/pythonslave.py +0 -0
  47. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/slaves/pythonslaveMX.py +0 -0
  48. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/slaves/pythonslaveMXCS.py +0 -0
  49. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/slaves/pythonslave_read_file.py +0 -0
  50. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/slaves/slavewithdep.py +0 -0
  51. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/test_builder.py +0 -0
  52. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/test_deploy.py +0 -0
  53. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/test_fmi3slave.py +0 -0
  54. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/test_integration.py +0 -0
  55. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/test_logger.py +0 -0
  56. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/test_multiple_fmus.py +0 -0
  57. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/test_variables.py +0 -0
  58. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/tests/utils.py +0 -0
  59. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/unit.py +0 -0
  60. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/variable_types.py +0 -0
  61. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3/variables.py +0 -0
  62. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3.egg-info/dependency_links.txt +0 -0
  63. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3.egg-info/entry_points.txt +0 -0
  64. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3.egg-info/not-zip-safe +0 -0
  65. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3.egg-info/requires.txt +0 -0
  66. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/pythonfmu3.egg-info/top_level.txt +0 -0
  67. {pythonfmu3-0.3.2 → pythonfmu3-0.3.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonfmu3
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: A lightweight framework that enables the packaging of Python3.x code as co-simulation FMUs.
5
5
  Home-page: https://github.com/stephensmith25/PythonFMU3
6
6
  Author: Stephen Smith
@@ -173,6 +173,7 @@ To create a model exchange FMU you must inherit from `Fmi3SlaveBase` and one of
173
173
  ```python
174
174
 
175
175
  from pythonfmu3 import Fmi3Causality, Fmi3SlaveBase, Float64, ModelExchange
176
+ from typing import List
176
177
 
177
178
 
178
179
  class PythonSlaveMX(Fmi3SlaveBase, ModelExchange):
@@ -146,6 +146,7 @@ To create a model exchange FMU you must inherit from `Fmi3SlaveBase` and one of
146
146
  ```python
147
147
 
148
148
  from pythonfmu3 import Fmi3Causality, Fmi3SlaveBase, Float64, ModelExchange
149
+ from typing import List
149
150
 
150
151
 
151
152
  class PythonSlaveMX(Fmi3SlaveBase, ModelExchange):
@@ -0,0 +1 @@
1
+ __version__ = "0.3.3"
@@ -13,7 +13,7 @@ from typing import Iterable, Optional, Tuple, Union
13
13
  from xml.dom.minidom import parseString
14
14
  from xml.etree.ElementTree import Element, SubElement, tostring
15
15
  from .osutil import get_lib_extension, get_platform
16
- from .fmi3slave import FMI3_MODEL_OPTIONS, Fmi3Slave, Fmi3SlaveBase
16
+ from .fmi3slave import FMI3_MODEL_OPTIONS_COMMON, FMI3_MODEL_OPTIONS_COSIM, FMI3_MODEL_OPTIONS_MX, Fmi3Slave, Fmi3SlaveBase
17
17
 
18
18
  FilePath = Union[str, Path]
19
19
  HERE = Path(__file__).parent
@@ -137,16 +137,20 @@ class FmuBuilder:
137
137
  dest_file = dest / f"{model_identifier}.fmu"
138
138
 
139
139
  type_node = xml.find("CoSimulation")
140
- option_names = [opt.name for opt in FMI3_MODEL_OPTIONS]
141
- if type_node:
140
+ option_names = [opt.name for opt in FMI3_MODEL_OPTIONS_COMMON]
141
+ cosim_option_names = option_names.copy()
142
+ cosim_option_names.extend(opt.name for opt in FMI3_MODEL_OPTIONS_COSIM)
143
+ if type_node is not None:
142
144
  for option, value in options.items():
143
- if option in option_names:
145
+ if option in cosim_option_names:
144
146
  type_node.set(option, str(value).lower())
145
147
 
146
148
  type_node = xml.find("ModelExchange")
147
- if type_node:
149
+ mx_option_names = option_names.copy()
150
+ mx_option_names.extend(opt.name for opt in FMI3_MODEL_OPTIONS_MX)
151
+ if type_node is not None:
148
152
  for option, value in options.items():
149
- if option in option_names:
153
+ if option in mx_option_names:
150
154
  type_node.set(option, str(value).lower())
151
155
 
152
156
  with zipfile.ZipFile(dest_file, "w") as zip_fmu:
@@ -247,7 +251,25 @@ def create_command_parser(parser: argparse.ArgumentParser):
247
251
  default=None
248
252
  )
249
253
 
250
- for option in FMI3_MODEL_OPTIONS:
254
+ for option in FMI3_MODEL_OPTIONS_COMMON:
255
+ action = "store_false" if option.value else "store_true"
256
+ parser.add_argument(
257
+ f"--{option.cli}",
258
+ dest=option.name,
259
+ help=f"If given, {option.name}={action[6:]}",
260
+ action=action
261
+ )
262
+
263
+ for option in FMI3_MODEL_OPTIONS_COSIM:
264
+ action = "store_false" if option.value else "store_true"
265
+ parser.add_argument(
266
+ f"--{option.cli}",
267
+ dest=option.name,
268
+ help=f"If given, {option.name}={action[6:]}",
269
+ action=action
270
+ )
271
+
272
+ for option in FMI3_MODEL_OPTIONS_MX:
251
273
  action = "store_false" if option.value else "store_true"
252
274
  parser.add_argument(
253
275
  f"--{option.cli}",
@@ -21,14 +21,22 @@ from .unit import Unit
21
21
 
22
22
  ModelOptions = namedtuple("ModelOptions", ["name", "value", "cli"])
23
23
 
24
- FMI3_MODEL_OPTIONS: List[ModelOptions] = [
24
+ FMI3_MODEL_OPTIONS_COMMON: List[ModelOptions] = [
25
25
  ModelOptions("needsExecutionTool", True, "no-external-tool"),
26
- ModelOptions("canHandleVariableCommunicationStepSize", True, "no-variable-step"),
27
26
  ModelOptions("canBeInstantiatedOnlyOncePerProcess", False, "only-one-per-process"),
28
27
  ModelOptions("canGetAndSetFMUState", False, "handle-state"),
29
28
  ModelOptions("canSerializeFMUState", False, "serialize-state")
30
29
  ]
31
30
 
31
+ FMI3_MODEL_OPTIONS_COSIM: List[ModelOptions] = [
32
+ ModelOptions("canHandleVariableCommunicationStepSize", True, "no-variable-step"),
33
+ ]
34
+
35
+ FMI3_MODEL_OPTIONS_MX: List[ModelOptions] = [
36
+ ModelOptions("needsCompletedIntegratorStep", False, "needs-completed-step"),
37
+ ]
38
+
39
+
32
40
  class Fmi3StepResult(NamedTuple):
33
41
  status: Fmi3Status = Fmi3Status.ok
34
42
  eventHandlingNeeded: bool = False
@@ -103,23 +111,26 @@ class Fmi3SlaveBase(object):
103
111
  root = Element("fmiModelDescription", attrib)
104
112
 
105
113
  options = dict()
106
- for option in FMI3_MODEL_OPTIONS:
114
+ for option in FMI3_MODEL_OPTIONS_COMMON:
107
115
  value = model_options.get(option.name, option.value)
108
116
  options[option.name] = str(value).lower()
117
+
109
118
  options["modelIdentifier"] = self.modelName
110
- options["canNotUseMemoryManagementFunctions"] = "true"
119
+
120
+ options_cs = options.copy()
121
+ for option in FMI3_MODEL_OPTIONS_COSIM:
122
+ options_cs[option.name] = str(value).lower()
111
123
 
112
- options_me = dict()
113
- options_me["canGetAndSetFMUState"] = "true"
114
- options_me["modelIdentifier"] = self.modelName
115
- options_me["needsCompletedIntegratorStep"] = "false"
124
+ options_me = options.copy()
125
+ for option in FMI3_MODEL_OPTIONS_MX:
126
+ options_me[option.name] = str(value).lower()
116
127
 
117
128
  # check if we have cosim mixin or model exchange mixin
118
129
  if isinstance(self, ModelExchange):
119
130
  SubElement(root, "ModelExchange", attrib=options_me)
120
131
 
121
132
  if isinstance(self, CoSimulation):
122
- SubElement(root, "CoSimulation", attrib=options)
133
+ SubElement(root, "CoSimulation", attrib=options_cs)
123
134
 
124
135
  if self.units:
125
136
  unit_defs = SubElement(root, "UnitDefinitions")
@@ -0,0 +1,98 @@
1
+ import pytest
2
+ import pathlib
3
+ import re
4
+ import tempfile
5
+
6
+ def extract_python_code_from_md(md_file):
7
+ """Extract Python code blocks from markdown, excluding skip blocks"""
8
+ content = pathlib.Path(md_file).read_text()
9
+
10
+ # Find all python code blocks that aren't marked as skip
11
+ python_blocks = []
12
+
13
+ # Pattern to match python blocks but not python skip
14
+ pattern = r'```python(?!\s+skip)(?:[^\n]*)\n(.*?)\n```'
15
+ matches = re.findall(pattern, content, re.DOTALL)
16
+
17
+ for match in matches:
18
+ # Skip blocks that are wrapped in skip-test comments
19
+ if '<!-- skip-test -->' not in content.split(match)[0][-100:]:
20
+ python_blocks.append(match)
21
+
22
+ return python_blocks
23
+
24
+ @pytest.mark.doc
25
+ def test_readme():
26
+ test_dir = pathlib.Path(__file__).parent
27
+ fpath = test_dir.parent.parent / "README.md"
28
+
29
+ # extract Python code
30
+ code_blocks = extract_python_code_from_md(fpath)
31
+
32
+ namespace = {}
33
+ exec("from pythonfmu3 import *", namespace)
34
+
35
+ for i, code in enumerate(code_blocks):
36
+ try:
37
+ exec(code, namespace)
38
+ print(f"✅ Code block {i+1} executed successfully")
39
+ except Exception as e:
40
+ pytest.fail(f"Code block {i+1} failed: {e}\nCode:\n{code}")
41
+
42
+
43
+
44
+
45
+ @pytest.mark.doc
46
+ def test_cosimulation_examples():
47
+ """Test that all Python examples in usage.md actually work"""
48
+ test_dir = pathlib.Path(__file__).parent
49
+ usage_file = test_dir.parent.parent / "docs" / "usage.md"
50
+
51
+ # Extract Python code
52
+ code_blocks = extract_python_code_from_md(usage_file)
53
+
54
+ # Create a test namespace
55
+ namespace = {}
56
+ exec("from pythonfmu3 import *", namespace)
57
+
58
+ # Execute each code block
59
+ for i, code in enumerate(code_blocks):
60
+ try:
61
+ exec(code, namespace)
62
+ print(f"✅ Code block {i+1} executed successfully")
63
+ except Exception as e:
64
+ pytest.fail(f"Code block {i+1} failed: {e}\nCode:\n{code}")
65
+
66
+ assert 'LinearTransform' in namespace, "LinearTransform class not found"
67
+ assert 'PIDController' in namespace, "PIDController class not found"
68
+
69
+ # Test instantiation
70
+ lt = namespace['LinearTransform'](instance_name="test")
71
+ pc = namespace['PIDController'](instance_name="test")
72
+
73
+
74
+ @pytest.mark.doc
75
+ def test_model_exchange_examples():
76
+ """Test Model Exchange examples"""
77
+ test_dir = pathlib.Path(__file__).parent
78
+ mx_file = test_dir.parent.parent / "docs" / "usageMX.md"
79
+
80
+ code_blocks = extract_python_code_from_md(mx_file)
81
+
82
+ namespace = {}
83
+ exec("from pythonfmu3 import *", namespace)
84
+
85
+ for i, code in enumerate(code_blocks):
86
+ try:
87
+ exec(code, namespace)
88
+ except Exception as e:
89
+ pytest.fail(f"MX Code block {i+1} failed: {e}")
90
+
91
+ # Test that classes were actually created
92
+ assert 'VanDerPol' in namespace, "VanDerPol class not found"
93
+ assert 'BouncingBall' in namespace, "BouncingBall class not found"
94
+
95
+ # Test instantiation
96
+ vdp = namespace['VanDerPol'](instance_name="test")
97
+
98
+ bb = namespace['BouncingBall'](instance_name="test")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonfmu3
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: A lightweight framework that enables the packaging of Python3.x code as co-simulation FMUs.
5
5
  Home-page: https://github.com/stephensmith25/PythonFMU3
6
6
  Author: Stephen Smith
@@ -173,6 +173,7 @@ To create a model exchange FMU you must inherit from `Fmi3SlaveBase` and one of
173
173
  ```python
174
174
 
175
175
  from pythonfmu3 import Fmi3Causality, Fmi3SlaveBase, Float64, ModelExchange
176
+ from typing import List
176
177
 
177
178
 
178
179
  class PythonSlaveMX(Fmi3SlaveBase, ModelExchange):
@@ -47,6 +47,7 @@ pythonfmu3/tests/__init__.py
47
47
  pythonfmu3/tests/conftest.py
48
48
  pythonfmu3/tests/test_builder.py
49
49
  pythonfmu3/tests/test_deploy.py
50
+ pythonfmu3/tests/test_docs.py
50
51
  pythonfmu3/tests/test_fmi3slave.py
51
52
  pythonfmu3/tests/test_integration.py
52
53
  pythonfmu3/tests/test_logger.py
@@ -49,6 +49,7 @@ tests =
49
49
  [tool:pytest]
50
50
  markers =
51
51
  integration: marks integration tests
52
+ doc: marks documentation tests
52
53
 
53
54
  [egg_info]
54
55
  tag_build =
@@ -1 +0,0 @@
1
- __version__ = "0.3.2"
File without changes
File without changes
File without changes