Support for Introspection API's#339
Conversation
bd92a0e to
06b6caf
Compare
efredriksson-modelon
left a comment
There was a problem hiding this comment.
Looks really cool 🧇
I think the main thing is to have get_model on the modeling_session object and accept that workspace.get_model().get_source() will not work. Otherwise there are too many ways you can create issues and this also streamlines the design significantly.
I also wonder about the async vs sync websocket client connection, which might be good to take a look at.
| self, uri: URI, http_client: HTTPClient, ws_client: SyncWebSocketClient | ||
| ): | ||
| self._base_uri = uri | ||
| self._http_client = http_client |
There was a problem hiding this comment.
Not used and can be removed?
|
|
||
| [tool.poetry.dependencies] | ||
| python = "^3.8.0" | ||
| python = ">=3.9.0,<3.12.0" |
There was a problem hiding this comment.
I think the upper limit should be 4.0. Adding the 3.12 limit can cause a lot of issues for downstream tooling.
| def __del__(self) -> None: | ||
| if self._modeling_session is not None: | ||
| self._modeling_session.close_nowait() | ||
| self._modeling_session = None | ||
|
|
||
| def close(self) -> None: | ||
| """Close the modeling session WebSocket connection, if one was opened.""" | ||
| if self._modeling_session is not None: | ||
| self._modeling_session.close() | ||
| self._modeling_session = None | ||
|
|
||
| def __enter__(self) -> "Workspace": | ||
| return self | ||
|
|
||
| def __exit__(self, *args: object) -> None: | ||
| self.close() | ||
|
|
||
| def _get_modeling_session(self) -> ModelingSession: | ||
| if self._modeling_session is None: | ||
| modeling_service = self._sal.start_modeling_session(workspace_id=self.id) | ||
| self._modeling_session = ModelingSession( | ||
| modeling_service.id, self.id, modeling_service, self._sal | ||
| ) | ||
| return self._modeling_session |
There was a problem hiding this comment.
This machinery adds a lot of hidden state and makes it easy for a user to setup things so things becomes unstable. I think that we should drop it and accept that the get_model on workspace does not have full functionality. This seems pretty minor given the reduced complexity.
| ) | ||
|
|
||
| @Experimental | ||
| def get_parameters(self) -> List[str]: |
There was a problem hiding this comment.
Is this returning the parameter names? If we want to add things in the future (start value/nominals/...) it might we worth return list[ModelParameter] where ModelParameter have the attribute name.
| return self._modeling_sal.close_session_nowait() | ||
|
|
||
| @Experimental | ||
| def get_model_parmeters(self, modelica_path: str) -> List[str]: |
There was a problem hiding this comment.
Same here on list[str]. But should we even have these methods? I would have expected something like:
model_session.get_model(class_path).get_parameters()
model_session.get_model(class_path).get_source()
so we keep the API clean and give the user one way to do this.
| """Returns the libraries the package has dependencies on.""" | ||
| return self._info()["uses"] | ||
|
|
||
| def get_sub_models(self) -> List[Model]: |
There was a problem hiding this comment.
I don't think sub_models are a thing. I think this should just be called get_models.
|
|
||
| @Experimental | ||
| @contextmanager | ||
| def start_modeling_session(self) -> Generator["ModelingSession", None, None]: |
There was a problem hiding this comment.
start_modeling_session -> new_modeling_session might read a little nicer and match our other naming, but feel free to ignore this.
| _is_local_dev = ( | ||
| os.environ.get("IMPACT_PYTHON_CLIENT_DEV", "false").lower() == "true" | ||
| ) | ||
| scheme = "ws" if _is_local_dev else "wss" |
There was a problem hiding this comment.
Do we want to keep this in?
| self._conn = await websockets.connect( | ||
| self._uri, | ||
| additional_headers=headers, | ||
| ) # type: ignore |
There was a problem hiding this comment.
I might be missing something here but you are creating an async connection and then you want to wrap it in a sync API? I have not tested it, but could we not use websockets.sync.client.connect directly?
| "This Model instance has no modeling session. " | ||
| "Obtain the model via workspace.get_model() to enable get_parameters()." |
There was a problem hiding this comment.
Obtain the model via modeling_session.get_model, see workspace.new_model_session is what this would say.
This PR adds support for introspecting the Model source, Model parameters, Top level packages and recursively look into their subpackages/models.