pythonfmu3 0.1.15__py3-none-any.whl → 0.1.17__py3-none-any.whl

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.
pythonfmu3/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from ._version import __version__
2
2
  from .builder import FmuBuilder
3
- from .enums import Fmi3Causality, Fmi3Initial, Fmi3Variability
4
- from .fmi3slave import Fmi3Slave
3
+ from .enums import Fmi3Causality, Fmi3Initial, Fmi3Status, Fmi3Variability
4
+ from .fmi3slave import Fmi3Slave, Fmi3StepResult
5
5
  from .variables import Boolean, Enumeration, Int32, Int64, UInt64, Float64, String, Dimension
6
6
  from .default_experiment import DefaultExperiment
7
7
  from .variable_types import Float64Type, EnumerationType
pythonfmu3/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.15"
1
+ __version__ = "0.1.17"
pythonfmu3/builder.py CHANGED
@@ -66,6 +66,7 @@ class FmuBuilder:
66
66
  dest: FilePath = ".",
67
67
  project_files: Iterable[FilePath] = set(),
68
68
  documentation_folder: Optional[FilePath] = None,
69
+ terminals_folder: Optional[FilePath] = None,
69
70
  **options,
70
71
  ) -> Path:
71
72
  script_file = Path(script_file)
@@ -85,6 +86,13 @@ class FmuBuilder:
85
86
  raise ValueError(
86
87
  f"The documentation folder does not exists {documentation_folder!s}"
87
88
  )
89
+
90
+ if terminals_folder is not None:
91
+ terminals_folder = Path(terminals_folder)
92
+ if not terminals_folder.exists():
93
+ raise ValueError(
94
+ f"The terminals folder does not exists {terminals_folder!s}"
95
+ )
88
96
 
89
97
  module_name = script_file.stem
90
98
 
@@ -178,6 +186,14 @@ class FmuBuilder:
178
186
  relative_f = f.relative_to(documentation_folder)
179
187
  zip_fmu.write(f, arcname=(documentation / relative_f))
180
188
 
189
+ if terminals_folder is not None:
190
+ terminals = Path("terminalsAndIcons")
191
+ for f in terminals_folder.rglob("*.xml"):
192
+ if f.is_file():
193
+ relative_f = f.relative_to(terminals_folder)
194
+ zip_fmu.write(f, arcname=(terminals / relative_f))
195
+
196
+
181
197
  # Add the model description
182
198
  xml_str = parseString(tostring(xml, "UTF-8"))
183
199
  zip_fmu.writestr(
@@ -215,6 +231,13 @@ def create_command_parser(parser: argparse.ArgumentParser):
215
231
  default=None
216
232
  )
217
233
 
234
+ parser.add_argument(
235
+ "--terminals",
236
+ dest="terminals_folder",
237
+ help="Folder containing terminals to include in the FMU.",
238
+ default=None
239
+ )
240
+
218
241
  for option in FMI3_MODEL_OPTIONS:
219
242
  action = "store_false" if option.value else "store_true"
220
243
  parser.add_argument(
pythonfmu3/fmi3slave.py CHANGED
@@ -5,7 +5,7 @@ import datetime
5
5
  from abc import ABC, abstractmethod
6
6
  from collections import OrderedDict, namedtuple
7
7
  from pathlib import Path
8
- from typing import Any, ClassVar, Dict, List, Optional
8
+ from typing import Any, ClassVar, Dict, List, NamedTuple, Optional
9
9
  from uuid import uuid1
10
10
  from xml.etree.ElementTree import Element, SubElement
11
11
 
@@ -27,6 +27,11 @@ FMI3_MODEL_OPTIONS: List[ModelOptions] = [
27
27
  ModelOptions("canSerializeFMUState", False, "serialize-state")
28
28
  ]
29
29
 
30
+ class Fmi3StepResult(NamedTuple):
31
+ status: Fmi3Status = Fmi3Status.ok
32
+ eventHandlingNeeded: bool = False
33
+ terminateSimulation: bool = False
34
+ earlyReturn: bool = False
30
35
 
31
36
  class Fmi3Slave(ABC):
32
37
  """Abstract facade class to execute Python through FMI standard."""
@@ -235,7 +240,7 @@ class Fmi3Slave(ABC):
235
240
  pass
236
241
 
237
242
  @abstractmethod
238
- def do_step(self, current_time: float, step_size: float) -> bool:
243
+ def do_step(self, current_time: float, step_size: float) -> Fmi3StepResult:
239
244
  pass
240
245
 
241
246
  def terminate(self):
pythonfmu3/osutil.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import sys
2
- import platform
3
2
 
4
3
  import platform
5
4
 
@@ -8,7 +7,8 @@ def get_fmu_arch():
8
7
  system = platform.system()
9
8
  is_x86 = platform.machine() in ["i386", "AMD64", "x86_64"]
10
9
  platforms = {"Windows": "windows", "Linux": "linux", "Darwin": "darwin"}
11
- return "x86_64" if is_x86 else "x86" + "-" + platforms.get(system, "unknown")
10
+ arch = "x86_64" if is_x86 else "x86"
11
+ return arch + "-" + platforms.get(system, "unknown")
12
12
 
13
13
  def get_platform() -> str:
14
14
  """Get FMU binary platform folder name."""
File without changes
@@ -105,11 +105,9 @@ public:
105
105
 
106
106
  Logger(
107
107
  FMIComponentEnvironment component,
108
- String instanceName,
109
108
  fmi3LogMessageCallback logCallback,
110
109
  std::shared_ptr<Settings> settings)
111
110
  : m_component{component}
112
- , m_instanceName(std::move(instanceName))
113
111
  , m_fmiLogger{logCallback}
114
112
  , m_settings{settings}
115
113
  {
@@ -154,7 +152,6 @@ public:
154
152
 
155
153
  private:
156
154
  const FMIComponentEnvironment m_component;
157
- const String m_instanceName;
158
155
  const FMICallbackLogger m_fmiLogger;
159
156
  std::shared_ptr<Settings> m_settings;
160
157
  };
@@ -124,10 +124,13 @@ public:
124
124
  FMIString value[]) const;
125
125
 
126
126
  // Called from fmi3DoStep()/fmiDoStep(). Must be implemented in model code.
127
- virtual bool DoStep(
127
+ virtual FMIStatus DoStep(
128
128
  FMIFloat64 currentCommunicationPoint,
129
129
  FMIFloat64 communicationStepSize,
130
130
  FMIBoolean newStep,
131
+ FMIBoolean* eventHandlingNeeded,
132
+ FMIBoolean* terminateSimulation,
133
+ FMIBoolean* earlyReturn,
131
134
  FMIFloat64& endOfStep) = 0;
132
135
 
133
136
  virtual void GetFMUstate(fmi3FMUState& state) = 0;
@@ -47,10 +47,10 @@ struct Component
47
47
  modelError = 1 << 12,
48
48
  modelFatal = 1 << 13,
49
49
  };
50
- Component(cppfmu::FMIString instanceName,
50
+ Component(cppfmu::FMIComponentEnvironment instanceEnvironment,
51
51
  cppfmu::FMICallbackLogger logCallback,
52
52
  cppfmu::FMIBoolean loggingOn) : loggerSettings{std::make_shared<cppfmu::Logger::Settings>()},
53
- logger{this, instanceName, logCallback, loggerSettings}, lastSuccessfulTime{std::numeric_limits<cppfmu::FMIFloat64>::quiet_NaN()}
53
+ logger{instanceEnvironment, logCallback, loggerSettings}
54
54
  {
55
55
  loggerSettings->debugLoggingEnabled = (loggingOn == cppfmu::FMITrue);
56
56
  }
@@ -62,7 +62,6 @@ struct Component
62
62
 
63
63
  // Co-simulation
64
64
  std::unique_ptr<cppfmu::SlaveInstance> slave;
65
- cppfmu::FMIFloat64 lastSuccessfulTime;
66
65
  };
67
66
  } // namespace
68
67
 
@@ -96,7 +95,8 @@ fmi3Instance fmi3InstantiateCoSimulation(
96
95
  fmi3IntermediateUpdateCallback intermediateUpdate )
97
96
  {
98
97
  try {
99
- auto component = new Component(instanceName,
98
+ auto component = new Component(
99
+ environment,
100
100
  logMessage,
101
101
  loggingOn);
102
102
  component->slave = CppfmuInstantiateSlave(
@@ -658,27 +658,30 @@ fmi3Status fmi3DoStep(
658
658
  fmi3Instance c,
659
659
  fmi3Float64 currentCommunicationPoint,
660
660
  fmi3Float64 communicationStepSize,
661
- fmi3Boolean /*noSetFMUStatePriorToCurrentPoint*/,
662
- fmi3Boolean*,
663
- fmi3Boolean*,
664
- fmi3Boolean*,
665
- fmi3Float64*)
661
+ fmi3Boolean noSetFmuStatePriorToCurrentPoint,
662
+ fmi3Boolean* eventHandlingNeeded ,
663
+ fmi3Boolean* terminateSimulation,
664
+ fmi3Boolean* earlyReturn,
665
+ fmi3Float64* lastSuccessfulTime)
666
666
  {
667
667
  const auto component = reinterpret_cast<Component*>(c);
668
668
  try {
669
669
  double endTime = currentCommunicationPoint;
670
- const auto ok = component->slave->DoStep(
670
+ const auto status = component->slave->DoStep(
671
671
  currentCommunicationPoint,
672
672
  communicationStepSize,
673
- fmi3True,
673
+ noSetFmuStatePriorToCurrentPoint,
674
+ eventHandlingNeeded,
675
+ terminateSimulation,
676
+ earlyReturn,
674
677
  endTime);
675
- if (ok) {
676
- component->lastSuccessfulTime =
678
+ if (status == fmi3Status::fmi3OK) {
679
+ *lastSuccessfulTime =
677
680
  currentCommunicationPoint + communicationStepSize;
678
681
  return fmi3OK;
679
682
  } else {
680
- component->lastSuccessfulTime = endTime;
681
- return fmi3Discard;
683
+ *lastSuccessfulTime = endTime;
684
+ return status;
682
685
  }
683
686
  } catch (const cppfmu::FatalError& e) {
684
687
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -200,20 +200,46 @@ void PySlaveInstance::ExitInitializationMode()
200
200
  });
201
201
  }
202
202
 
203
- bool PySlaveInstance::DoStep(cppfmu::FMIFloat64 currentTime, cppfmu::FMIFloat64 stepSize, cppfmu::FMIBoolean, cppfmu::FMIFloat64& endOfStep)
204
- {
205
- bool status;
206
- py_safe_run([this, &status, currentTime, stepSize](PyGILState_STATE gilState) {
203
+ cppfmu::FMIStatus PySlaveInstance::DoStep(cppfmu::FMIFloat64 currentTime,
204
+ cppfmu::FMIFloat64 stepSize,
205
+ cppfmu::FMIBoolean noSetFmuStatePriorToCurrentPoint,
206
+ cppfmu::FMIBoolean* eventHandlingNeeded,
207
+ cppfmu::FMIBoolean* terminateSimulation,
208
+ cppfmu::FMIBoolean* earlyReturn,
209
+ cppfmu::FMIFloat64& endOfStep)
210
+ {
211
+ cppfmu::FMIStatus fmuStatus = cppfmu::FMIOK;
212
+ py_safe_run([this, &fmuStatus, currentTime, stepSize, terminateSimulation](PyGILState_STATE gilState) {
207
213
  auto f = PyObject_CallMethod(pInstance_, "do_step", "(dd)", currentTime, stepSize);
208
214
  if (f == nullptr) {
209
215
  handle_py_exception("[doStep] PyObject_CallMethod", gilState);
210
216
  }
211
- status = static_cast<bool>(PyObject_IsTrue(f));
217
+
218
+ if (PyObject_HasAttrString(f, "status")) {
219
+ PyObject* pyStatus = PyObject_GetAttrString(f, "status");
220
+ if (pyStatus) {
221
+ fmuStatus = static_cast<cppfmu::FMIStatus>(PyLong_AsLong(pyStatus));
222
+ Py_DECREF(pyStatus);
223
+ }
224
+ } else {
225
+ bool status = static_cast<bool>(PyObject_IsTrue(f));
226
+ if (!status) {
227
+ fmuStatus = cppfmu::FMIDiscard;
228
+ }
229
+ }
230
+
231
+ if (PyObject_HasAttrString(f, "terminateSimulation")) {
232
+ PyObject* pyTerminateSimulation = PyObject_GetAttrString(f, "terminateSimulation");
233
+ if (pyTerminateSimulation) {
234
+ *terminateSimulation = static_cast<bool>(PyObject_IsTrue(pyTerminateSimulation));
235
+ Py_DECREF(pyTerminateSimulation);
236
+ }
237
+ }
212
238
  Py_DECREF(f);
213
239
  clearLogBuffer();
214
240
  });
215
241
 
216
- return status;
242
+ return fmuStatus;
217
243
  }
218
244
 
219
245
  void PySlaveInstance::Reset()
@@ -25,7 +25,13 @@ public:
25
25
  void ExitInitializationMode() override;
26
26
  void Terminate() override;
27
27
  void Reset() override;
28
- bool DoStep(cppfmu::FMIFloat64 currentCommunicationPoint, cppfmu::FMIFloat64 communicationStepSize, cppfmu::FMIBoolean newStep, cppfmu::FMIFloat64& endOfStep) override;
28
+ cppfmu::FMIStatus DoStep(cppfmu::FMIFloat64 currentCommunicationPoint,
29
+ cppfmu::FMIFloat64 communicationStepSize,
30
+ cppfmu::FMIBoolean newStep,
31
+ cppfmu::FMIBoolean* eventHandlingNeeded,
32
+ cppfmu::FMIBoolean* terminateSimulation,
33
+ cppfmu::FMIBoolean* earlyReturn,
34
+ cppfmu::FMIFloat64& endOfStep) override;
29
35
 
30
36
  void SetFloat64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIFloat64* value, std::size_t nValues) override;
31
37
  void SetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt32* value) override;
@@ -1,4 +1,4 @@
1
- from pythonfmu3.fmi3slave import Fmi3Slave, Fmi3Causality, Float64
1
+ from pythonfmu3.fmi3slave import Fmi3Slave, Fmi3Causality, Float64, Fmi3Variability
2
2
 
3
3
 
4
4
  class PythonSlaveWithException(Fmi3Slave):
@@ -8,6 +8,9 @@ class PythonSlaveWithException(Fmi3Slave):
8
8
 
9
9
  self.realIn = 22.0
10
10
  self.realOut = 0.0
11
+ self.time = 0
12
+
13
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
11
14
  self.register_variable(Float64("realIn", causality=Fmi3Causality.input))
12
15
  self.register_variable(Float64("realOut", causality=Fmi3Causality.output))
13
16
 
@@ -21,6 +21,9 @@ class PythonSlave(Fmi3Slave):
21
21
  self.realIn = 2. / 3.
22
22
  self.booleanParameter = False
23
23
  self.stringParameter = "dog"
24
+ self.time = 0
25
+
26
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
24
27
  self.register_variable(
25
28
  Int32("intParam", causality=Fmi3Causality.parameter, variability=Fmi3Variability.tunable))
26
29
  self.register_variable(Float64("realIn", causality=Fmi3Causality.input))
@@ -1,4 +1,4 @@
1
- from pythonfmu3.fmi3slave import Fmi3Slave, Fmi3Causality, Fmi3Variability, String, DefaultExperiment
1
+ from pythonfmu3.fmi3slave import Fmi3Slave, Fmi3Causality, Fmi3Variability, String, DefaultExperiment, Float64
2
2
 
3
3
 
4
4
  class PythonSlaveReadFile(Fmi3Slave):
@@ -11,6 +11,9 @@ class PythonSlaveReadFile(Fmi3Slave):
11
11
  with (open(f'{self.resources}/hello.txt', 'r')) as file:
12
12
  data = file.read()
13
13
 
14
+ self.time = 0
15
+
16
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
14
17
  self.register_variable(
15
18
  String("file_content", getter=lambda: data,
16
19
  causality=Fmi3Causality.output,
@@ -1,5 +1,5 @@
1
1
  import math
2
- from pythonfmu3.fmi3slave import Fmi3Slave, Fmi3Causality, Float64
2
+ from pythonfmu3.fmi3slave import Fmi3Slave, Fmi3Causality, Float64, Fmi3Variability
3
3
  from localmodule import get_amplitude, get_time_constant
4
4
 
5
5
 
@@ -10,6 +10,9 @@ class PythonSlaveWithDep(Fmi3Slave):
10
10
 
11
11
  self.realIn = 22.0
12
12
  self.realOut = 0.0
13
+ self.time = 0
14
+
15
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
13
16
  self.register_variable(Float64("realIn", causality=Fmi3Causality.input))
14
17
  self.register_variable(Float64("realOut", causality=Fmi3Causality.output))
15
18
 
@@ -176,3 +176,23 @@ def test_documentation(tmp_path):
176
176
 
177
177
  assert "documentation/index.html" in names
178
178
  assert "documentation/licenses/license.txt" in names
179
+
180
+
181
+ def test_terminals(tmp_path):
182
+ script_file = Path(__file__).parent / "slaves/pythonslave.py"
183
+ def build():
184
+ with tempfile.TemporaryDirectory() as terminals_dir:
185
+ terminals_dir = Path(terminals_dir)
186
+ terminal1 = terminals_dir / "terminal1.xml"
187
+ terminal1.write_text("Dummy Terminal 1")
188
+
189
+ terminal2 = terminals_dir / "terminal2.xml"
190
+ terminal2.write_text("Dummy Terminal 2")
191
+ return FmuBuilder.build_FMU(script_file, dest=tmp_path, terminals_folder=terminals_dir)
192
+
193
+ fmu = build()
194
+ with zipfile.ZipFile(fmu) as files:
195
+ names = files.namelist()
196
+
197
+ assert "terminalsAndIcons/terminal1.xml" in names
198
+ assert "terminalsAndIcons/terminal2.xml" in names
@@ -38,13 +38,12 @@ def test_integration_reset(tmp_path):
38
38
 
39
39
  md = fmpy.read_model_description(str(fmu))
40
40
  unzipdir = fmpy.extract(str(fmu))
41
- model = fmpy.fmi3.FMI3Slave(guid=md.guid,
41
+ model = fmpy.fmi3.FMU3Slave(guid=md.guid,
42
42
  unzipDirectory=unzipdir,
43
43
  modelIdentifier=md.coSimulation.modelIdentifier,
44
44
  instanceName="instance"
45
45
  )
46
46
  model.instantiate()
47
- model.setupExperiment()
48
47
  model.enterInitializationMode()
49
48
  model.exitInitializationMode()
50
49
 
@@ -52,13 +51,13 @@ def test_integration_reset(tmp_path):
52
51
  vr = vars["realOut"].valueReference
53
52
  dt = 0.1
54
53
 
55
- initial_value = model.getReal([vr])[0]
54
+ initial_value = model.getFloat64([vr])[0]
56
55
  assert initial_value == pytest.approx(3.0, rel=1e-7)
57
56
  model.doStep(0.0, dt, True)
58
- read = model.getReal([vr])[0]
57
+ read = model.getFloat64([vr])[0]
59
58
  assert read == pytest.approx(dt, rel=1e-7)
60
59
  model.reset()
61
- read = model.getReal([vr])[0]
60
+ read = model.getFloat64([vr])[0]
62
61
  assert read == pytest.approx(initial_value, rel=1e-7)
63
62
 
64
63
  model.terminate()
@@ -77,13 +76,12 @@ def test_integration_get_state(tmp_path):
77
76
 
78
77
  md = fmpy.read_model_description(str(fmu))
79
78
  unzipdir = fmpy.extract(str(fmu))
80
- model = fmpy.fmi3.FMI3Slave(guid=md.guid,
79
+ model = fmpy.fmi3.FMU3Slave(guid=md.guid,
81
80
  unzipDirectory=unzipdir,
82
81
  modelIdentifier=md.coSimulation.modelIdentifier,
83
82
  instanceName="instance"
84
83
  )
85
84
  model.instantiate()
86
- model.setupExperiment()
87
85
  model.enterInitializationMode()
88
86
  model.exitInitializationMode()
89
87
 
@@ -98,15 +96,15 @@ def test_integration_get_state(tmp_path):
98
96
  t += dt
99
97
 
100
98
  step_model()
101
- state = model.getFMUstate()
102
- assert model.getReal([vr])[0] == pytest.approx(dt, rel=1e-7)
99
+ state = model.getFMUState()
100
+ assert model.getFloat64([vr])[0] == pytest.approx(dt, rel=1e-7)
103
101
  step_model()
104
- assert model.getReal([vr])[0] == pytest.approx(dt * 2, rel=1e-7)
105
- model.setFMUstate(state)
106
- assert model.getReal([vr])[0] == pytest.approx(dt, rel=1e-7)
102
+ assert model.getFloat64([vr])[0] == pytest.approx(dt * 2, rel=1e-7)
103
+ model.setFMUState(state)
104
+ assert model.getFloat64([vr])[0] == pytest.approx(dt, rel=1e-7)
107
105
  step_model()
108
- assert model.getReal([vr])[0] == pytest.approx(dt * 3, rel=1e-7)
109
- model.freeFMUstate(state)
106
+ assert model.getFloat64([vr])[0] == pytest.approx(dt * 3, rel=1e-7)
107
+ model.freeFMUState(state)
110
108
 
111
109
  model.terminate()
112
110
  model.freeInstance()
@@ -126,14 +124,13 @@ def test_integration_get_serialize_state(tmp_path):
126
124
  md = fmpy.read_model_description(fmu)
127
125
  unzip_dir = fmpy.extract(fmu)
128
126
 
129
- model = fmpy.fmi3.FMI3Slave(
127
+ model = fmpy.fmi3.FMU3Slave(
130
128
  guid=md.guid,
131
129
  unzipDirectory=unzip_dir,
132
130
  modelIdentifier=md.coSimulation.modelIdentifier,
133
131
  instanceName='instance1')
134
132
 
135
133
  model.instantiate()
136
- model.setupExperiment()
137
134
  model.enterInitializationMode()
138
135
  model.exitInitializationMode()
139
136
 
@@ -148,22 +145,22 @@ def test_integration_get_serialize_state(tmp_path):
148
145
  t += dt
149
146
 
150
147
  step_model()
151
- state = model.getFMUstate()
152
- assert model.getReal(vrs)[0] == pytest.approx(dt, rel=1e-7)
148
+ state = model.getFMUState()
149
+ assert model.getFloat64(vrs)[0] == pytest.approx(dt, rel=1e-7)
153
150
  step_model()
154
- assert model.getReal(vrs)[0] == pytest.approx(dt * 2, rel=1e-7)
155
- model.setFMUstate(state)
156
- assert model.getReal(vrs)[0] == pytest.approx(dt, rel=1e-7)
151
+ assert model.getFloat64(vrs)[0] == pytest.approx(dt * 2, rel=1e-7)
152
+ model.setFMUState(state)
153
+ assert model.getFloat64(vrs)[0] == pytest.approx(dt, rel=1e-7)
157
154
  step_model()
158
- assert model.getReal(vrs)[0] == pytest.approx(dt * 3, rel=1e-7)
155
+ assert model.getFloat64(vrs)[0] == pytest.approx(dt * 3, rel=1e-7)
159
156
 
160
- serialize_fmu_state = model.serializeFMUstate(state)
161
- model.freeFMUstate(state)
162
- de_serialize_fmu_state = model.deSerializeFMUstate(serialize_fmu_state)
163
- model.setFMUstate(de_serialize_fmu_state)
164
- assert model.getReal(vrs)[0] == pytest.approx(dt, rel=1e-7)
157
+ serialize_fmu_state = model.serializeFMUState(state)
158
+ model.freeFMUState(state)
159
+ de_serialize_fmu_state = model.deserializeFMUState(serialize_fmu_state)
160
+ model.setFMUState(de_serialize_fmu_state)
161
+ assert model.getFloat64(vrs)[0] == pytest.approx(dt, rel=1e-7)
165
162
 
166
- model.freeFMUstate(de_serialize_fmu_state)
163
+ model.freeFMUState(de_serialize_fmu_state)
167
164
 
168
165
  model.terminate()
169
166
  model.freeInstance()
@@ -178,14 +175,13 @@ def test_integration_get(tmp_path):
178
175
  md = fmpy.read_model_description(fmu)
179
176
  unzip_dir = fmpy.extract(fmu)
180
177
 
181
- model = fmpy.fmi3.FMI3Slave(
178
+ model = fmpy.fmi3.FMU3Slave(
182
179
  guid=md.guid,
183
180
  unzipDirectory=unzip_dir,
184
181
  modelIdentifier=md.coSimulation.modelIdentifier,
185
182
  instanceName='instance1')
186
183
 
187
184
  model.instantiate()
188
- model.setupExperiment()
189
185
  model.enterInitializationMode()
190
186
  model.exitInitializationMode()
191
187
 
@@ -207,14 +203,14 @@ def test_integration_get(tmp_path):
207
203
  for key, value in to_test.items():
208
204
  var = variables[key]
209
205
  vrs = [var.valueReference]
210
- if var.type == "Integer":
211
- model_value = model.getInteger(vrs)[0]
212
- elif var.type == "Real":
213
- model_value = model.getReal(vrs)[0]
206
+ if var.type == "Int32":
207
+ model_value = model.getInt32(vrs)[0]
208
+ elif var.type == "Float64":
209
+ model_value = model.getFloat64(vrs)[0]
214
210
  elif var.type == "Boolean":
215
211
  model_value = model.getBoolean(vrs)[0]
216
212
  elif var.type == "String":
217
- model_value = model.getString(vrs)[0].decode("UTF-8")
213
+ model_value = model.getString(vrs)[0]
218
214
  else:
219
215
  pytest.xfail("Unsupported type")
220
216
 
@@ -234,20 +230,19 @@ def test_integration_read_from_file(tmp_path):
234
230
  md = fmpy.read_model_description(fmu)
235
231
  unzip_dir = fmpy.extract(fmu)
236
232
 
237
- model = fmpy.fmi3.FMI3Slave(
233
+ model = fmpy.fmi3.FMU3Slave(
238
234
  guid=md.guid,
239
235
  unzipDirectory=unzip_dir,
240
236
  modelIdentifier=md.coSimulation.modelIdentifier,
241
237
  instanceName='instance1')
242
238
 
243
239
  model.instantiate()
244
- model.setupExperiment()
245
240
  model.enterInitializationMode()
246
241
  model.exitInitializationMode()
247
242
 
248
243
  variables = mapped(md)
249
244
  var = variables["file_content"]
250
- model_value = model.getString([var.valueReference])[0].decode("UTF-8")
245
+ model_value = model.getString([var.valueReference])[0]
251
246
 
252
247
  with (open(project_file, 'r')) as file:
253
248
  data = file.read()
@@ -267,14 +262,13 @@ def test_integration_set(tmp_path):
267
262
  md = fmpy.read_model_description(fmu)
268
263
  unzip_dir = fmpy.extract(fmu)
269
264
 
270
- model = fmpy.fmi3.FMI3Slave(
265
+ model = fmpy.fmi3.FMU3Slave(
271
266
  guid=md.guid,
272
267
  unzipDirectory=unzip_dir,
273
268
  modelIdentifier=md.coSimulation.modelIdentifier,
274
269
  instanceName='instance1')
275
270
 
276
271
  model.instantiate()
277
- model.setupExperiment()
278
272
  model.enterInitializationMode()
279
273
  model.exitInitializationMode()
280
274
 
@@ -292,18 +286,18 @@ def test_integration_set(tmp_path):
292
286
  for key, value in to_test.items():
293
287
  var = variables[key]
294
288
  vrs = [var.valueReference]
295
- if var.type == "Integer":
296
- model.setInteger(vrs, [value])
297
- model_value = model.getInteger(vrs)[0]
298
- elif var.type == "Real":
299
- model.setReal(vrs, [value])
300
- model_value = model.getReal(vrs)[0]
289
+ if var.type == "Int32":
290
+ model.setInt32(vrs, [value])
291
+ model_value = model.getInt32(vrs)[0]
292
+ elif var.type == "Float64":
293
+ model.setFloat64(vrs, [value])
294
+ model_value = model.getFloat64(vrs)[0]
301
295
  elif var.type == "Boolean":
302
296
  model.setBoolean(vrs, [value])
303
297
  model_value = model.getBoolean(vrs)[0]
304
298
  elif var.type == "String":
305
299
  model.setString(vrs, [value])
306
- model_value = model.getString(vrs)[0].decode("UTF-8")
300
+ model_value = model.getString(vrs)[0]
307
301
  else:
308
302
  pytest.xfail("Unsupported type")
309
303
 
@@ -22,7 +22,7 @@ def mapped(md):
22
22
  @pytest.mark.integration
23
23
  def test_integration_multiple_fmus(tmp_path):
24
24
  slave1_code = """import math
25
- from pythonfmu3.Fmi3Slave import Fmi3Slave, Fmi3Causality, Int32, Float64, Boolean, String
25
+ from pythonfmu3 import Fmi3Slave, Fmi3Causality, Fmi3Variability, Int32, Float64, Boolean, String
26
26
 
27
27
 
28
28
  class Slave1(Fmi3Slave):
@@ -32,6 +32,8 @@ class Slave1(Fmi3Slave):
32
32
 
33
33
  self.realIn = 22.0
34
34
  self.realOut = 0.0
35
+ self.time = 0
36
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
35
37
  self.register_variable(Float64("realIn", causality=Fmi3Causality.input))
36
38
  self.register_variable(Float64("realOut", causality=Fmi3Causality.output))
37
39
 
@@ -41,7 +43,7 @@ class Slave1(Fmi3Slave):
41
43
  return True
42
44
  """
43
45
 
44
- slave2_code = """from pythonfmu3.Fmi3Slave import Fmi3Slave, Fmi3Causality, Int32, Float64, Boolean, String
46
+ slave2_code = """from pythonfmu3 import Fmi3Slave, Fmi3Causality, Fmi3Variability, Int32, Float64, Boolean, String
45
47
 
46
48
 
47
49
  class Slave2(Fmi3Slave):
@@ -51,6 +53,8 @@ class Slave2(Fmi3Slave):
51
53
 
52
54
  self.realIn = 22.0
53
55
  self.realOut = 0.0
56
+ self.time = 0
57
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
54
58
  self.register_variable(Float64("realIn", causality=Fmi3Causality.input))
55
59
  self.register_variable(Float64("realOut", causality=Fmi3Causality.output))
56
60
 
@@ -84,21 +88,20 @@ class Slave2(Fmi3Slave):
84
88
  md1 = fmpy.read_model_description(fmu1)
85
89
  unzip_dir = fmpy.extract(fmu1)
86
90
 
87
- model1 = fmpy.fmi3.FMI3Slave(
91
+ model1 = fmpy.fmi3.FMU3Slave(
88
92
  guid=md1.guid,
89
93
  unzipDirectory=unzip_dir,
90
94
  modelIdentifier=md1.coSimulation.modelIdentifier,
91
95
  instanceName='instance1')
92
96
 
93
97
  model1.instantiate()
94
- model1.setupExperiment()
95
98
  model1.enterInitializationMode()
96
99
  model1.exitInitializationMode()
97
100
 
98
101
  md2 = fmpy.read_model_description(fmu2)
99
102
  unzip_dir = fmpy.extract(fmu2)
100
103
 
101
- model2 = fmpy.fmi3.FMI3Slave(
104
+ model2 = fmpy.fmi3.FMU3Slave(
102
105
  guid=md2.guid,
103
106
  unzipDirectory=unzip_dir,
104
107
  modelIdentifier=md2.coSimulation.modelIdentifier,
@@ -111,11 +114,10 @@ class Slave2(Fmi3Slave):
111
114
  realIn = variables2["realIn"]
112
115
 
113
116
  model2.instantiate()
114
- model2.setupExperiment()
115
117
  model2.enterInitializationMode()
116
118
 
117
- value = model1.getReal([realOut.valueReference])[0]
118
- model2.setReal([realIn.valueReference], [value])
119
+ value = model1.getFloat64([realOut.valueReference])[0]
120
+ model2.setFloat64([realIn.valueReference], [value])
119
121
 
120
122
  model2.exitInitializationMode()
121
123
 
@@ -125,12 +127,12 @@ class Slave2(Fmi3Slave):
125
127
 
126
128
  while time < stop_time:
127
129
 
128
- model2.setReal([realIn.valueReference], [value])
130
+ model2.setFloat64([realIn.valueReference], [value])
129
131
 
130
132
  model1.doStep(time, step_size)
131
133
  model2.doStep(time, step_size)
132
134
 
133
- value = model1.getReal([realOut.valueReference])[0]
135
+ value = model1.getFloat64([realOut.valueReference])[0]
134
136
 
135
137
  time += step_size
136
138
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pythonfmu3
3
- Version: 0.1.15
3
+ Version: 0.1.17
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
@@ -62,7 +62,7 @@ pip install pythonfmu3
62
62
  3. Run `pythonfmu3 build` to create the fmu.
63
63
 
64
64
  ```
65
- usage: pythonfmu3 build [-h] -f SCRIPT_FILE [-d DEST] [--doc DOCUMENTATION_FOLDER] [--no-external-tool]
65
+ usage: pythonfmu3 build [-h] -f SCRIPT_FILE [-d DEST] [--doc DOCUMENTATION_FOLDER] [--terminals TERMINALS_FOLDER] [--no-external-tool]
66
66
  [--no-variable-step] [--interpolate-inputs] [--only-one-per-process] [--handle-state]
67
67
  [--serialize-state] [--use-memory-management]
68
68
  [Project files [Project files ...]]
@@ -79,6 +79,8 @@ optional arguments:
79
79
  -d DEST, --dest DEST Where to save the FMU.
80
80
  --doc DOCUMENTATION_FOLDER
81
81
  Documentation folder to include in the FMU.
82
+ --terminals TERMINALS_FOLDER
83
+ Folder of terminals to include in the FMU.
82
84
  --no-external-tool If given, needsExecutionTool=false
83
85
  --no-variable-step If given, canHandleVariableCommunicationStepSize=false
84
86
  --interpolate-inputs If given, canInterpolateInputs=true
@@ -1,13 +1,13 @@
1
- pythonfmu3/__init__.py,sha256=PT1R0LpSInyVdXGJbkWMTQym6_SEU7CqUkG7OH5j1f0,396
1
+ pythonfmu3/__init__.py,sha256=oN-2oXyCFwq0gvL2IEf5QvwIXBXZgsSBwAJw7LZ9vzc,424
2
2
  pythonfmu3/__main__.py,sha256=gC1T8x2d02hhqshyNQGSS70SyCk-3I3t8zPqoRo2Xd8,1543
3
- pythonfmu3/_version.py,sha256=qb0TalpSt1CbprnFyeLUKqgrqNtmnk9IoQQ7umAoXVY,23
4
- pythonfmu3/builder.py,sha256=YLTeLLpiFOkoDYwnJ55GEhb3ham0xxROMjMN6bvaw5Y,8784
3
+ pythonfmu3/_version.py,sha256=BzIjnki8Bz3evNWo6bjGxxpLhy_tN9MRYhtM0MnDiWs,23
4
+ pythonfmu3/builder.py,sha256=ZW-ig7GkWlwGrQ3z8wVsL6j7S6bynWLtL50Sw__M_og,9679
5
5
  pythonfmu3/default_experiment.py,sha256=FJ0l0FpU7pT4Pox2RiA2y-Cb_e7DE2XlbWKySRYQaVk,293
6
6
  pythonfmu3/deploy.py,sha256=eqFWVxZUkJCLvmq1-GuMNjn2j0VCGoaXPhRWrCk2Vxg,3741
7
7
  pythonfmu3/enums.py,sha256=ZmC6vGeBTGt7HarPQ4uYV10ezPsvIxAHH1ypjNq7G3E,729
8
- pythonfmu3/fmi3slave.py,sha256=7rDp_5TCQnkFLV11UF55mKEvUDXbpZPfn8sOjYCNCSw,16569
8
+ pythonfmu3/fmi3slave.py,sha256=M5zZbsdM8fv8NPfMp9ljyrLcqzE5RSvM3iFz5qyxnN0,16770
9
9
  pythonfmu3/logmsg.py,sha256=0wn11GLwq0LLWqyC2ktLRjQFWlpj07wWliZ8rUHx1gg,359
10
- pythonfmu3/osutil.py,sha256=KMAoMf_BpqFQQUy3WzHnt9jiklkS1xy0syIbj7kNH6A,656
10
+ pythonfmu3/osutil.py,sha256=1qN6qudN4zCupZwc15pzp52WObkqi6jGy9a-MehNt9Q,656
11
11
  pythonfmu3/unit.py,sha256=SjOaywb5lVQbAO_iLjc_7Ly3nYrmAvIW2_hAGt12UFU,1475
12
12
  pythonfmu3/variable_types.py,sha256=Q0D4wlGi3i3zE5UsmGJEpNh7SV_W8mn_8p_WIkwrLQA,2881
13
13
  pythonfmu3/variables.py,sha256=hwYT6AfaSQIa1egVJrOxnDi5NEj1bk_VkQd9-hsoDII,11905
@@ -16,39 +16,39 @@ pythonfmu3/pythonfmu-export/CMakeLists.txt,sha256=p0-4Xh_sAaOI9AVb8lsUsMxJPc6bg9
16
16
  pythonfmu3/pythonfmu-export/build_unix.sh,sha256=I5RrF2O6y0hRG_SN4ExKN_CCFYaa2l-ngKzqmBXnHmA,73
17
17
  pythonfmu3/pythonfmu-export/build_win.sh,sha256=UzmAcWqFmwBu6mvYne2Dx3UK8iPwTtP4HpjICsjUaJA,97
18
18
  pythonfmu3/pythonfmu-export/src/CMakeLists.txt,sha256=RyjGhUUDhG_HEieCdt5WMfTR1snofOqigEKc83_zvfE,1104
19
- pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_common.hpp,sha256=k6TEU6J6fe6RJWxsvA4uA2W4BRQriPnkQX4GKdM-MgA,4465
19
+ pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_common.hpp,sha256=cgrlZa5L-bbjZeVi0pmy4JKE5UJ2GszzuyOqTdRcBRQ,4353
20
20
  pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp,sha256=EsUIevwmCzX9hsui3i8x1crSnSOG8dEK15Zm1ZIavYQ,3843
21
- pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp,sha256=v4Fb8gOWk2tsUgnuQ2NBeqwc3EFQhWRxvDYHtL1C0zk,6144
22
- pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp,sha256=sTHQVUCH_dwIxRl6u1VRNkTb1MRUoVlQLGpTPh5WQdk,25505
21
+ pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp,sha256=UmqAVAVE1KHNHMC8mIh8gIHRJ_aQk0Ma139TU6Kvv4o,6264
22
+ pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp,sha256=FL8TveY4TNAbtrgzElC4WliY8C1vOfvtd5Sh2CcVFgc,25610
23
23
  pythonfmu3/pythonfmu-export/src/fmi/fmi3FunctionTypes.h,sha256=Tk1WY0nAYBGiOAQ8zVbmqRAfdQttITWsLba7udhBwG4,30050
24
24
  pythonfmu3/pythonfmu-export/src/fmi/fmi3Functions.h,sha256=NsHuclp20wcuUInYf-91UXZbljTeu2cPXENqNEORdgU,16262
25
25
  pythonfmu3/pythonfmu-export/src/fmi/fmi3PlatformTypes.h,sha256=ZCQLJgSbRGrMsBiQ4auaYCY4J3Hck6g3t1iZp5NEguw,4251
26
26
  pythonfmu3/pythonfmu-export/src/pythonfmu/IPyState.hpp,sha256=GLiOjhKLDVEICersnqVwezwEshbxfdh_cyMxBJGFbu8,456
27
- pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp,sha256=pzHSx3Cfq7Lt7dcvMR5na7tyOrTs0RsNglnrAcRc0cs,24333
28
- pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp,sha256=Q8eulMAkv7YkfzCi2KSwxvYngv0I_nRbmfTJR9vT92M,4063
27
+ pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp,sha256=MpEUUcxPwoJlM_mW-9qxj4ezgKQd-CkDc2ud0mM7HbQ,25362
28
+ pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp,sha256=T-epGp68SjhDv-JupxUe2ZgnV8unU4htc-PUBokjWm4,4239
29
29
  pythonfmu3/pythonfmu-export/src/pythonfmu/PyState.hpp,sha256=CjFEIrZu8b1jxQAIgfI_o36hyItW_SdQ5VSkImf7JNs,2977
30
- pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so,sha256=abssHrtFiwtjugmJkjHL29TqmimbkydTsAEr5k7ryKc,365120
31
- pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll,sha256=5S2ivGp0No5x-vJjb9iWBf2m7SLvDw_gcTgQycTcdKk,431104
30
+ pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so,sha256=LLTlb6TDjJ24xuy7zhO5Sbj39nVzQSODkkXMXGl8Y7s,365224
31
+ pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll,sha256=b22hsx-MKU7vhYcbLViGyAfd0Jxv29sx0mxtWO3S7u0,430592
32
32
  pythonfmu3/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  pythonfmu3/tests/conftest.py,sha256=B6XxTnBdeF_tEJ3w2DlfPKUfvlk-oULgIhQtXkgOJIc,171
34
- pythonfmu3/tests/test_builder.py,sha256=StR9oNmF6dtuxxKtPFlncLQN-O7n97nvHm6EFH4Qn14,6252
34
+ pythonfmu3/tests/test_builder.py,sha256=gxelTXyk03VreAy5ptQRQtl20IstO9eWTifTSvTceiE,7004
35
35
  pythonfmu3/tests/test_deploy.py,sha256=JCDo-O93-izxrP9Q4K0njBcfZ-gAXYx9aZ4plgctz7k,1783
36
36
  pythonfmu3/tests/test_fmi3slave.py,sha256=1uwTdfiFZNmU0yzIdC30kAuu95xsZSTMA9CGk_Kdmm4,4304
37
- pythonfmu3/tests/test_integration.py,sha256=2ewA-Mai5qbC5ujyYDLo_Em1NzGsfrgaYiugDZH53ow,10562
37
+ pythonfmu3/tests/test_integration.py,sha256=zA3iJ4rI2cKEE8mDsAmcVuwNWlJzhonV8Wxz92hzEac,10387
38
38
  pythonfmu3/tests/test_logger.py,sha256=OcHQhxUtNBPH-0zdmheC4I9OWz1yu48W8MYDshNVkf8,5765
39
- pythonfmu3/tests/test_multiple_fmus.py,sha256=NJC3aHu1PA4LlZjMmCfC3IKh-_IBu1h3QMkrKiDYFrY,3680
39
+ pythonfmu3/tests/test_multiple_fmus.py,sha256=-sthCm2YUZiRkdfvpLQNgquPBForUKQ7HGqfFBdrRas,3942
40
40
  pythonfmu3/tests/test_variables.py,sha256=t4r2TBruf58uYwjkp3r-RcZS5TrsOaVT_mDuoiUTQtg,9598
41
41
  pythonfmu3/tests/utils.py,sha256=WusWSUGoBPenZL-FAKQlzaHN2aYXiznZM2fwCjoldwY,301
42
42
  pythonfmu3/tests/data/csvdemo.csv,sha256=TiTUyzHyjQNXM4eXI33oJipc7w9_PJ8aMejRmwc52Xw,256
43
43
  pythonfmu3/tests/data/hello.txt,sha256=wFNeS-K3n_2TKRMFQ2v4iTFOSj-uwF7P_Lt98xrZ5Ro,12
44
- pythonfmu3/tests/slaves/PythonSlaveWithException.py,sha256=SUSjrba1mZBT_2pOYNQi2fEv8Ns5QWDM5zYps__4NJM,479
44
+ pythonfmu3/tests/slaves/PythonSlaveWithException.py,sha256=lTTMMnD5Cu09HzA8G2masKyf-ntEMfJ0a3M8btdYVLo,644
45
45
  pythonfmu3/tests/slaves/localmodule.py,sha256=-q5Lmh2I88MG7nLTscms0n5xhHLkUDed1IuQ5wj49lo,79
46
- pythonfmu3/tests/slaves/pythonslave.py,sha256=H75vLhqshSWWvMj2NQt6a_aQhA6BGSkBVJstjjVE0AU,2024
47
- pythonfmu3/tests/slaves/pythonslave_read_file.py,sha256=NIAmyZZGNAcnqf8R5jb1yFcQxj6iSMOAc13pY0GFtco,634
48
- pythonfmu3/tests/slaves/slavewithdep.py,sha256=4yqxa0vsOTLLvtaUQFkjfU9OcwjDUtuUe-qIjnD-jrw,647
49
- pythonfmu3-0.1.15.dist-info/LICENSE,sha256=24Cw_MPouLK-G_t8Hgjm59IS9BnPoL6SKkyuZ0xesXY,1155
50
- pythonfmu3-0.1.15.dist-info/METADATA,sha256=wLt8-BEWjeq7FO4G_YnSEQXUd2387gE_YhY3oW4v3hc,7442
51
- pythonfmu3-0.1.15.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
52
- pythonfmu3-0.1.15.dist-info/entry_points.txt,sha256=GgkWYs0DKGHLcijMEYZGkhkHOK2RVUpjGwvl1fwyDwQ,60
53
- pythonfmu3-0.1.15.dist-info/top_level.txt,sha256=6ne7bh_cME1hepxCx1BG8N5QVhVAufrp7LLok6vq7nE,11
54
- pythonfmu3-0.1.15.dist-info/RECORD,,
46
+ pythonfmu3/tests/slaves/pythonslave.py,sha256=uzrTQmfk0QBalxNTviGMZNph_YgVmcbxPqKgX5rSvXg,2172
47
+ pythonfmu3/tests/slaves/pythonslave_read_file.py,sha256=t2sDaZSr2veD91gdqCO9W9CN-AN3TyXABXXfV9Rt0Xs,791
48
+ pythonfmu3/tests/slaves/slavewithdep.py,sha256=hHDFB0dw8wkHiGzxeAVbz9O5LR6ghsFeONgRFdiK_t0,812
49
+ pythonfmu3-0.1.17.dist-info/LICENSE,sha256=24Cw_MPouLK-G_t8Hgjm59IS9BnPoL6SKkyuZ0xesXY,1155
50
+ pythonfmu3-0.1.17.dist-info/METADATA,sha256=JnvWnoH6HzMnzQiBmd6P9J5goxKpqPdGYQcMO4Aalo4,7571
51
+ pythonfmu3-0.1.17.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
52
+ pythonfmu3-0.1.17.dist-info/entry_points.txt,sha256=GgkWYs0DKGHLcijMEYZGkhkHOK2RVUpjGwvl1fwyDwQ,60
53
+ pythonfmu3-0.1.17.dist-info/top_level.txt,sha256=6ne7bh_cME1hepxCx1BG8N5QVhVAufrp7LLok6vq7nE,11
54
+ pythonfmu3-0.1.17.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.0.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5