Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spookylukey/d8dfdab4ffd606a4404e24f1b699aa06 to your computer and use it in GitHub Desktop.
Save spookylukey/d8dfdab4ffd606a4404e24f1b699aa06 to your computer and use it in GitHub Desktop.
The make_OnboardingRenameTeamForm class was a hack to try to get around some problems:
We want to do this at module level:
OnboardingRenameTeamForm = global_preference_form_builder(preferences=[("organization_name", "branding")])
However, this is a problem because `global_preference_form_builder` does database queries,
which is in general a bad idea to do when modules are loading, and it breaks our test suite badly.
First idea - change `OnboardingRenameTeamForm` to a function that will return the form - the wizard shouldn't
know the difference:
def OnboardingRenameTeamForm(*args, **kwargs):
actual_form_class = global_preference_form_builder(preferences=[("organization_name", "branding")])
return actual_form_class(*args, **kwargs)
Problem: the wizard *does* know the difference, because it does an `isinstance` check to detect
form classes. This is an even bigger problem, because `isinstance` on a function doesn't just
return False, it throws an error. So, we need to supply something like a class, but when the class
is called, it should return a different type of thing. That's what the `__new__` thing is supposed
to do, a bit like this: https://stackoverflow.com/questions/20221858/python-new-method-returning-something-other-than-class-instance
Except I didn't test it and messed it up. Here is my debugging using a simplified case:
I couldn't see how `data` could get passed multiple times, but from experience I'm guessing this
is something to do with `data` being the first positional arg, so the code is trying to pass both
the first positional arg and the `data` kwarg.
Debugging in IPython:
In [1]: class Form:
...: def __init__(self, data=None, other=None):
...: pass
...:
In [2]: class FormMaker:
...: def __new__(*args, **kwargs):
...: return Form(*args, **kwargs)
...:
In [3]: FormMaker()
Out[3]: <__main__.Form at 0x7ff3de21a8c0>
In [4]: Form(data="test")
Out[4]: <__main__.Form at 0x7ff3de21a320>
In [4]: FormMaker(data="test")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[4], line 1
----> 1 FormMaker(data="test")
Cell In[2], line 3, in FormMaker.__new__(*args, **kwargs)
2 def __new__(*args, **kwargs):
----> 3 return Form(*args, **kwargs)
OK, good I've got the same error. Print debugging on what those args are:
In [5]: class FormMaker:
...: def __new__(*args, **kwargs):
...: print(args)
...: print(kwargs)
...: return Form(*args, **kwargs)
...:
In [6]: FormMaker(data="test")
(<class '__main__.FormMaker'>,)
{'data': 'test'}
Confirmed - it's passing a positional arg, which is a class object. I messed up the signature to
`__new__`, which should start with `cls`. Fix:
In [8]: class FormMaker:
...: def __new__(cls, *args, **kwargs):
...: print(args)
...: print(kwargs)
...: return Form(*args, **kwargs)
...:
In [9]: FormMaker(data="test")
()
{'data': 'test'}
Out[9]: <__main__.Form at 0x7ff3dc8ef1c0>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment