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

How to debug traits/session/zmqstream/socket communication ? (why string gets lowercased ?) #413

Open
SGR-FA opened this issue Sep 4, 2024 · 2 comments

Comments

@SGR-FA
Copy link

SGR-FA commented Sep 4, 2024

Hi,

First of all, thank you all for your great work !!

I'm upgrading from an old Python 3.8 venv but unfortunately I get a traitlets related message when I try to open a pythreejs based 3D model viewer in a notebooks.

TraitError: The 'rotation' trait of a GridHelper instance contains an Enum of an Euler which expected any of ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'], not the str 'xyz'.

For now, I'm completely stuck but as I understand, an "XYZ" string value (expected for a pythreejs Euler traits ) gets lowercased somewhere during the Jupyter traits/session/zmqstream/socket communication. It could be during any of the cast, from_json, to_json, send_multipart or recv_multipart steps but I have not managed to find which one :( and I get the same TraitError for any other version of python/occt/ifcopenshell...

Jupyter back/front communication is quite tricky to debug, so if you have any information about how to do that, somewhere else to ask or any idea why this gets lowercased...

Here is the venv :

#conda env export --from-history

name: ifc_viewer_311
channels:
  - defaults
dependencies:
  - pythonocc-core[build=*novtk*]
  - lark
  - occt=7.7.2
  - ifcopenshell
  - python=3.11
  - jsonpath-ng
  - pythreejs
  - vpython
  - cmasher
  - ipywidgets
  - ipympl
  - matplotlib
  - traitlets
  - jupyterlab
  - scipy
  - pandas
  - tornado

Here is an example to get the error:

import ifcopenshell
import ifcopenshell.geom

settings = ifcopenshell.geom.settings()
settings.set(settings.USE_PYTHON_OPENCASCADE, True)

from OCC.Display.WebGl.jupyter_renderer import JupyterRenderer as Renderer

class ifc_viewer(Renderer):
    def __init__(self):
        Renderer.__init__(self)
        self.products = []

    @staticmethod
    def subshapes(shp):
        import OCC.Core.TopoDS
        it = OCC.Core.TopoDS.TopoDS_Iterator(shp)
        while it.More():
            yield it.Value()
            it.Next()

    def DisplayShape(self, product, shp, color):
        for shp, sty in zip(self.subshapes(shp), color):
            Renderer.DisplayShape(self, shp, shape_color=sty[0:3], render_edges=True, transparency=True)
            self.products.append(product)

    def onclick(self, item):
        self.html.value = "Selected %r" % self.products[int(item.name)]

file = ifcopenshell.open("YOUR_IFC_FILE.ifc")
geometry = dict((file[item.data.id], (item.geometry, item.styles)) for item in ifcopenshell.geom.iterator(settings, file))

viewer = ifc_viewer()

for product, (shape, styles) in geometry.items():
    viewer.DisplayShape(product, shape, styles)
    
viewer.Display()

Here is the output

---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\ipywidgets\widgets\widget.py:773, in Widget._handle_msg(self, msg)
    771         if 'buffer_paths' in data:
    772             _put_buffers(state, data['buffer_paths'], msg['buffers'])
--> 773         self.set_state(state)
    775 # Handle a state request.
    776 elif method == 'request_state':

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\ipywidgets\widgets\widget.py:655, in Widget.set_state(self, sync_data)
    652 if name in self.keys:
    653     from_json = self.trait_metadata(name, 'from_json',
    654                                     self._trait_from_json)
--> 655     self.set_trait(name, from_json(sync_data[name], self))

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:1764, in HasTraits.set_trait(self, name, value)
   1762 if not self.has_trait(name):
   1763     raise TraitError(f"Class {cls.__name__} does not have a trait named {name}")
-> 1764 getattr(cls, name).set(self, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:690, in TraitType.set(self, obj, value)
    689 def set(self, obj: HasTraits, value: S) -> None:
--> 690     new_value = self._validate(obj, value)
    691     assert self.name is not None
    692     try:

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:722, in TraitType._validate(self, obj, value)
    720     return value
    721 if hasattr(self, "validate"):
--> 722     value = self.validate(obj, value)
    723 if obj._cross_validation_lock is False:
    724     value = self._cross_validate(obj, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3482, in Container.validate(self, obj, value)
   3479 if value is None:
   3480     return value
-> 3482 value = self.validate_elements(obj, value)
   3484 return t.cast(T, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3823, in Tuple.validate_elements(self, obj, value)
   3821     v = trait._validate(obj, v)
   3822 except TraitError as error:
-> 3823     self.error(obj, v, error)
   3824 else:
   3825     validated.append(v)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:810, in TraitType.error(self, obj, value, error, info)
    801         else:
    802             error.args = (
    803                 "The '{}' trait contains {} which " "expected {}, not {}.".format(
    804                     self.name,
   (...)
    808                 ),
    809             )
--> 810     raise error
    812 # this trait caused an error
    813 if self.name is None:
    814     # this is not the root trait

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3821, in Tuple.validate_elements(self, obj, value)
   3819 for trait, v in zip(self._traits, value):
   3820     try:
-> 3821         v = trait._validate(obj, v)
   3822     except TraitError as error:
   3823         self.error(obj, v, error)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:722, in TraitType._validate(self, obj, value)
    720     return value
    721 if hasattr(self, "validate"):
--> 722     value = self.validate(obj, value)
    723 if obj._cross_validation_lock is False:
    724     value = self._cross_validate(obj, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:3224, in Enum.validate(self, obj, value)
   3222 if self.values and value in self.values:
   3223     return t.cast(G, value)
-> 3224 self.error(obj, value)

File D:\Anaconda3\envs\ifc_viewer_311\Lib\site-packages\traitlets\traitlets.py:815, in TraitType.error(self, obj, value, error, info)
    812 # this trait caused an error
    813 if self.name is None:
    814     # this is not the root trait
--> 815     raise TraitError(value, info or self.info(), self)
    817 # this is the root trait
    818 if obj is not None:

TraitError: The 'rotation' trait of a GridHelper instance contains an Enum of an Euler which expected any of ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'], not the str 'xyz'.

FYI I've already tried to open an issue here.

Thank you for your help.

@maartenbreddels
Copy link
Member

Jupyter back/front communication is quite tricky to debug

I agree, maybe https://github.com/itepifanio/ipywatch helps (or would have helped)?

@SGR-FA
Copy link
Author

SGR-FA commented Sep 5, 2024

EDIT:
Thank you, I've made a try with the same strange 'XYZ' to 'xyz': in the notebook output, I get:

Comm message sent by GridHelper (d6c128ac3f844875bc5830a3fbe4f26a): {'method': 'update', 'state': {'rotation': [1.5707963267948966, 0.0, 0.0, 'XYZ']}, 'buffer_paths': []}

But in the log console, I get :

Comm message sent by GridHelper (d6c128ac3f844875bc5830a3fbe4f26a): {'method': 'echo_update', 'state': {'rotation': [1.5707963267948966, 0, 0, 'xyz']}, 'buffer_paths': []}

just before

TraitError: The 'rotation' trait of a GridHelper instance contains an Enum of an Euler which expected any of ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'], not the str 'xyz'.

chrome_GpkxxNpbGU

For now I've added pydevd debug plumbing in Kernel::__init__ in kernelbase.py and in VENV\Scripts\jupyter-lab-script.py (so I can run 2 debug servers simultaneously). I don't know if there is another way to diagnose such front <=> back asynchronous communication (with changing identifiers).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants