Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Getting the parent of a dynamically method as a function
-
Other ways to bind a new method to an object instance (class not affected):
- Using types, really binding:
import types btn.msg = types.MethodType(test_func, btn)
- Using functools, just add the object to be always included as the first argument (like the lambda):
from functools import partial btn.msg = partial(test_func, btn)
-
@mikael beat me to it.. I was going to suggest partial if you prefer to not use lambda: https://docs.python.org/2/library/functools.html#functools.partial
-
Thanks everyone here for all the excellent feedback and help. Will have a go with types now. Looks straight fwd enough
-
@mikael , I was stumped there for a few mins because I am adding the extra functions from a dict. Where the k is method name and v is function/method (address).
But I did the below. It works. But not really understanding this well enough, just wanted to ask as you guys if this is seen as an acceptable way call it. As I say, it works great. Just want to be sure I haven't overlooked something
Thanks
for k,v in _extended_methods.iteritems(): setattr(ctl, k, types.MethodType(v, ctl)) #ctl. = types.MethodType(v, ctl)
-
Coming back to this...
Here is how I add functionality to built-in ui classes these days, using ProxyTypes.
import ui from proxy import ObjectWrapper class ButtonWrapper(ObjectWrapper): def __init__(self, obj): ObjectWrapper.__init__(self, obj) def msg(self, leader): print leader + ': ' + self.name button = ButtonWrapper(ui.Button(name = 'Wrapped ui.Button')) button.msg('Calling extra method')
-
@mikael said:
Coming back to this...
Here is how I add functionality to built-in ui classes these days, using ProxyTypes.
import ui
from proxy import ObjectWrapperclass ButtonWrapper(ObjectWrapper):
def init(self, obj):
ObjectWrapper.init(self, obj)
def msg(self, leader):
print leader + ': ' + self.namebutton = ButtonWrapper(ui.Button(name = 'Wrapped ui.Button'))
button.msg('Calling extra method')
@mikael, sorry just revisiting this. But is above complete? I just mean button is no longer considered a ui.View.
Sorry, I have a idea, I am just totally missing the point here -
I am heavily utilizing this in my current project, so I can confirm that it works. The only gotcha I have found is that you have to give
proxy_view.__subject__
instead of just the proxy_view to add_subview since, as you say, proxy_view is not descended from View. And likewise for ObjCInstance, if you are using objc_util. -
@Phuket2, that said, I think I understand what you are aiming for in your recent discussions, and agree that we are not there yet. Let me get back to this.
-
@mikael , ok. Sorry been a while since I looked at this. I just thought there was some magic happening that I was not getting
-
So, I think that one of the things we want is the ability to style UI components with inheritance. This is relatively straightforward and clean with the proxy approach:
# coding: utf-8 import ui from proxy import ObjectWrapper class DefaultStyle(ObjectWrapper): def __init__(self, obj): ObjectWrapper.__init__(self, obj) self.background_color = '#fff7ee' self.tint_color = 'black' class HighlightStyle(DefaultStyle): def __init__(self, obj): DefaultStyle.__init__(self, obj) self.tint_color = 'red' button = HighlightStyle(ui.Button()) button.title = 'Styled button' button.present()
-
@mikael , hmmm. I am having a bad day today. Nothing is working 😱
You can see below I have to
from peak.util.proxies import ObjectWrapper
I can't
from proxy import ObjectWrapperBut I am getting a no module named 'pkg_resources' error. Are you on v2 beta?
Could be something with the beta# coding: utf-8 import ui #from proxy import ObjectWrapper from peak.util.proxies import ObjectWrapper class DefaultStyle(ObjectWrapper): def __init__(self, obj): ObjectWrapper.__init__(self, obj) self.background_color = '#fff7ee' self.tint_color = 'black' class HighlightStyle(DefaultStyle): def __init__(self, obj): DefaultStyle.__init__(self, obj) self.tint_color = 'red' button = HighlightStyle(ui.Button()) button.title = 'Styled button' button.present()
-
Sorry, I have the proxies code in a different place, but it is the same code. And yes, I am on v2 beta.
-
@mikael said:
Sorry, I have the proxies code in a different place, but it is the same code. And yes, I am on v2 beta.
If you get time could you please show me the dir structure you have, I have tried modifying it, I just get the same error. I just tried moving the proxies.py up one level. As the init files in both dirs contain the same statement
import('pkg_resources').declare_namespace(name)
But still same error. -
I have proxies.py in the same directory, it does not need anything else. Could of course also be in site packages.
I guess this is partly why it would be so nice to have it "built in".
-
@mikael , mine is in site-packages. I installed it with stash. It's ok, I don't know what's going on. I will look into it. As I say, nothing is going smoothly today 😜
Have completely shut down my ipad. Didn't help -
Wrappers also chain nicely, so you might have e.g. styles in a different inheritance hierarchy and extra functionality in other.
The only thing that is not chained is subject, so it probably makes sense inherit from a common base class and include a method that does the chaining, as follows:
# coding: utf-8 import ui from proxy import ObjectWrapper class ChainableWrapper(ObjectWrapper): def __init__(self, obj): ObjectWrapper.__init__(self, obj) # Follow the chain of __subject__'s, if needed def get_subject(self): subject = self.__subject__ while isinstance(subject, ObjectWrapper): subject = subject.__subject__ return subject class DefaultStyle(ChainableWrapper): def __init__(self, obj): super(DefaultStyle, self).__init__(obj) self.background_color = '#fff7ee' self.tint_color = 'black' class HighlightStyle(DefaultStyle): def __init__(self, obj): super(HighlightStyle, self).__init__(obj) self.tint_color = 'red' class ToggleButton(ChainableWrapper): def __init__(self, obj): super(ToggleButton, self).__init__(obj) def extra_functionality(self): pass button = ToggleButton(HighlightStyle(ui.Button())) button.title = 'Styled button' button.present() # Get the wrapped ui.* instance some_other_view.add_subview(button.get_subject())
-
@omz, would there be any chance to have add_subview accept proxies in addition to direct view objects? And have ObjCInstance recognize proxies and use the underlying reference instead?
-
@mikael , just let you know, I got it working again. For some reason my version of ProxyTypes was corrupt 😂
-
I wrote the below on another thread. I think it would help a lot without having to change much. Not sure what you think. Was not sure you seen it or not.
Phuket2 posted a day ago reply quote 0
I am not sure if being able to subclass ui compents is in the wind or will ever be. But I thought of something that may be quite useful, at least in my mind.
The simplest form of my idea is that you could call a ui method that sets a callback function that is called upon creation of any ui component. We could be passed the object type, or worse case check with type.
A little more refined would be able to also set different callbacks for the different types of ui components.That would offer a lot of flexibility and possibilities. Also, especially when testing would be so easy just to style the objects. I know, you can still just have a make button function anyway. But this just seems so much cleaner.
Not sure the impact this would have on performance or threading issues etc. I assume threading type problems would not be an issue as it would only be called on creation.
-
@Phuket2, thanks, I did see it, and read it with interest.
In the end I think I did not yet fully grasp the intended use case and value when compared to the effort:
- Styling objects has not been a major source of pain for me
- It feels like it could actually be a bit of effort for omz to implement in the UI module
- I try to avoid callbacks as long as I can
- Could lead to some really hard-to-debug situations when you take someone else's code and you both have used these callbacks
You could try it out by making a function that you use to wrap every object creation and call the callback(s).