Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/2188.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Prevent tool and command classes instantiation outside of modeler object
23 changes: 21 additions & 2 deletions src/ansys/geometry/core/designer/geometry_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
TangentCondition,
)
from ansys.geometry.core.designer.selection import NamedSelection
from ansys.geometry.core.errors import protect_grpc
from ansys.geometry.core.errors import GeometryRuntimeError, protect_grpc
from ansys.geometry.core.math.plane import Plane
from ansys.geometry.core.math.point import Point3D
from ansys.geometry.core.math.vector import UnitVector3D
Expand Down Expand Up @@ -135,11 +135,30 @@ class GeometryCommands:
----------
grpc_client : GrpcClient
gRPC client to use for the geometry commands.
_internal_use : bool, optional
Internal flag to prevent direct instantiation by users.
This parameter is for internal use only.

Raises
------
GeometryRuntimeError
If the class is instantiated directly by users instead
of through the modeler.

Notes
-----
This class should not be instantiated directly. Use
``modeler.geometry_commands`` instead.
"""

@protect_grpc
def __init__(self, grpc_client: GrpcClient):
def __init__(self, grpc_client: GrpcClient, _internal_use: bool = False):
"""Initialize an instance of the ``GeometryCommands`` class."""
if not _internal_use:
raise GeometryRuntimeError(
"GeometryCommands should not be instantiated directly. "
"Use 'modeler.geometry_commands' to access geometry commands."
)
self._grpc_client = grpc_client
self._commands_stub = CommandsStub(self._grpc_client.channel)

Expand Down
10 changes: 5 additions & 5 deletions src/ansys/geometry/core/modeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ def __init__(
self._design: Optional["Design"] = None

# Enabling tools/commands for all: repair and prepare tools, geometry commands
self._measurement_tools = MeasurementTools(self._grpc_client)
self._repair_tools = RepairTools(self._grpc_client, self)
self._prepare_tools = PrepareTools(self._grpc_client)
self._geometry_commands = GeometryCommands(self._grpc_client)
self._unsupported = UnsupportedCommands(self._grpc_client, self)
self._measurement_tools = MeasurementTools(self._grpc_client, _internal_use=True)
self._repair_tools = RepairTools(self._grpc_client, self, _internal_use=True)
self._prepare_tools = PrepareTools(self._grpc_client, _internal_use=True)
self._geometry_commands = GeometryCommands(self._grpc_client, _internal_use=True)
self._unsupported = UnsupportedCommands(self._grpc_client, self, _internal_use=True)

@property
def client(self) -> GrpcClient:
Expand Down
21 changes: 20 additions & 1 deletion src/ansys/geometry/core/tools/measurement_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,29 @@ class MeasurementTools:
----------
grpc_client : GrpcClient
gRPC client to use for the measurement tools.
_internal_use : bool, optional
Internal flag to prevent direct instantiation by users.
This parameter is for internal use only.

Raises
------
GeometryRuntimeError
If the class is instantiated directly by users instead
of through the modeler.

Notes
-----
This class should not be instantiated directly. Use
``modeler.measurement_tools`` instead.
"""

def __init__(self, grpc_client: GrpcClient):
def __init__(self, grpc_client: GrpcClient, _internal_use: bool = False):
"""Initialize measurement tools class."""
if not _internal_use:
raise GeometryRuntimeError(
"MeasurementTools should not be instantiated directly. "
"Use 'modeler.measurement_tools' to access measurement tools."
)
self._grpc_client = grpc_client

@min_backend_version(24, 2, 0)
Expand Down
21 changes: 20 additions & 1 deletion src/ansys/geometry/core/tools/prepare_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from ansys.geometry.core.connection import GrpcClient
from ansys.geometry.core.connection.backend import BackendType
from ansys.geometry.core.errors import GeometryRuntimeError
from ansys.geometry.core.logger import LOG
from ansys.geometry.core.misc.auxiliary import (
get_bodies_from_ids,
Expand All @@ -51,10 +52,28 @@ class PrepareTools:
----------
grpc_client : GrpcClient
Active supporting geometry service instance for design modeling.
_internal_use : bool, optional
Internal flag to prevent direct instantiation by users.
This parameter is for internal use only.

Raises
------
GeometryRuntimeError
If the class is instantiated directly by users instead of through the modeler.

Notes
-----
This class should not be instantiated directly. Use
``modeler.prepare_tools`` instead.
"""

def __init__(self, grpc_client: GrpcClient):
def __init__(self, grpc_client: GrpcClient, _internal_use: bool = False):
"""Initialize Prepare Tools class."""
if not _internal_use:
raise GeometryRuntimeError(
"PrepareTools should not be instantiated directly. "
"Use 'modeler.prepare_tools' to access prepare tools."
)
self._grpc_client = grpc_client

@min_backend_version(25, 1, 0)
Expand Down
34 changes: 31 additions & 3 deletions src/ansys/geometry/core/tools/repair_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import ansys.geometry.core as pyansys_geometry
from ansys.geometry.core.connection import GrpcClient
from ansys.geometry.core.errors import GeometryRuntimeError
from ansys.geometry.core.misc.auxiliary import (
get_bodies_from_ids,
get_design_from_body,
Expand Down Expand Up @@ -61,10 +62,37 @@


class RepairTools:
"""Repair tools for PyAnsys Geometry."""

def __init__(self, grpc_client: GrpcClient, modeler: "Modeler"):
"""Repair tools for PyAnsys Geometry.

Parameters
----------
grpc_client : GrpcClient
Active supporting geometry service instance for design modeling.
modeler : Modeler
The parent modeler instance.
_internal_use : bool, optional
Internal flag to prevent direct instantiation by users.
This parameter is for internal use only.

Raises
------
GeometryRuntimeError
If the class is instantiated directly by users instead
of through the modeler.

Notes
-----
This class should not be instantiated directly. Use
``modeler.repair_tools`` instead.
"""

def __init__(self, grpc_client: GrpcClient, modeler: "Modeler", _internal_use: bool = False):
"""Initialize a new instance of the ``RepairTools`` class."""
if not _internal_use:
raise GeometryRuntimeError(
"RepairTools should not be instantiated directly. "
"Use 'modeler.repair_tools' to access repair tools."
)
self._modeler = modeler
self._grpc_client = grpc_client

Expand Down
23 changes: 21 additions & 2 deletions src/ansys/geometry/core/tools/unsupported.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)
from ansys.api.geometry.v0.unsupported_pb2_grpc import UnsupportedStub
from ansys.geometry.core.connection import GrpcClient
from ansys.geometry.core.errors import protect_grpc
from ansys.geometry.core.errors import GeometryRuntimeError, protect_grpc
from ansys.geometry.core.misc.auxiliary import get_all_bodies_from_design
from ansys.geometry.core.misc.checks import (
min_backend_version,
Expand Down Expand Up @@ -72,10 +72,29 @@ class UnsupportedCommands:
gRPC client to use for the geometry commands.
modeler : Modeler
Modeler instance to use for the geometry commands.
_internal_use : bool, optional
Internal flag to prevent direct instantiation by users.
This parameter is for internal use only.

Raises
------
GeometryRuntimeError
If the class is instantiated directly by users instead of through the modeler.

Notes
-----
This class should not be instantiated directly. Use
``modeler.unsupported`` instead.

"""

def __init__(self, grpc_client: GrpcClient, modeler: "Modeler"):
def __init__(self, grpc_client: GrpcClient, modeler: "Modeler", _internal_use: bool = False):
"""Initialize an instance of the ``UnsupportedCommands`` class."""
if not _internal_use:
raise GeometryRuntimeError(
"UnsupportedCommands should not be instantiated directly. "
"Use 'modeler.unsupported' to access unsupported commands."
)
self._grpc_client = grpc_client
self._unsupported_stub = UnsupportedStub(self._grpc_client.channel)
self.__id_map = {}
Expand Down
46 changes: 46 additions & 0 deletions tests/integration/test_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
from pathlib import Path

import numpy as np
import pytest

from ansys.geometry.core.designer.geometry_commands import GeometryCommands
from ansys.geometry.core.errors import GeometryRuntimeError
from ansys.geometry.core.math import (
UNITVECTOR3D_X,
UNITVECTOR3D_Y,
Expand All @@ -37,6 +40,12 @@
from ansys.geometry.core.misc import DEFAULT_UNITS, UNITS, Angle, Distance
from ansys.geometry.core.modeler import Modeler
from ansys.geometry.core.sketch import Sketch
from ansys.geometry.core.tools import (
MeasurementTools,
PrepareTools,
RepairTools,
UnsupportedCommands,
)

from .conftest import FILES_DIR

Expand Down Expand Up @@ -325,3 +334,40 @@ def test_issue_1813_edge_start_end_non_default_units(modeler: Modeler):
finally:
# Reset the default units to meters
DEFAULT_UNITS.LENGTH = UNITS.meter


def test_issue_2184_prevent_raw_instantiation_of_tools_and_commands():
"""Test that raw instantiation of tools and commands is prevented.

For more info see
https://github.com/ansys/pyansys-geometry/issues/2184
"""
# Test UnsupportedCommands
with pytest.raises(
GeometryRuntimeError, match="UnsupportedCommands should not be instantiated directly"
):
UnsupportedCommands(None, None)

# Test RepairTools
with pytest.raises(
GeometryRuntimeError, match="RepairTools should not be instantiated directly"
):
RepairTools(None, None)

# Test PrepareTools
with pytest.raises(
GeometryRuntimeError, match="PrepareTools should not be instantiated directly"
):
PrepareTools(None)

# Test MeasurementTools
with pytest.raises(
GeometryRuntimeError, match="MeasurementTools should not be instantiated directly"
):
MeasurementTools(None)

# Test GeometryCommands
with pytest.raises(
GeometryRuntimeError, match="GeometryCommands should not be instantiated directly"
):
GeometryCommands(None)
7 changes: 2 additions & 5 deletions tests/integration/test_repair_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
UnsimplifiedFaceProblemAreas,
)
from ansys.geometry.core.tools.repair_tool_message import RepairToolMessage
from ansys.geometry.core.tools.repair_tools import RepairTools

from .conftest import FILES_DIR

Expand Down Expand Up @@ -731,8 +730,7 @@ def test_problem_area_fix_no_data(modeler: Modeler, problem_area_class, kwargs):
)
def test_repair_tools_no_bodies(modeler: Modeler, method_name):
"""Test RepairTools methods when bodies is empty or None."""
grpc_client = modeler.client
repair_tools = RepairTools(grpc_client, modeler)
repair_tools = modeler.repair_tools
method = getattr(repair_tools, method_name)

# Test with an empty list of bodies
Expand All @@ -755,8 +753,7 @@ def test_repair_tools_no_bodies(modeler: Modeler, method_name):
)
def test_repair_tools_find_and_fix_no_bodies(modeler: Modeler, method_name):
"""Test RepairTools find_and_fix methods when bodies is empty or None."""
grpc_client = modeler.client
repair_tools = RepairTools(grpc_client, modeler)
repair_tools = modeler.repair_tools
method = getattr(repair_tools, method_name)

# Test with an empty list of bodies
Expand Down
Loading