theodox / mGui

Python module for cleaner maya GUI layout syntax
MIT License
123 stars 23 forks source link

Overriding Nested.__exit__ breaks the key-less idiom #28

Closed bob-white closed 8 years ago

bob-white commented 8 years ago

This currently breaks BindingWindow when operating with the key-less idiom, but would apply to anything else that might override Nested.__exit__.

import mGui.gui as mg
import mGui.forms as mf

with mg.BindingWindow() as win:
    with mf.VerticalExpandForm() as main:
        btn = mg.Button()
win.show()
win.main.btn.label = 'I fail here'
# AttributeError: 'BindingWindow'' has no attribute 'main' # 

So in the above example when win's BindingWindow.__exit__ method is called, it then calls into Nested.__exit__, from there we grab the parent frame, which turns out to be BindingWindow.__exit__, and not the actual context scope we were hoping for.

theodox commented 8 years ago

This would be limited to only BndingWindows right now, yes?

bob-white commented 8 years ago

Yeah, currently only limited to BindingWindow right now.

theodox commented 8 years ago

looks like the fix in 8b35711c72d2437f0f9dc91b02f9ca8deaa85bf0 is busted -- i integrated the pull and it broke name references in code that worked otherwise.

bob-white commented 8 years ago

Well damn. So I know it worked with my simple tests, and all of the examples in the example folder. This was where I had found the problem actually. Do you have a simple example where it fails?

theodox commented 8 years ago

Not a simple one, no, But the relevant layout was like this:

 with BindingContext() as self.bindings:
            with forms.VerticalExpandForm(css=outer_margin) as self.root:
                with gui.FrameLayout(css=frame_css) as top_frame:
                    with forms.VerticalForm(css=pad_css) as header_v:
                        with forms.HorizontalStretchForm(css=header_buttons) as header:
                            add_sequence_button = gui.Button(key='add_s', label='add sequence')
                            enable_all_btn = gui.Button(key='untemplate', label='enable all')
                            disable_all_btn = gui.Button(key='template', label='disable all')
                            sort_by_time_btn = gui.Button(key='sort_time', label='sort by time')
                            sort_by_active_btn = gui.Button(key='sort_status', label='sort by status')
                        with gui.RowLayout(numberOfColumns=3, adjustableColumn=3) as prefix_tools:
                            with gui.RadioCollection() as prefix_radio:
                                use_prefix_cb = gui.RadioButton(key='use_fn', label='filename is prefix', width=130)
                                use_explicit_cb = gui.RadioButton(key='use_pf', label='use custom prefix:', width=130)
                            prefix_field = gui.TextField(text=prefix_settings['prefix'],
                                                         enable=not prefix_settings['use_filename'],
                                                         width=360)
                anim_list = lists.VerticalList(width=500,
                                               synchronous=True,
                                               itemTemplate=SequenceTemplate)

                anim_list.onWidgetCreated += self.handle_new_sequence
                self.collection > bind() > anim_list.collection

            add_sequence_button.command += self.create_sequence
            enable_all_btn.command += self.enable_all
            disable_all_btn.command += self.disable_all
            sort_by_time_btn.command += self.sort_by_time
            sort_by_active_btn.command += self.sort_by_active

            if prefix_settings['use_filename']:
                prefix_radio.select = use_prefix_cb
            else:
                prefix_radio.select = use_explicit_cb
            prefix_radio.bind.select > bind() > (prefix_settings, 'use_filename')
            prefix_field.bind.text > bind() > (prefix_settings, 'prefix')
            use_explicit_cb.changeCommand += self.toggle_prefix
            use_prefix_cb.changeCommand += self.toggle_prefix

The closure was never attaching anim_list to root which was how I found it

bob-white commented 8 years ago

So the problem is that self.root doesn't exist in the frame locals, and we end up walking right past the frame when we're inspecting the stack.

So a simple fix in this case it to kind of brute force it a bit. Instead of trying to deduce the valid frame, we just check all of them until we reach the top of the stack. Sure we end up processing a lot more entries, but we're already filtering out non-child controls so we should get the same results.

30 Implements said fix.