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

fix: fix name collisions between dataclass fields and guiclass container attributes #688

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

tlambert03
Copy link
Member

@tlambert03 tlambert03 commented Feb 2, 2025

fixes #684

When a container has a widget whose name attribute matches an attribute on the Widget class itself, then the overloaded __getattr__ method becomes a problem. (reminder: that getattr is what makes it possible to retrieve a magicgui function parameter (for example) as an attribute on the magicgui container widget).

Here I add a get_widget(self, name:str) method on Container that is guaranteed to either return a widget instance or None, avoiding conflicts with other attributes no the Widget instance itself

@tlambert03 tlambert03 changed the title fix: fix name collisions on guiclass dataclass fix: fix name collisions between dataclass fields and guiclass container attributes Feb 2, 2025
Copy link

codecov bot commented Feb 2, 2025

Codecov Report

Attention: Patch coverage is 86.76471% with 9 lines in your changes missing coverage. Please review.

Project coverage is 88.85%. Comparing base (e18ddc6) to head (23b38e1).

Files with missing lines Patch % Lines
src/magicgui/widgets/bases/_named_list.py 88.23% 4 Missing ⚠️
src/magicgui/schema/_guiclass.py 83.33% 3 Missing ⚠️
src/magicgui/experimental.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #688      +/-   ##
==========================================
- Coverage   88.86%   88.85%   -0.02%     
==========================================
  Files          39       40       +1     
  Lines        4761     4809      +48     
==========================================
+ Hits         4231     4273      +42     
- Misses        530      536       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@tlambert03
Copy link
Member Author

@hanjinliu, could you have a look at the magic-class error and see what i've done here that is selectively breaking magic-class? thanks!

@hanjinliu
Copy link
Collaborator

Hi @tlambert03 , I found that the older version and this version returns inconsistent result when a Container widget has multiple widgets with the same name.

from magicgui import __version__
from magicgui.widgets import Container, LineEdit
c = Container()
c.append(LineEdit(name="a", value="1"))
c.append(LineEdit(name="a", value="2"))
c["a"].value

This code returns 1 in the older version, but returns 2 for this PR. The magicclass error occurred because there are widgets of different types.
In the order version, __getattr__ (and __getitem__) searches for the widget whose name matches the input str by for-loop from the beginning of _list. Maybe something changed in this PR?

@tlambert03
Copy link
Member Author

ok, that makes sense... it's caused by this change:

https://github.com/tlambert03/magicgui/blob/8deddf6c7e93cb160ca5dbb06ded2e666a2160c5/src/magicgui/widgets/bases/_named_list.py#L26-L36

I'd say that the implicit expectation of getting the first matching widget in the case of a name collision rather than the last matching widget was probably always more bug-like and not any sort of formal protocol here, but if that's all it takes not to break magic-class I can go back to that behavior. Perhaps after this PR, you can also have a look at places where you have behavior (either explicit or implicit) that might change depending on whether someone has added two widgets with the same name attribute. I don't think either of us should depend on name lookup in that case...

In the case of a dataclass (which precipitated this PR), i think it is safe to assume that there will never be two widgets with the same name, but that is probably a unique case

@hanjinliu
Copy link
Collaborator

Yes, I definitely have to avoid adding widget of the same name on my side.
I think that adding widgets of the same name is always dangerous and it is a good idea to encourage people to make widgets from dataclass, TypedDict, pydantic BaseModel etc. to prevent collision errors at the language level.

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

Successfully merging this pull request may close these issues.

guiclass and the name reserved keyword
2 participants