Skip to content
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

Fixed compas_ghpython is not importable in Rhino8 #1391

Merged
merged 20 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

* Fixed support for `compas_gpython` in Rhino 8 Grasshopper CPython components.

### Removed


Expand Down
17 changes: 15 additions & 2 deletions src/compas/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import pkgutil
import threading

import compas

__all__ = [
"pluggable",
"plugin",
Expand All @@ -33,6 +35,17 @@
"PluginDefaultNotAvailableError",
]

if compas.RHINO:
import System # type: ignore # pragma: no cover
chenkasirer marked this conversation as resolved.
Show resolved Hide resolved

DotNetException = System.Exception # pragma: no cover
else:

class DummyDotNetException(BaseException):
pass

DotNetException = DummyDotNetException
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this done in two steps?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean two steps? why I'm not using BaseException directly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, why not class DotNetException(BaseException): pass

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no other reason except it never crossed my mind :)



class PluginNotInstalledError(Exception):
"""Exception raised when an extension point is invoked but no plugin is available."""
Expand Down Expand Up @@ -401,15 +414,15 @@ def try_import(self, module_name):
If importable, it returns the imported module, otherwise ``None``.
"""
module = None

try:
module = __import__(module_name, fromlist=["__name__"], level=0)
self._cache[module_name] = True

# There are two types of possible failure modes:
# 1) cannot be imported, or
# 2) is a python 3 module and we're in IPY, which causes a SyntaxError
except (ImportError, SyntaxError):
# 3) in Rhino8 we may get a nasty DotNet Exception when trying to import a module
except (ImportError, SyntaxError, DotNetException):
tomvanmele marked this conversation as resolved.
Show resolved Hide resolved
self._cache[module_name] = False

return module
Expand Down
3 changes: 0 additions & 3 deletions src/compas_ghpython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@

__version__ = "2.4.2"

if compas.is_rhino():
from .utilities import * # noqa: F401 F403

__all__ = [
"get_grasshopper_managedplugin_path",
"get_grasshopper_library_path",
Expand Down
13 changes: 12 additions & 1 deletion src/compas_ghpython/drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
from Rhino.Geometry import Vector3f

from compas.geometry import centroid_points
from compas.geometry import centroid_polygon
from compas.itertools import pairwise
from compas_rhino.drawing import _face_to_max_quad

try:
from Rhino.Geometry import MeshNgon
Expand All @@ -31,6 +31,17 @@
TOL = sc.doc.ModelAbsoluteTolerance


def _face_to_max_quad(points, face):
faces = []
c = len(points)
points.append(centroid_polygon(points))
for i in range(-1, len(face) - 1):
a = face[i]
b = face[i + 1]
faces.append([c, a, b, b])
return faces


def draw_frame(frame):
"""Draw a frame."""
pt = Point3d(*iter(frame.point))
Expand Down
2 changes: 1 addition & 1 deletion src/compas_ghpython/scene/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def register_scene_objects():
register(VolMesh, VolMeshObject, context="Grasshopper")
register(Brep, BrepObject, context="Grasshopper")

# print("GH SceneObjects registered.")
print("GH SceneObjects registered.")


__all__ = [
Expand Down
13 changes: 11 additions & 2 deletions src/compas_ghpython/scene/meshobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from compas.scene import MeshObject as BaseMeshObject
from compas_rhino import conversions
from compas_rhino.scene.helpers import ngon

from .sceneobject import GHSceneObject

Expand Down Expand Up @@ -147,11 +146,21 @@ def draw_faces(self):
for face in faces:
color = self.facecolor[face] # type: ignore
vertices = [self.mesh.vertex_attributes(vertex, "xyz") for vertex in self.mesh.face_vertices(face)] # type: ignore
facet = ngon(len(vertices))
facet = self._create_ngon(len(vertices))

if facet:
geometry = conversions.vertices_and_faces_to_rhino(vertices, [facet], color=color)
geometry.Transform(transformation)
meshes.append(geometry)

return meshes

@staticmethod
def _create_ngon(vertex_count):
if vertex_count < 3:
return
if vertex_count == 3:
return [0, 1, 2]
if vertex_count == 4:
return [0, 1, 2, 3]
return list(range(vertex_count))
chenkasirer marked this conversation as resolved.
Show resolved Hide resolved
13 changes: 11 additions & 2 deletions src/compas_ghpython/scene/volmeshobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from compas.scene import VolMeshObject as BaseVolMeshObject
from compas_rhino import conversions
from compas_rhino.scene.helpers import ngon

from .sceneobject import GHSceneObject

Expand Down Expand Up @@ -84,7 +83,7 @@ def draw_faces(self):
for face in faces:
color = self.facecolor[face]
vertices = [self.vertex_xyz[vertex] for vertex in self.volmesh.face_vertices(face)]
facet = ngon(len(vertices))
facet = self._create_ngon(len(vertices))
if facet:
meshes.append(conversions.vertices_and_faces_to_rhino(vertices, [facet], color=color))

Expand Down Expand Up @@ -115,3 +114,13 @@ def draw_cells(self):
meshes.append(mesh)

return meshes

@staticmethod
def _create_ngon(vertex_count):
if vertex_count < 3:
return
if vertex_count == 3:
return [0, 1, 2]
if vertex_count == 4:
return [0, 1, 2, 3]
return list(range(vertex_count))
chenkasirer marked this conversation as resolved.
Show resolved Hide resolved
36 changes: 0 additions & 36 deletions src/compas_ghpython/utilities/__init__.py

This file was deleted.

27 changes: 26 additions & 1 deletion tests/compas/test_plugins.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import abstractmethod

import pytest

import compas
from compas.plugins import IncompletePluginImplError
from compas.plugins import PluginValidator

Expand Down Expand Up @@ -36,3 +36,28 @@ def test_ensure_implementations_fails_with_incomplete_impl():

def test_ensure_implementations_with_valid_impl():
PluginValidator.ensure_implementations(CompleteImpl)


def test_dot_net_exception_with_rhino():
if not compas.RHINO:
return

from compas.plugins import DotNetException

assert DotNetException is not None

import System

assert DotNetException == System.Exception


def test_dot_net_exception_without_rhino():
if compas.RHINO:
return

from compas.plugins import DotNetException

assert DotNetException is not None
from compas.plugins import DummyDotNetException

assert DotNetException == DummyDotNetException
Loading