Skip to content

Commit 0a03f69

Browse files
authored
Allow marking 'supported_since' on class level (#604)
Add a `_SUPPORTED_SINCE` class attribute to the `GrpcObjectBase` class, which has two effects: - upon storing an object, check the server version and raise an appropriate exception if the server version is too low - in the `mark_grpc_properties` class decorator, add a line at the end of the class docstring indicating the server version at which the class was introduced On all existing classes, the `_SUPPORTED_SINCE` attribute is set to `"24.2"`.
1 parent bc6aa18 commit 0a03f69

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+107
-3
lines changed

src/ansys/acp/core/_server/direct.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import dataclasses
2424
import os
25+
import pathlib
2526
import subprocess
2627
from typing import TextIO
2728

@@ -103,6 +104,10 @@ def start(self) -> None:
103104
stdout_file = self._config.stdout_file
104105
stderr_file = self._config.stderr_file
105106

107+
binary = pathlib.Path(self._config.binary_path)
108+
if not binary.exists():
109+
raise FileNotFoundError(f"Binary not found: '{binary}'")
110+
106111
port = find_free_ports()[0]
107112
self._url = f"localhost:{port}"
108113
self._stdout = open(stdout_file, mode="w", encoding="utf-8")

src/ansys/acp/core/_tree_objects/_grpc_helpers/mapping.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from typing import Any, Concatenate, Generic, TypeVar
2727

2828
from grpc import Channel
29+
from packaging.version import parse as parse_version
2930
from typing_extensions import ParamSpec, Self
3031

3132
from ansys.api.acp.v0.base_pb2 import CollectionPath, DeleteRequest, ListRequest
@@ -302,6 +303,14 @@ def define_mutable_mapping(
302303
"""Define a mutable mapping of child tree objects."""
303304

304305
def collection_property(self: ParentT) -> MutableMapping[CreatableValueT]:
306+
if self._server_version is not None:
307+
if self._server_version < parse_version(object_class._SUPPORTED_SINCE):
308+
raise RuntimeError(
309+
f"The '{object_class.__name__}' object is only supported since version "
310+
f"{object_class._SUPPORTED_SINCE} of the ACP gRPC server. The current server version is "
311+
f"{self._server_version}."
312+
)
313+
305314
return MutableMapping._initialize_with_cache(
306315
server_wrapper=self._server_wrapper,
307316
collection_path=CollectionPath(

src/ansys/acp/core/_tree_objects/_grpc_helpers/property_helper.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from collections.abc import Callable
3131
from functools import reduce
32+
import sys
3233
from typing import TYPE_CHECKING, Any, TypeVar
3334

3435
from google.protobuf.message import Message
@@ -91,6 +92,27 @@ def mark_grpc_properties(cls: T) -> T:
9192
if name not in props_unique:
9293
props_unique.append(name)
9394
cls._GRPC_PROPERTIES = tuple(props_unique)
95+
96+
# The 'mark_grpc_properties' decorator is also used on intermediate base
97+
# classes which do not have the '_SUPPORTED_SINCE' attribute. We only want
98+
# to add the version information to the final class.
99+
if hasattr(cls, "_SUPPORTED_SINCE"):
100+
if isinstance(cls.__doc__, str):
101+
# When adding to the docstring, we need to match the existing
102+
# indentation of the docstring (except the first line).
103+
# See PEP 257 'Handling Docstring Indentation'.
104+
# Alternatively, we could strip the common indentation from the
105+
# docstring.
106+
indent = sys.maxsize
107+
for line in cls.__doc__.splitlines()[1:]:
108+
stripped = line.lstrip()
109+
if stripped: # ignore empty lines
110+
indent = min(indent, len(line) - len(stripped))
111+
if indent == sys.maxsize:
112+
indent = 0
113+
cls.__doc__ += (
114+
f"\n\n{indent * ' '}*Added in ACP server version {cls._SUPPORTED_SINCE}.*\n"
115+
)
94116
return cls
95117

96118

src/ansys/acp/core/_tree_objects/_grpc_helpers/protocols.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class GrpcObjectBase(Protocol):
151151

152152
__slots__: Iterable[str] = tuple()
153153
_GRPC_PROPERTIES: tuple[str, ...] = tuple()
154+
_SUPPORTED_SINCE: str
154155

155156
def __str__(self) -> str:
156157
string_items = []

src/ansys/acp/core/_tree_objects/_grpc_helpers/supported_since.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ def supported_since(
4545
4646
Parameters
4747
----------
48-
version : Optional[str]
48+
version :
4949
The server version since which the method is supported. If ``None``, the
5050
decorator does nothing.
51-
err_msg_tpl : Optional[str]
51+
err_msg_tpl :
5252
A custom error message template. If ``None``, a default error message is used.
5353
"""
5454
if version is None:
@@ -69,7 +69,7 @@ def inner(self: T, /, *args: P.args, **kwargs: P.kwargs) -> R:
6969
if server_version < required_version:
7070
if err_msg_tpl is None:
7171
err_msg = (
72-
f"The method '{func.__name__}' is only supported since version {version} "
72+
f"The '{func.__name__}' method is only supported since version {version} "
7373
f"of the ACP gRPC server. The current server version is {server_version}."
7474
)
7575
else:

src/ansys/acp/core/_tree_objects/analysis_ply.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class AnalysisPly(ReadOnlyTreeObject, IdTreeObject):
105105

106106
_COLLECTION_LABEL = "analysis_plies"
107107
_OBJECT_INFO_TYPE = analysis_ply_pb2.ObjectInfo
108+
_SUPPORTED_SINCE = "24.2"
108109

109110
def _create_stub(self) -> analysis_ply_pb2_grpc.ObjectServiceStub:
110111
return analysis_ply_pb2_grpc.ObjectServiceStub(self._channel)

src/ansys/acp/core/_tree_objects/base.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class TreeObjectBase(ObjectCacheMixin, GrpcObjectBase):
7676

7777
_COLLECTION_LABEL: str
7878
_OBJECT_INFO_TYPE: type[ObjectInfo]
79+
_SUPPORTED_SINCE: str
7980

8081
_pb_object: ObjectInfo
8182
name: ReadOnlyProperty[str]
@@ -328,6 +329,13 @@ def store(self: Self, parent: TreeObject) -> None:
328329
Parent object to store the object under.
329330
"""
330331
self._server_wrapper_store = parent._server_wrapper
332+
assert self._server_version is not None
333+
if self._server_version < parse_version(self._SUPPORTED_SINCE):
334+
raise RuntimeError(
335+
f"The '{type(self).__name__}' object is only supported since version "
336+
f"{self._SUPPORTED_SINCE} of the ACP gRPC server. The current server version is "
337+
f"{self._server_version}."
338+
)
331339

332340
collection_path = CollectionPath(
333341
value=_rp_join(parent._resource_path.value, self._COLLECTION_LABEL)

src/ansys/acp/core/_tree_objects/boolean_selection_rule.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class BooleanSelectionRule(CreatableTreeObject, IdTreeObject):
9191
_COLLECTION_LABEL = "boolean_selection_rules"
9292
_OBJECT_INFO_TYPE = boolean_selection_rule_pb2.ObjectInfo
9393
_CREATE_REQUEST_TYPE = boolean_selection_rule_pb2.CreateRequest
94+
_SUPPORTED_SINCE = "24.2"
9495

9596
def __init__(
9697
self,

src/ansys/acp/core/_tree_objects/cad_component.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class CADComponent(ReadOnlyTreeObject, IdTreeObject):
4949
__slots__: Iterable[str] = tuple()
5050
_COLLECTION_LABEL = "cad_components"
5151
_OBJECT_INFO_TYPE = cad_component_pb2.ObjectInfo
52+
_SUPPORTED_SINCE = "24.2"
5253

5354
def _create_stub(self) -> cad_component_pb2_grpc.ObjectServiceStub:
5455
return cad_component_pb2_grpc.ObjectServiceStub(self._channel)

src/ansys/acp/core/_tree_objects/cad_geometry.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class CADGeometry(CreatableTreeObject, IdTreeObject):
108108
_COLLECTION_LABEL = "cad_geometries"
109109
_OBJECT_INFO_TYPE = cad_geometry_pb2.ObjectInfo
110110
_CREATE_REQUEST_TYPE = cad_geometry_pb2.CreateRequest
111+
_SUPPORTED_SINCE = "24.2"
111112

112113
def __init__(
113114
self,

0 commit comments

Comments
 (0)