# Eto + python + mac. shut down

**URL:** <https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842>\
**Category:** Rhino Developer\
**Tags:** mac, eto\
**Created:** [May 21, 2025, 1:50pm UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842 "2025-05-21T13:50:37Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [May 21, 2025, 1:50pm UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/1 "2025-05-21T13:50:38Z")

</div>

Hello. Recently I noticed about Eto. I started to study this and connecting my python project to this UI.  
But in some cases the bug not just break process, but also break Rhino. What I mean is that, in some cases Rhino shut down.  
I had to open Console App to check the last error messages. Why this happened? And How can I fix this?

---

<div class="post-metadata">

**Author:** ![CallumSykes](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/callumsykes/32/569341_2.png) [@CallumSykes](https://discourse.mcneel.com/u/CallumSykes)\
**Post date:** [May 21, 2025, 3:03pm UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/2 "2025-05-21T15:03:05Z")

</div>

Hello @이신후 is Rhino crashing when you’re editing python in the Script Editor?

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [May 22, 2025, 12:39am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/3 "2025-05-22T00:39:04Z")

</div>

not during editing, but running script through Tool \> Script \> Run

running this code

```auto
import sys

sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")
import utils
import Rhino.Input
import Rhino.Input.Custom
import scriptcontext as sc
from apartment.apartment_builder import (
    ApartmentInputStructure,
    UnitInput,
    CoreInput,
    WindowInput,
)

from Eto.Forms import (
    Application,
    Form,
    TextBox,
    Button,
    Label,
    TableLayout,
    TableRow,
    TableCell,
)
import Eto.Forms as ef
from Eto.Drawing import Size, Padding

def get_object(): # DEPRECATED ETO loop와 충돌발생
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt("아파트 관련 도면 객체를 선택하세요")
    go.EnablePreSelect(True, True)
    go.GetMultiple(1, 0)

    if go.CommandResult() != Rhino.Commands.Result.Success:
        ef.MessageBox.Show("오브젝트 선택이 취소되었습니다.", ef.MessageBoxButtons.OK)
        return

def get_preselected_objects():
    objs = sc.doc.Objects.GetSelectedObjects(True, False)
    return objs

class ValidationResultForm(Form):
    def __init__ (self, objects, results):
        super(ValidationResultForm, self). __init__ ()
        self.Title = "검증 결과"
        self.ClientSize = Size(400, 200)
        self.Padding = Padding(10)
        self.objects = objects

        layout = TableLayout(
            rows=[
                TableRow(
                    Label(Text=f"검증 {key}: {'✅ 통과' if passed else '❌ 실패'}")
                )
                for key, passed in results.items()
            ]
            + [None]
        )
        self.Content = layout

class ValidationForm(Form):
    def __init__ (
        self,
    ):
        super(ValidationForm, self). __init__ ()
        self.objects = None
        self.Title = "아파트 도면 검증"
        self.ClientSize = Size(400, 300)
        self.Padding = Padding(10)

        # --- 위젯들 ---
        self.name_input = TextBox()
        self.upload_button = utils.make_button("Upload")

        self.result_labels = {
            "A": utils.make_label("검증 A: 대기 중"),
            "B": utils.make_label("검증 B: 대기 중"),
            "C": utils.make_label("검증 C: 대기 중"),
            "D": utils.make_label("검증 D: 대기 중"),
        }

        self.upload_button.Click += self.on_upload_clicked

        # --- 레이아웃 ---
        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(utils.make_label("아파트 이름")),
                    TableCell(self.name_input),
                ),
                TableRow(None, TableCell(self.upload_button)),
                TableRow(TableCell(self.result_labels["A"])),
                TableRow(TableCell(self.result_labels["B"])),
                TableRow(TableCell(self.result_labels["C"])),
                TableRow(TableCell(self.result_labels["D"])),
                None, # 끝에 여유 공간
            ]
        )

        self.Content = layout

    def on_upload_clicked(self, sender, e):
        apartment_name = self.name_input.Text
        # 아파트로 만들 RhinoObject들을 선택하도록 함.

        objs = sc.doc.Objects.GetSelectedObjects(True, False)

        # 선택된 오브젝트들
        self.objects = objs

        apartment_input_structure = self._create_apartment_input_structure(
            apartment_name, self.objects
        )

        # 검증 실행
        apartment_check_result = apartment_input_structure.validate()

        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(utils.make_label(self.get_result_message(result_dict)))
                )
                for key, result_dict in apartment_check_result.items()
            ]
            + [None]
        )
        self.Content = layout

    def get_result_message(self, result_dict):
        result_message = ""
        result = result_dict.get("result")
        message = result_dict.get("message")
        if result:
            result_message += f"검증 결과: ✅ 통과\n"
        else:
            result_message += f"검증 결과: ❌ 실패 :{message}\n"

        return result_message

    def _create_apartment_input_structure(
        self, apartment_name, clicked_items
    ) -> ApartmentInputStructure:

        object_by_layer = {}
        for rhino_object in clicked_items:
            lyr_name = utils.get_layer_name(rhino_object)
            if lyr_name not in object_by_layer:
                object_by_layer[lyr_name] = []
            object_by_layer[lyr_name].append(rhino_object)
        unit_inputs = [UnitInput(unit_obj) for unit_obj in object_by_layer["unit"]]
        core_inputs = [CoreInput(core_obj) for core_obj in object_by_layer["core"]]
        window_inputs = [
            WindowInput(window_obj) for window_obj in object_by_layer["window"]
        ]
        apartment_input_structure = ApartmentInputStructure(
            apartment_name,
            unit_inputs,
            core_inputs,
            corridor_inputs=[],
            window_inputs=window_inputs,
            sidewall_inputs=[],
        )
        return apartment_input_structure

# --- 애플리케이션 실행 ---
if __name__ == " __main__":
    form = ValidationForm()
    form.Show()

```

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [May 22, 2025, 12:42am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/4 "2025-05-22T00:42:04Z")

</div>

![image](https://global.discourse-cdn.com/mcneel/uploads/default/original/4X/5/1/2/51269658e47c2b3c673c2ebd726c8c6a2e1f0d6f.jpeg)  
Because Rhino Crash. I have to check error message thorugh Console App in Mac.  
This makes development experience so bad. So I want to fix this.

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [May 22, 2025, 12:44am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/5 "2025-05-22T00:44:50Z")

</div>

![image](https://global.discourse-cdn.com/mcneel/uploads/default/original/4X/6/f/2/6f27dd62f39f68febadaf48536ac307ecfffcc45.jpeg)  
This is image of UI I’m trying to build.  
If i click Upload Button, if there is any error in code(simple error such as input value count not matching). Rhino Crash.

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [May 22, 2025, 12:51am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/6 "2025-05-22T00:51:42Z")

</div>

If there is better way to create GUI, I want to try, please inform me.  
functions that I need with the GUI

1. interact with User  
user click RhinoObjects \> check Validation + Create BlockDefinition \> simulate and optimize with the Block Definition \> Visualize 3D results and show data with table or graph.
2. Python (Cpython prefer)
3. Various UI elements(image, table, Rhino viewport)

the reason I choose Eto was that Eto has all of this functions, but if there is other way, I want to try that.  
Thank You for reading this!

---

<div class="post-metadata">

**Author:** ![CallumSykes](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/callumsykes/32/569341_2.png) [@CallumSykes](https://discourse.mcneel.com/u/CallumSykes)\
**Post date:** [May 22, 2025, 11:49am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/7 "2025-05-22T11:49:38Z")

</div>

Hey @이신후 ,

A few questions.  
Can you run the `_systemInfo` command and paste the results here.

> [@이신후](#):
>
> `sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")`

I can’t test the script crash unfortunately without this library, if you can add it here ot DM it to me I can try to replicate and then create a ticket.

> [@이신후](#):
>
> not during editing, but running script through Tool \> Script \> Run

I personally write my Eto UI’s in the [Script Editor](https://developer.rhino3d.com/guides/scripting/scripting-command/).

I do know that some things will just Crash Rhino when scripting, especially events.  
try/catch can help with certain errors to prevent crashes.

Also, more Eto docs which may help.

> **[Eto Guides](https://developer.rhino3d.com/en/guides/eto/)**
>
> Guides that apply to developing UIs across platforms using Eto.

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [May 30, 2025, 1:42am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/8 "2025-05-30T01:42:00Z")

</div>

Hello, Thank you for response.  
I hope you can replicate with this script and my contexts.

My test code which stopping Rhino

```auto
import sys
sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")

import Rhino.Input
import Rhino.Input.Custom
import scriptcontext as sc

from Eto.Forms import (
    Application,
    Form,
    TextBox,
    Button,
    Label,
    TableLayout,
    TableRow,
    TableCell,
    Dialog,
)
import Eto.Forms as ef
from Eto.Drawing import Size, Padding

def make_label(text) -> Label:
    lbl = Label()
    lbl.Text = text
    return lbl

def make_button(text) -> Button:
    btn = Button()
    btn.Text = text
    return btn

class ValidationResultForm(Form):
    def __init__ (self, objects, results):
        super(ValidationResultForm, self). __init__ ()
        self.Title = "검증 결과"
        self.ClientSize = Size(400, 200)
        self.Padding = Padding(10)
        self.objects = objects

        layout = TableLayout(
            rows=[
                TableRow(
                    Label(Text=f"검증 {key}: {'✅ 통과' if passed else '❌ 실패'}")
                )
                for key, passed in results.items()
            ]
            + [None]
        )
        self.Content = layout

class ValidationDialog(Dialog):
    def __init__ (
        self,
    ):
        super(ValidationDialog, self). __init__ ()
        self.objects = None
        self.Title = "아파트 도면 검증"
        self.Width = 400
        self.Height = 800
        self.Padding = Padding(10)

        # --- 위젯들 ---
        self.name_input = TextBox()
        self.upload_button = make_button("Upload")

        self.result_labels = {
            "A": make_label("검증 A: 대기 중"),
            "B": make_label("검증 B: 대기 중"),
            "C": make_label("검증 C: 대기 중"),
            "D": make_label("검증 D: 대기 중"),
        }

        self.upload_button.Click += self.on_upload_clicked

        # --- 레이아웃 ---
        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(make_label("아파트 이름")),
                    TableCell(self.name_input),
                ),
                TableRow(None, TableCell(self.upload_button)),
                TableRow(TableCell(self.result_labels["A"])),
                TableRow(TableCell(self.result_labels["B"])),
                TableRow(TableCell(self.result_labels["C"])),
                TableRow(TableCell(self.result_labels["D"])),
                None, # 끝에 여유 공간
            ]
        )

        self.Content = layout

    def on_upload_clicked(self, sender, e):
        apartment_name = self.name_input.Text
        # 아파트로 만들 RhinoObject들을 선택하도록 함.

        objs = sc.doc.Objects.GetSelectedObjects(True, False)

        # 선택된 오브젝트들
        self.objects = objs
        raise Exception("this is raise test")
       

    def get_result_message(self, result_dict):
        result_message = ""
        result = result_dict.get("result")
        message = result_dict.get("message")
        if result:
            result_message += f"검증 결과: ✅ 통과\n"
        else:
            result_message += f"검증 결과: ❌ 실패 :{message}\n"

        return result_message

print("Starting ValidationForm...")
dialog = ValidationDialog()
dialog.ShowModal()

```

my systemInfo

Rhino 8 SR19 2025-5-12 (Rhino 8, 8.19.25132.01002, Git hash:master @ 57e3eb280b0f32cbe59f53a554be5e8ffa66fc36)  
License type: Commercial, build 2025-05-12  
License details: Cloud Zoo

Apple macOS Version 14.7 (Build 23H124) (Physical RAM: 16GB)  
Mac Model Identifier: MacBookAir10,1  
Language: en-KR (MacOS default)  
.NET 7.0.0

Metal GPU Family Apple 7  
Metal GPU Family Common 3  
Metal GPU Family Mac 2  
Graphics processors  
Apple M1  
Color LCD (1440 x 900 @ 60.00Hz)  
GPU Vendor: Apple

USB devices  
None

Bluetooth devices  
None

Third party kernel extensions  
None

Third party plugins  
/usr/lib/swift/libswiftCore.dylib  
/usr/lib/swift/libswiftCoreFoundation.dylib  
/usr/lib/swift/libswiftCoreGraphics.dylib  
/usr/lib/swift/libswiftCoreImage.dylib  
/usr/lib/swift/libswiftDarwin.dylib  
/usr/lib/swift/libswiftDispatch.dylib  
/usr/lib/swift/libswiftIOKit.dylib  
/usr/lib/swift/libswiftMetal.dylib  
/usr/lib/swift/libswiftOSLog.dylib  
/usr/lib/swift/libswiftObjectiveC.dylib  
/usr/lib/swift/libswiftQuartzCore.dylib  
/usr/lib/swift/libswiftUniformTypeIdentifiers.dylib  
/usr/lib/swift/libswiftXPC.dylib  
/usr/lib/swift/libswift\_Concurrency.dylib  
/usr/lib/swift/libswiftos.dylib  
/usr/lib/swift/libswiftsimd.dylib  
/usr/lib/swift/libswift\_StringProcessing.dylib  
/usr/lib/swift/libswift\_RegexParser.dylib  
/usr/lib/swift/libswiftCryptoTokenKit.dylib  
/usr/lib/usd/libusd\_ms.dylib  
/usr/lib/swift/libswiftCoreAudio.dylib  
/usr/lib/swift/libswiftCoreLocation.dylib  
/usr/lib/swift/libswiftCoreMedia.dylib  
/usr/lib/swift/libswiftCompression.dylib  
/usr/lib/swift/libswiftCoreMIDI.dylib  
/usr/lib/swift/libswiftAVFoundation.dylib  
/usr/lib/swift/libswiftCoreML.dylib  
/usr/lib/swift/libswiftFileProvider.dylib  
/usr/lib/swift/libswiftIntents.dylib  
/usr/lib/swift/libswiftAccelerate.dylib  
/usr/lib/swift/libswiftGLKit.dylib  
/usr/lib/swift/libswiftGameplayKit.dylib  
/usr/lib/swift/libswiftMetalKit.dylib  
/usr/lib/swift/libswiftModelIO.dylib  
/usr/lib/swift/libswiftSceneKit.dylib  
/usr/lib/swift/libswiftSpriteKit.dylib  
/usr/lib/swift/libswiftVision.dylib  
/usr/lib/swift/libswiftRegexBuilder.dylib  
/usr/lib/swift/libswiftDemangle.dylib  
/usr/lib/swift/libswiftShazamKit.dylib  
/usr/lib/swift/libswiftObservation.dylib  
/usr/lib/swift/libswiftVideoToolbox.dylib  
/usr/lib/swift/libswiftWebKit.dylib  
/usr/lib/swift/libswiftNaturalLanguage.dylib  
/usr/lib/swift/libswiftSystem.dylib  
/usr/lib/swift/libswiftMapKit.dylib  
/usr/lib/log/liblog\_network.dylib  
/Users/sinhoo/.rhinocode/py39-rh8/libpython3.9.dylib  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_heapq.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_ssl.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/libssl.1.1.dylib  
/Users/sinhoo/.rhinocode/py39-rh8/libcrypto.1.1.dylib  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_socket.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/math.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/select.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/array.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_struct.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/binascii.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/zlib.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_bz2.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_lzma.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/grp.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_bisect.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_random.cpython-39-darwin.so  
/Users/sinhoo/.rhinocode/py39-rh8/lib/python3.9/lib-dynload/\_sha512.cpython-39-darwin.so

Rhino plugins that do not ship with Rhino  
/Users/sinhoo/Library/Application Support/McNeel/Rhinoceros/packages/8.0/Fologram/2024.2.9/Fologram.rhp “Fologram” 2024.2.9.0  
/Users/sinhoo/Library/Application Support/McNeel/Rhinoceros/8.0/MacPlugIns/Enscape.Rhino8.Plugin.rhp “Enscape.Rhino8.Plugin” 4.7.0.57

Rhino plugins that ship with Rhino  
/Applications/Rhino 8.app/Contents/Frameworks/RhMaterialEditor.framework “Renderer Development Kit” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/Commands.rhp “Commands” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/PlugIns/NamedSnapshots.rhp “Snapshots” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RDK\_EtoUI.rhp “RDK\_EtoUI” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/MeshCommands.rhp “MeshCommands” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoRenderCycles.rhp “Rhino Render” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoCycles.rhp “RhinoCycles” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/PlugIns/SectionTools.rhp “SectionTools” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/PlugIns/Displacement.rhp “Displacement” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/PlugIns/PanelingTools.rhp “PanelingTools” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoDLR\_Python.rhp “IronPython” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/GrasshopperPlugin.rhp “Grasshopper” 8.19.25132.1002  
/Applications/Rhino 8.app/Contents/Frameworks/RhCore.framework/Resources/ManagedPlugIns/RhinoCodePlugin.rhp “RhinoCodePlugin” 8.19.25132.1002

---

<div class="post-metadata">

**Author:** ![CallumSykes](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/callumsykes/32/569341_2.png) [@CallumSykes](https://discourse.mcneel.com/u/CallumSykes)\
**Post date:** [May 30, 2025, 9:33am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/9 "2025-05-30T09:33:56Z")

</div>

> [@이신후](#):
>
> `sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")`

Are you able to include me this library either here or in a direct message @이신후? The script won’t run without it for me 🙂

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [June 10, 2025, 2:21am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/10 "2025-06-10T02:21:09Z")

</div>

[RhinoPlugin.zip](https://discourse.mcneel.com/uploads/short-url/vnf699tp8SlCOrK9kHdCyAeFMGk.zip) (156.3 KB)  
This is all files in that directory. I ran codes in python\_scripts directory.  
Thanks for follwing up.

---

<div class="post-metadata">

**Author:** ![tom33](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/tom33/32/757238_2.png) [@tom33](https://discourse.mcneel.com/u/tom33)\
**Post date:** [June 10, 2025, 3:40pm UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/13 "2025-06-10T15:40:37Z")

</div>

The rhino ide can now write c# directly. If you want to use pyeto, it is better to write py+cs in the rhino ide. There should be fewer errors.

---

<div class="post-metadata">

**Author:** ![nathanletwory](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/nathanletwory/32/482880_2.png) [@nathanletwory](https://discourse.mcneel.com/u/nathanletwory)\
**Post date:** [June 10, 2025, 3:55pm UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/14 "2025-06-10T15:55:02Z")

</div>

@이신후 for what it is worth, the screenshot of the Console app shows the error and solution. ` __init__ ()` missing an argument `core_inputs`. You probably should do `core_inputs=core_inputs`, but it really depends on what the ` __init__ ` of your class `ApartmentInputStructure` is.

edit: I actually only now noticed the ZIP file you uploaded. I think probably should remove the named arguments in the call, just pass in the values you want to without naming them.

From

```python
        apartment_input_structure = ApartmentInputStructure(
            apartment_name,
            unit_inputs,
            core_inputs,
            corridor_inputs=[],
            window_inputs=window_inputs,
            sidewall_inputs=[],
        )

```

to

```python
        apartment_input_structure = ApartmentInputStructure(
            apartment_name,
            unit_inputs,
            core_inputs,
            [],
            window_inputs,
            [],
        )

```

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [June 11, 2025, 12:44am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/15 "2025-06-11T00:44:51Z")

</div>

@N Thank you for the advice. I’m trying to find best way to build interface with Rhino - python script.  
I used to build this interface with grasshopper + VSCode Studio and make every python scripts as package and import + reload in Grasshopper to make my codes reusable.  
But my client had some difficulties to use GH interface so I wanted to build UI in Rhino.  
What is the best way?  
My concern is two things.  
First, it should be flexible and interactive with rhino Document(like creating block defintions or validating)  
Second, the code could be reusable(I build many tiny utilty codes and use those codes in many projects)  
I found that I can write python3 in rhino script editor(before I confused script editor between RhinoPythonEditor which allows only iron python), so I started to test it. But if there is better way, please give me some advice

---

<div class="post-metadata">

**Author:** ![이신후](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/%EC%9D%B4%EC%8B%A0%ED%9B%84/32/633164_2.png) [@이신후](https://discourse.mcneel.com/u/%EC%9D%B4%EC%8B%A0%ED%9B%84)\
**Post date:** [June 11, 2025, 12:47am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/16 "2025-06-11T00:47:16Z")

</div>

Thank you for your check.  
I knew my code has error, my issue was that Rhino crashes so its hard to check what the error is, which makes developing experience so bad.

As you mentioned, I will try to remove named args to check if this work. Thank you!

---

<div class="post-metadata">

**Author:** ![nathanletwory](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/nathanletwory/32/482880_2.png) [@nathanletwory](https://discourse.mcneel.com/u/nathanletwory)\
**Post date:** [June 11, 2025, 7:52am UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/17 "2025-06-11T07:52:28Z")

</div>

> [@이신후](#):
>
> my issue was that Rhino crashes so its hard to check what the error is, which makes developing experience so bad.

That is indeed not ideal. @CallumSykes , @eirannejad, is there maybe something be done here that Rhino wouldn’t completely crash on a Python error?

---

<div class="post-metadata">

**Author:** ![tom33](https://sea3.discourse-cdn.com/mcneel/user_avatar/discourse.mcneel.com/tom33/32/757238_2.png) [@tom33](https://discourse.mcneel.com/u/tom33)\
**Post date:** [June 11, 2025, 6:41pm UTC](https://discourse.mcneel.com/t/eto-python-mac-shut-down/204842/19 "2025-06-11T18:41:11Z")

</div>

Change to get the object name, I hope you can help  
Forgive me if I don’t understand your native language, I can only guess and make some changes

```auto
#! python 3
import sys
sys.path.append("/Users/sinhoo/Documents/RhinoPlugin")

import Rhino.Input
import Rhino.Input.Custom
import scriptcontext as sc
import Eto.Forms as ef
import rhinoscriptsyntax as rs

from Eto.Forms import (
    Application,
    Form,
    TextBox,
    Button,
    Label,
    TableLayout,
    TableRow,
    TableCell,
    Dialog,
)
import Eto.Forms as ef
from Eto.Drawing import Size, Padding

def make_label(text) -> Label:
    lbl = Label()
    lbl.Text = text
    return lbl

def make_button(text) -> Button:
    btn = Button()
    btn.Text = text
    return btn

class ValidationResultForm(Form):
    def __init__ (self, objects, results):
        super(ValidationResultForm, self). __init__ ()
        self.Title = "검증 결과"
        self.ClientSize = Size(400, 200)
        self.Padding = Padding(10)
        self.objects = objects

        layout = TableLayout(
            rows=[
                TableRow(
                    Label(Text=f"검증 {key}: {'✅ 통과' if passed else '❌ 실패'}")
                )
                for key, passed in results.items()
            ]
            + [None]
        )
        self.Content = layout

class ValidationDialog(ef.Form):
    def __init__ (
        self,
    ):
        super(ValidationDialog, self). __init__ ()
        self.objects = None
        self.Title = "아파트 도면 검증"
        self.Width = 400
        self.Height = 800
        self.Padding = Padding(10)
        self.Topmost = True

        # --- 위젯들 ---
        self.name_input = TextBox()
        self.upload_button = make_button("Upload")

        self.result_labels = {
            "A": make_label("검증 A: 대기 중"),
            "B": make_label("검증 B: 대기 중"),
            "C": make_label("검증 C: 대기 중"),
            "D": make_label("검증 D: 대기 중"),
        }

        self.upload_button.Click += self.on_upload_clicked

        # --- 레이아웃 ---
        layout = TableLayout(
            rows=[
                TableRow(
                    TableCell(make_label("아파트 이름")),
                    TableCell(self.name_input),
                ),
                TableRow(None, TableCell(self.upload_button)),
                TableRow(TableCell(self.result_labels["A"])),
                TableRow(TableCell(self.result_labels["B"])),
                TableRow(TableCell(self.result_labels["C"])),
                TableRow(TableCell(self.result_labels["D"])),
                None, # 끝에 여유 공간
            ]
        )

        self.Content = layout

    def on_upload_clicked(self, sender, e):
        try:
            # apartment_name = self.name_input.Text
            # 아파트로 만들 RhinoObject들을 선택하도록 함.

            # objs = sc.doc.Objects.GetSelectedObjects(True, False)
            objs = "test"
            # # 선택된 오브젝트들
            # self.objects = objsCV 
            # raise Exception("this is raise test")
            self.name_input.Text = self.rs_cmd()
            # self.Invalidate()
        except Exception as ex:
            print("Error!" + ex)
       
    def get_result_message(self, result_dict):
        result_message = ""
        result = result_dict.get("result")
        message = result_dict.get("message")
        if result:
            result_message += f"검증 결과: ✅ 통과\n"
        else:
            result_message += f"검증 결과: ❌ 실패 :{message}\n"

        return result_message

    def rs_cmd(self):
        obj = rs.SelectedObjects()
        ro = rs.ObjectName(obj)
        return ro

print("Starting ValidationForm...")
dialog = ValidationDialog()
dialog.Show()

```
