From: Kevin A. <al...@se...> - 2006-09-15 23:52:46
|
I'm moving this discussion to the developer list until we have a solution... On Sep 15, 2006, at 5:13 AM, Alex Tweedly wrote: > Jussi Salmela wrote: > >> Hello all and particularly Alex Tweedly, I guess! >> >> I'm using Python 2.4.3, wxPython 2.3.0, PythonCard 0.8.2 and its >> Resource Editor on Win XP SP2. >> >> 1. I have an ImageButton and a bunch of other components on my page. >> 2. I enter >> open >> into the command field of the ImageButton component in the >> Property Editor. >> 3. I click some other component(s) active and then click ImageButton >> active again. >> 4. The command field now contains >> <type 'file'> >> instead of the open I entered earlier. >> 5. If I now run my program I get an error, so not only the display is >> erroneous but also the resource file. >> 6. If I retype open in the command field, save and run, everything >> works >> as expected. >> >> > Hmmmm - very interesting. > > 1. It's not unique to ImageButton - happens with any component. > 2. It's (probably) not unique to the 'command' attribute - should > happen > to some others, but I haven't tried too hard to see which ones it > happens with. > > It's caused by the following snippet of code in > modules/propertyEditor.py (and /multipropertyEditor,.py): > >> if propName not in ['label', 'stringSelection', 'text', >> 'toolTip', 'userdata']: >> try: >> value = eval(value) >> except: >> pass > > I'm not 100% sure why this was wanted. It does let you do interesting > things - e.g. you can enter a string such as > 3+8 > and it will be evaluated to 11 for you. You can enter a string like > [20+3*15, 17] > and it will be evaluated (to [65,17]) for, say, the position > value. And > various other more strange possibilities > (e.g. enter self.position and you get the current co-ords > of the > property editor window !!) > > But I'm not clear on what the *useful* purpose of this eval is. > > In any case, the two oddities I know about are 'open' and 'file' > which both eval to <type 'file'> (though there may be others). > > Suggestions (please comment): > > 1. short term - just avoid either open or file as command names :-) > > 2. figure out an exhaustive list of strings which eval to something > they > "shouldn't", and explicitly check for them (??) > > 3. decide that you never want to eval the user-entered value to > produce > a Python type, so add a test something like > if not isinstance(eval(value), types.TypeType) : > before resetting the variable 'value', thus > if propName not in ['label', 'stringSelection', 'text', 'toolTip', > 'userdata']: > try: > if not isinstance(eval(value), types.TypeType) : > value = > eval(value) > except: > pass > > 4. decide whether there is real purpose in doing an 'eval' here at > all, > and if there is, limiting the use to those cases, somehow. > > > > -- > Alex Tweedly al...@tw... http://www.tweedly.net The current strategy for the property editor uses a single text field where we expect the user to enter a value that is then turned into the appropriate type. Since a TextField or TextArea can only display a string, the if statement was simply checking whether the expected data in the text field should be a string and the eval is for converting strings to numbers, tuples, lists, dictionaries, etc. Obviously, that isn't very bullet-proof so we could do a couple of things to make this work better. As I look at the old code the other thing I've realized is just how much of it needs to be rewritten so there probably isn't a quick fix that will solve all the possible problems. Since we don't want to try and convert string attributes to other types I've added a line to list all of the attributes that we don't want to attempt to convert. This may not be complete, but this is what I checked in: self.stringItems = self.popItems + ['alignment', 'command', 'file', 'label', 'name', 'text', 'toolTip', 'userdata'] I updated displayProperty to use this new variable as well as an additional check for when the value might be None which should deal with 'command'. def displayProperty(self, wName, wClass, propName): self.components.wName.text = propName + ":" ##widget = self.components[wName] widget = self._comp[wName] if propName in self.stringItems or propName in self.checkItems: value = getattr(widget, propName) else: value = str(getattr(widget, propName)) ... if value == None: self.components.wField.text = '' else: self.components.wField.text = value updateComponent got a similar change, including breaking up the handling of items and indenting the value conversion so it isn't done except as part of the default conversion. I haven't done extensive testing, but given that this is a logic change, conversions that used to work may not work now. I'm also a bit wary of places where we might have had None that might be an empty string now. Either way, Alex will make similar changes to his property editor code and then we can simply bang on it prior to a 0.8.3 release. def updateComponent(self): wName, wClass = self.components.wComponentList.stringSelection.split(" : ") propName = self.components.wPropertyList.stringSelection if propName in self.checkItems: value = self.components.wChecked.checked elif propName in self.popItems: value = self.components.wPop.stringSelection elif propName == 'items': value = self.components.wTextArea.text # KEA 2006-09-15 # need better error handling try: value = eval(value) except: pass elif propName == 'userdata' or (wClass == 'TextArea' and propName == 'text'): value = self.components.wTextArea.text else: value = self.components.wField.text if propName not in self.stringItems: # KEA 2006-09-15 # need better error handling try: value = eval(value) except: pass ka |