Skip to content

feat: Streaming upload support #1779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 72 commits into from
Mar 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
3d55a42
Streaming upload support
mlkaplan36 Feb 25, 2025
a6d0d86
chore: adding changelog file 1779.added.md [dependabot-skip]
pyansys-ci-bot Feb 25, 2025
3e00f36
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Feb 25, 2025
9385ba2
Add support for streaming a file download
mlkaplan36 Feb 26, 2025
8c498ea
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Feb 26, 2025
5bf9eec
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Feb 26, 2025
cd8aa59
Use MAX_MESSAGE_LENGTH to determine chunk size
mlkaplan36 Feb 26, 2025
b2751b7
Add support for streaming tessellation
mlkaplan36 Feb 28, 2025
f66562c
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Feb 28, 2025
353851a
Adapt max message size to account for gRPC message overhead
mlkaplan36 Feb 28, 2025
d9c1c35
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Feb 28, 2025
87a5e51
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Feb 28, 2025
bb84ad0
Merge branch 'main' of https://github.com/ansys/pyansys-geometry into…
mlkaplan36 Mar 10, 2025
b827101
ci: simplify blitz ci
RobPasMue Mar 10, 2025
f86a444
chore: adding changelog file 1779.added.md [dependabot-skip]
pyansys-ci-bot Mar 10, 2025
75a4aab
Merge branch 'blitz' into feat/streaming_upload_support
mlkaplan36 Mar 10, 2025
a4edd7d
Merge branch 'blitz' of https://github.com/ansys/pyansys-geometry int…
mlkaplan36 Mar 10, 2025
17a18bc
Determine when to stream during an open_file command
mlkaplan36 Mar 10, 2025
df5165e
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 10, 2025
1ff650c
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 10, 2025
9f2766a
Fix precommit issues
mlkaplan36 Mar 10, 2025
55cabb4
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 10, 2025
8787ad6
Fix str file path issue
mlkaplan36 Mar 10, 2025
f4ccacd
MAX_MESSAGE_SIZE returns size in kb, not mb. Always provide the PATH …
mlkaplan36 Mar 10, 2025
d8810c9
Try/Except for streaming tessellation
mlkaplan36 Mar 10, 2025
3dc0d18
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 10, 2025
3c44dd8
Catch and raise GeometryExitedError
mlkaplan36 Mar 10, 2025
41990b5
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 10, 2025
e94b10f
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 10, 2025
7039876
fix: translating sketch issues when using a custom default unit (#1808)
RobPasMue Mar 10, 2025
f26f02c
feat: matrix helper methods (#1806)
umutsoysalansys Mar 11, 2025
179686b
fix: edge start and end were not being mapped correctly (#1816)
RobPasMue Mar 11, 2025
eaf99ea
Separate and implement tessellate_with_options (which supports stream…
mlkaplan36 Mar 12, 2025
f539952
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 12, 2025
7d46959
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 12, 2025
f6cebd6
Merge branch 'blitz' into feat/streaming_upload_support
mlkaplan36 Mar 12, 2025
e5cb09c
Add abstract method for "get_tessellation_with_options" + add default…
mlkaplan36 Mar 12, 2025
bc4db4d
Minor adjustments to formatting
mlkaplan36 Mar 12, 2025
ba83eab
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 12, 2025
6e1d0e7
ci: simplify blitz ci
RobPasMue Mar 10, 2025
c01276f
fix: translating sketch issues when using a custom default unit (#1808)
RobPasMue Mar 10, 2025
b10fb50
feat: matrix helper methods (#1806)
umutsoysalansys Mar 11, 2025
eb8b206
fix: edge start and end were not being mapped correctly (#1816)
RobPasMue Mar 11, 2025
9389ba5
ci: fix ci/cd
RobPasMue Mar 12, 2025
561a783
Replace tessellation() removed by merge mistake
mlkaplan36 Mar 12, 2025
844bb6f
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 12, 2025
3619657
Merge branch 'blitz' of https://github.com/ansys/pyansys-geometry int…
mlkaplan36 Mar 12, 2025
7d47684
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 12, 2025
f2e0b46
"catch Exception" allows for tessellation streaming to kick in the ev…
mlkaplan36 Mar 12, 2025
edfc103
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 12, 2025
b28443e
Merge branch 'blitz' of https://github.com/ansys/pyansys-geometry int…
mlkaplan36 Mar 13, 2025
845ac89
Combine tessellate calls into one method. Other minor suggested changes.
mlkaplan36 Mar 13, 2025
edcbdcc
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 13, 2025
3bfe5b0
Wrap the TessellationOptions in a class so as not to expose the under…
mlkaplan36 Mar 13, 2025
d94d485
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 13, 2025
f3cbf37
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 13, 2025
827273d
precommit fixes
mlkaplan36 Mar 14, 2025
a897120
Merge branch 'feat/streaming_upload_support' of https://github.com/an…
mlkaplan36 Mar 14, 2025
2d85a78
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 14, 2025
8a05c0b
Move TessellationOptions to options.py; minor renaming/reordering fixes.
mlkaplan36 Mar 14, 2025
c2f8b5a
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 14, 2025
f901e44
Missed import on commit
mlkaplan36 Mar 14, 2025
d7b8ecf
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Mar 14, 2025
a68b6be
Merge branch 'blitz' into feat/streaming_upload_support
RobPasMue Mar 14, 2025
c246f4d
Merge branch 'blitz' into feat/streaming_upload_support
RobPasMue Mar 14, 2025
d234530
Merge branch 'blitz' into feat/streaming_upload_support
RobPasMue Mar 14, 2025
4bf55d3
fix: reduce max message length for test and additional related mods
RobPasMue Mar 16, 2025
ce8aa03
fix: wrong indentation
RobPasMue Mar 16, 2025
ff381df
fix: remove default on fully private method
RobPasMue Mar 16, 2025
61413c5
fix: folder upload should be done properly - by evaluating each of th…
RobPasMue Mar 16, 2025
d043c95
fix: autohandle stream download when needed
RobPasMue Mar 16, 2025
e91856e
fix: cleanup protect_grpc usage
RobPasMue Mar 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changelog.d/1779.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Streaming upload support
6 changes: 1 addition & 5 deletions src/ansys/geometry/core/connection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@
trimmed_curve_to_grpc_trimmed_curve,
unit_vector_to_grpc_direction,
)
from ansys.geometry.core.connection.defaults import (
DEFAULT_HOST,
DEFAULT_PORT,
GEOMETRY_SERVICE_DOCKER_IMAGE,
)
import ansys.geometry.core.connection.defaults as defaults
from ansys.geometry.core.connection.docker_instance import (
GeometryContainers,
LocalDockerInstance,
Expand Down
10 changes: 5 additions & 5 deletions src/ansys/geometry/core/connection/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
)
from ansys.api.dbu.v0.admin_pb2_grpc import AdminStub
from ansys.geometry.core.connection.backend import BackendType
from ansys.geometry.core.connection.defaults import DEFAULT_HOST, DEFAULT_PORT, MAX_MESSAGE_LENGTH
import ansys.geometry.core.connection.defaults as pygeom_defaults
from ansys.geometry.core.connection.docker_instance import LocalDockerInstance
from ansys.geometry.core.connection.product_instance import ProductInstance
from ansys.geometry.core.logger import LOG, PyGeometryCustomAdapter
Expand Down Expand Up @@ -158,8 +158,8 @@ class GrpcClient:
@check_input_types
def __init__(
self,
host: str = DEFAULT_HOST,
port: str | int = DEFAULT_PORT,
host: str = pygeom_defaults.DEFAULT_HOST,
port: str | int = pygeom_defaults.DEFAULT_PORT,
channel: grpc.Channel | None = None,
remote_instance: Optional["Instance"] = None,
docker_instance: LocalDockerInstance | None = None,
Expand All @@ -183,8 +183,8 @@ def __init__(
self._channel = grpc.insecure_channel(
self._target,
options=[
("grpc.max_receive_message_length", MAX_MESSAGE_LENGTH),
("grpc.max_send_message_length", MAX_MESSAGE_LENGTH),
("grpc.max_receive_message_length", pygeom_defaults.MAX_MESSAGE_LENGTH),
("grpc.max_send_message_length", pygeom_defaults.MAX_MESSAGE_LENGTH),
],
)

Expand Down
13 changes: 8 additions & 5 deletions src/ansys/geometry/core/connection/docker_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
except ModuleNotFoundError: # pragma: no cover
_HAS_DOCKER = False

from ansys.geometry.core.connection.defaults import DEFAULT_PORT, GEOMETRY_SERVICE_DOCKER_IMAGE
import ansys.geometry.core.connection.defaults as pygeom_defaults
from ansys.geometry.core.logger import LOG


Expand Down Expand Up @@ -157,7 +157,7 @@ def is_docker_installed() -> bool:
@_docker_python_available
def __init__(
self,
port: int = DEFAULT_PORT,
port: int = pygeom_defaults.DEFAULT_PORT,
connect_to_existing_service: bool = True,
restart_if_existing_service: bool = False,
name: str | None = None,
Expand Down Expand Up @@ -234,7 +234,10 @@ def _is_cont_geom_service(self, cont: "Container") -> bool:
# If one of the tags matches a Geometry service tag --> Return True
for tag in cont.image.tags:
for geom_services in GeometryContainers:
if tag == f"{GEOMETRY_SERVICE_DOCKER_IMAGE}:{geom_services.value[2]}":
if (
tag
== f"{pygeom_defaults.GEOMETRY_SERVICE_DOCKER_IMAGE}:{geom_services.value[2]}"
):
return True

# If you have reached this point, the image is not a Geometry service
Expand Down Expand Up @@ -290,7 +293,7 @@ def _deploy_container(self, port: int, name: str | None, image: GeometryContaine
# Try to deploy it
try:
container: Container = self.docker_client().containers.run(
image=f"{GEOMETRY_SERVICE_DOCKER_IMAGE}:{image.value[2]}",
image=f"{pygeom_defaults.GEOMETRY_SERVICE_DOCKER_IMAGE}:{image.value[2]}",
detach=True,
auto_remove=True,
name=name,
Expand Down Expand Up @@ -350,7 +353,7 @@ def get_geometry_container_type(instance: LocalDockerInstance) -> GeometryContai
"""
for tag in instance.container.image.tags:
for geom_services in GeometryContainers:
if tag == f"{GEOMETRY_SERVICE_DOCKER_IMAGE}:{geom_services.value[2]}":
if tag == f"{pygeom_defaults.GEOMETRY_SERVICE_DOCKER_IMAGE}:{geom_services.value[2]}":
return geom_services

return None
9 changes: 4 additions & 5 deletions src/ansys/geometry/core/connection/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
from typing import TYPE_CHECKING

from ansys.geometry.core.connection.backend import ApiVersions, BackendType
from ansys.geometry.core.connection.client import MAX_MESSAGE_LENGTH
from ansys.geometry.core.connection.defaults import DEFAULT_PIM_CONFIG, DEFAULT_PORT
import ansys.geometry.core.connection.defaults as pygeom_defaults
from ansys.geometry.core.connection.docker_instance import (
_HAS_DOCKER,
GeometryContainers,
Expand Down Expand Up @@ -290,7 +289,7 @@ def launch_remote_modeler(


def launch_docker_modeler(
port: int = DEFAULT_PORT,
port: int = pygeom_defaults.DEFAULT_PORT,
connect_to_existing_service: bool = True,
restart_if_existing_service: bool = False,
name: str | None = None,
Expand Down Expand Up @@ -958,7 +957,7 @@ def _launch_pim_instance(

# If PIM Light is being used and PyPIM configuration is not defined... use defaults.
if is_pim_light and not os.environ.get("ANSYS_PLATFORM_INSTANCEMANAGEMENT_CONFIG", None):
os.environ["ANSYS_PLATFORM_INSTANCEMANAGEMENT_CONFIG"] = DEFAULT_PIM_CONFIG
os.environ["ANSYS_PLATFORM_INSTANCEMANAGEMENT_CONFIG"] = pygeom_defaults.DEFAULT_PIM_CONFIG
pop_out = True
else:
pop_out = False
Expand All @@ -969,7 +968,7 @@ def _launch_pim_instance(
instance.wait_for_ready()
channel = instance.build_grpc_channel(
options=[
("grpc.max_receive_message_length", MAX_MESSAGE_LENGTH),
("grpc.max_receive_message_length", pygeom_defaults.MAX_MESSAGE_LENGTH),
]
)

Expand Down
64 changes: 55 additions & 9 deletions src/ansys/geometry/core/designer/body.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
BooleanRequest,
CopyRequest,
GetCollisionRequest,
GetTessellationRequest,
MapRequest,
MirrorRequest,
RotateRequest,
Expand All @@ -59,6 +60,7 @@
ShellRequest,
)
from ansys.api.geometry.v0.commands_pb2_grpc import CommandsStub
from ansys.api.geometry.v0.models_pb2 import TessellationOptions as GRPCTessellationOptions
from ansys.geometry.core.connection.client import GrpcClient
from ansys.geometry.core.connection.conversions import (
frame_to_grpc_frame,
Expand Down Expand Up @@ -96,6 +98,7 @@
min_backend_version,
)
from ansys.geometry.core.misc.measurements import DEFAULT_UNITS, Angle, Distance
from ansys.geometry.core.misc.options import TessellationOptions
from ansys.geometry.core.shapes.curves.trimmed_curve import TrimmedCurve
from ansys.geometry.core.sketch.sketch import Sketch
from ansys.geometry.core.typing import Real
Expand Down Expand Up @@ -564,7 +567,9 @@ def copy(self, parent: "Component", name: str = None) -> "Body":
return

@abstractmethod
def tessellate(self, merge: bool = False) -> Union["PolyData", "MultiBlock"]:
def tessellate(
self, merge: bool = False, tessellation_options: TessellationOptions = None
) -> Union["PolyData", "MultiBlock"]:
"""Tessellate the body and return the geometry as triangles.

Parameters
Expand All @@ -573,6 +578,8 @@ def tessellate(self, merge: bool = False) -> Union["PolyData", "MultiBlock"]:
Whether to merge the body into a single mesh. When ``False`` (default), the
number of triangles are preserved and only the topology is merged.
When ``True``, the individual faces of the tessellation are merged.
tessellation_options : TessellationOptions, default: None
A set of options to determine the tessellation quality.

Returns
-------
Expand Down Expand Up @@ -1266,7 +1273,10 @@ def copy(self, parent: "Component", name: str = None) -> "Body": # noqa: D102
@protect_grpc
@graphics_required
def tessellate( # noqa: D102
self, merge: bool = False, transform: Matrix44 = IDENTITY_MATRIX44
self,
merge: bool = False,
transform: Matrix44 = IDENTITY_MATRIX44,
tess_options: TessellationOptions = None,
) -> Union["PolyData", "MultiBlock"]:
# lazy import here to improve initial module load time
import pyvista as pv
Expand All @@ -1278,11 +1288,45 @@ def tessellate( # noqa: D102

# cache tessellation
if not self._tessellation:
resp = self._bodies_stub.GetTessellation(self._grpc_id)
self._tessellation = {
str(face_id): tess_to_pd(face_tess)
for face_id, face_tess in resp.face_tessellation.items()
}
if tess_options is not None:
request = GetTessellationRequest(
id=self._grpc_id,
options=GRPCTessellationOptions(
surface_deviation=tess_options.surface_deviation,
angle_deviation=tess_options.angle_deviation,
maximum_aspect_ratio=tess_options.max_aspect_ratio,
maximum_edge_length=tess_options.max_edge_length,
watertight=tess_options.watertight,
),
)
try:
resp = self._bodies_stub.GetTessellationWithOptions(request)
self._tessellation = {
str(face_id): tess_to_pd(face_tess)
for face_id, face_tess in resp.face_tessellation.items()
}
except Exception:
tessellation_map = {}
for response in self._bodies_stub.GetTessellationStream(request):
for key, value in response.face_tessellation.items():
tessellation_map[key] = tess_to_pd(value)

self._tessellation = tessellation_map
else:
try:
resp = self._bodies_stub.GetTessellation(self._grpc_id)
self._tessellation = {
str(face_id): tess_to_pd(face_tess)
for face_id, face_tess in resp.face_tessellation.items()
}
except Exception:
tessellation_map = {}
request = GetTessellationRequest(self._grpc_id)
for response in self._bodies_stub.GetTessellationStream(request):
for key, value in response.face_tessellation.items():
tessellation_map[key] = tess_to_pd(value)

self._tessellation = tessellation_map

pdata = [tess.transform(transform, inplace=False) for tess in self._tessellation.values()]
comp = pv.MultiBlock(pdata)
Expand Down Expand Up @@ -1810,9 +1854,11 @@ def copy(self, parent: "Component", name: str = None) -> "Body": # noqa: D102

@ensure_design_is_active
def tessellate( # noqa: D102
self, merge: bool = False
self, merge: bool = False, tess_options: TessellationOptions = None
) -> Union["PolyData", "MultiBlock"]:
return self._template.tessellate(merge, self.parent_component.get_world_transform())
return self._template.tessellate(
merge, self.parent_component.get_world_transform(), tess_options
)

@ensure_design_is_active
def shell_body(self, offset: Real) -> bool: # noqa: D102
Expand Down
35 changes: 21 additions & 14 deletions src/ansys/geometry/core/designer/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,7 @@ def download(
file_location.write_bytes(received_bytes)
self._grpc_client.log.debug(f"Design downloaded at location {file_location}.")

def __export_and_download_legacy(
self,
format: DesignFileFormat = DesignFileFormat.SCDOCX,
) -> bytes:
def __export_and_download_legacy(self, format: DesignFileFormat) -> bytes:
"""Export and download the design from the server.

Notes
Expand All @@ -339,7 +336,7 @@ def __export_and_download_legacy(

Parameters
----------
format : DesignFileFormat, default: DesignFileFormat.SCDOCX
format : DesignFileFormat
Format for the file to save to.

Returns
Expand Down Expand Up @@ -371,15 +368,12 @@ def __export_and_download_legacy(

return received_bytes

def __export_and_download(
self,
format: DesignFileFormat = DesignFileFormat.SCDOCX,
) -> bytes:
def __export_and_download(self, format: DesignFileFormat) -> bytes:
"""Export and download the design from the server.

Parameters
----------
format : DesignFileFormat, default: DesignFileFormat.SCDOCX
format : DesignFileFormat
Format for the file to save to.

Returns
Expand All @@ -402,10 +396,23 @@ def __export_and_download(
DesignFileFormat.SCDOCX,
DesignFileFormat.STRIDE,
]:
response = self._design_stub.DownloadExportFile(
DownloadExportFileRequest(format=format.value[1])
)
received_bytes += response.data
try:
response = self._design_stub.DownloadExportFile(
DownloadExportFileRequest(format=format.value[1])
)
received_bytes += response.data
except Exception:
self._grpc_client.log.warning(
f"Failed to download the file in {format.value[0]} format."
" Attempting to stream download."
)
# Attempt to download the file via streaming
received_bytes = bytes()
responses = self._design_stub.StreamDownloadExportFile(
DownloadExportFileRequest(format=format.value[1])
)
for response in responses:
received_bytes += response.data
else:
self._grpc_client.log.warning(
f"{format.value[0]} format requested is not supported. Ignoring download request."
Expand Down
Loading
Loading