Skip to content

Commit 7e07357

Browse files
jonahrbRobPasMuedastan-ansys
authored
FEAT: upload and open a file (#390)
Co-authored-by: Roberto Pastor Muela <37798125+RobPasMue@users.noreply.github.com> Co-authored-by: Dastan Abdulla <dastan.abdulla@ansys.com> Co-authored-by: dastan-ansys <132925889+dastan-ansys@users.noreply.github.com>
1 parent 3c2c4fa commit 7e07357

File tree

3 files changed

+131
-1
lines changed

3 files changed

+131
-1
lines changed

src/ansys/geometry/core/modeler.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import logging
33
from pathlib import Path
44

5+
from ansys.api.geometry.v0.commands_pb2 import UploadFileRequest
6+
from ansys.api.geometry.v0.commands_pb2_grpc import CommandsStub
57
from beartype.typing import TYPE_CHECKING, Optional, Union
68
from grpc import Channel
79

@@ -118,6 +120,63 @@ def close(self) -> None:
118120
"""``Modeler`` easy-access method to the client's close method."""
119121
return self.client.close()
120122

123+
def _upload_file(self, file_path: str, open_file: bool = False) -> str:
124+
"""
125+
Upload a file from the client to the server. ``file_path`` must include the extension.
126+
127+
The new file created on the server will have the same name and extension.
128+
129+
Parameters
130+
----------
131+
file_path : str
132+
The path of the file. Must include extension.
133+
open_file : bool
134+
Open the file in the Geometry Service.
135+
136+
Returns
137+
-------
138+
file_path : str
139+
The full path of the uploaded file on the server machine.
140+
"""
141+
import os
142+
143+
if not os.path.exists(file_path):
144+
raise ValueError(f"Could not find file: {file_path}")
145+
if os.path.isdir(file_path):
146+
raise ValueError("File path must lead to a file, not a directory.")
147+
148+
file_name = os.path.split(file_path)[1]
149+
150+
with open(file_path, "rb") as file:
151+
data = file.read()
152+
153+
c_stub = CommandsStub(self._client.channel)
154+
155+
response = c_stub.UploadFile(
156+
UploadFileRequest(data=data, file_name=file_name, open=open_file)
157+
)
158+
return response.file_path
159+
160+
def open_file(self, file_path: str) -> "Design":
161+
"""
162+
Open a file. ``file_path`` must include the extension.
163+
164+
This imports a design into the service. On Windows, `.scdocx` and HOOPS Exchange formats
165+
are supported. On Linux, only `.scdocx` is supported.
166+
167+
Parameters
168+
----------
169+
file_path : str
170+
The path of the file. Must include extension.
171+
172+
Returns
173+
-------
174+
Design
175+
The newly imported design.
176+
"""
177+
self._upload_file(file_path, True)
178+
return self.read_existing_design()
179+
121180
def __repr__(self) -> str:
122181
"""Represent the modeler as a string."""
123182
lines = []

tests/integration/test_design.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Test design interaction."""
22

3+
import os
4+
35
import numpy as np
46
from pint import Quantity
57
import pytest
@@ -817,6 +819,22 @@ def test_download_file(
817819
assert fmd_file.exists()
818820

819821

822+
def test_upload_file(modeler: Modeler, tmp_path_factory: pytest.TempPathFactory):
823+
"""Test uploading a file to the server."""
824+
file = tmp_path_factory.mktemp("test_design") / "upload_example.scdocx"
825+
file_size = 1024
826+
827+
# Write random bytes
828+
with open(file, "wb") as fout:
829+
fout.write(os.urandom(file_size))
830+
831+
assert file.exists()
832+
833+
# Upload file
834+
path_on_server = modeler._upload_file(file)
835+
assert path_on_server is not None
836+
837+
820838
def test_slot_extrusion(modeler: Modeler):
821839
"""Test the extrusion of a slot."""
822840
# Create your design on the server side

tests/integration/test_design_import.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Test design import."""
22

3+
import numpy as np
34
from pint import Quantity
5+
import pytest
46

57
from ansys.geometry.core import Modeler
68
from ansys.geometry.core.designer import Component, Design
7-
from ansys.geometry.core.math import Point2D
9+
from ansys.geometry.core.math import Plane, Point2D, Point3D, UnitVector3D, Vector3D
810
from ansys.geometry.core.misc import UNITS
911
from ansys.geometry.core.sketch import Sketch
1012

@@ -89,3 +91,54 @@ def test_design_import_simple_case(modeler: Modeler):
8991

9092
# Check the design
9193
_checker_method(read_design, design)
94+
95+
96+
def test_open_file(modeler: Modeler, tmp_path_factory: pytest.TempPathFactory):
97+
"""Test creation of a component, saving it to a file, and loading it again to a
98+
second component and make sure they have the same properties."""
99+
100+
design_name = "CarDesign_Test"
101+
design = modeler.create_design(design_name)
102+
103+
# Create a car
104+
car1 = design.add_component("Car1")
105+
comp1 = car1.add_component("A")
106+
comp2 = car1.add_component("B")
107+
wheel1 = comp2.add_component("Wheel1")
108+
109+
# Create car base frame
110+
sketch = Sketch().box(Point2D([5, 10]), 10, 20)
111+
comp2.extrude_sketch("Base", sketch, 5)
112+
113+
# Create first wheel
114+
sketch = Sketch(Plane(direction_x=Vector3D([0, 1, 0]), direction_y=Vector3D([0, 0, 1])))
115+
sketch.circle(Point2D([0, 0]), 5)
116+
wheel1.extrude_sketch("Wheel", sketch, -5)
117+
118+
# Create 3 other wheels and move them into position
119+
rotation_origin = Point3D([0, 0, 0])
120+
rotation_direction = UnitVector3D([0, 0, 1])
121+
122+
wheel2 = comp2.add_component("Wheel2", wheel1)
123+
wheel2.modify_placement(Vector3D([0, 20, 0]))
124+
125+
wheel3 = comp2.add_component("Wheel3", wheel1)
126+
wheel3.modify_placement(Vector3D([10, 0, 0]), rotation_origin, rotation_direction, np.pi)
127+
128+
wheel4 = comp2.add_component("Wheel4", wheel1)
129+
wheel4.modify_placement(Vector3D([10, 20, 0]), rotation_origin, rotation_direction, np.pi)
130+
131+
# Create 2nd car
132+
car2 = design.add_component("Car2", car1)
133+
car2.modify_placement(Vector3D([30, 0, 0]))
134+
135+
# Create top of car - applies to BOTH cars
136+
sketch = Sketch(Plane(Point3D([0, 5, 5]))).box(Point2D([5, 2.5]), 10, 5)
137+
comp1.extrude_sketch("Top", sketch, 5)
138+
139+
file = tmp_path_factory.mktemp("test_design_import") / "two_cars.scdocx"
140+
design.download(file)
141+
design2 = modeler.open_file(file)
142+
143+
# assert the two cars are the same
144+
_checker_method(design, design2)

0 commit comments

Comments
 (0)