I'm not sure what went wrong with the formatting in my last post. my code is under 80 characters wide. Here is a more narrow copy and paste...
class DelegationWrapper(object): """ This is a new-style base class that allows python to extend, or override attributes of a given X3DObject. :parameters: obj : object instance If this class (or a sub-class of this class) do not have an attribute, this wrapped object will be checked before failing. """ def __init__(self, obj): """ Store the object to delegate to. """ self.__obj = obj def __repr__(self): """ Makes the object's name the string representation of the object, just like XSI does. """ return str(self.__obj.name) def __getattr__(self, name): """ Tries to delegate any attribute calls not found in this class to the X3DObject. """ # Try to delegate to the 3DObject. obj = self.__dict__["__obj"] try: return obj.__getattr__(name) except: pass # Raise an attribute error (Python requires this # to avoid problems) className = self.__class__.__name__ msg = "%s has no attribute '%s'." % (className, name) raise AttributeError(msg) def __setattr__(self, name, val): """ Tries to delegate any attribute assignment not found in this class to the X3DObject. """ # This allows sub-classes to add "private" attributes # freely. dir is checked insteaf od __dict__ because # it contains bound attributes not available in the # instance __dict__. if name in dir(self) or name.startswith("_"): object.__setattr__(self, name, val) return # Try to delegate to the X3DObject. try: self.__dict__["__obj"].__setattr__(name, val) return except TypeError, err: raise TypeError(err) except AttributeError: pass # raised later except Exception, err: raise Exception(err) # Don't allow addition of new 'public' attributes # with AttributeError className = self.__class__.__name__ msg = "%s has no attribute '%s'." % (className, name) raise AttributeError(msg) @property def name(self): """ This doesn't do anything here, but in my real code it does. The problem is, if the user types 'Name' this will be bypassed. """ return self.__obj.Name - Rafe On Oct 14, 11:29 am, Rafe <[EMAIL PROTECTED]> wrote: > I really appreciate the replies. I hope you gyus will stick with me > through one more round. > > super(C, self).__setattr__(attr.lower(), value) > > Unfortunately, this will not work because an attribute name such as > "getObject" is legal (I'll explain the convention in a moment.) I > think I would have to loop over all attributes and force both sides of > the compare to lower case to test for a match. > > just skip ahead to the example code if you don't want more confusing > background ;) > > Bear with me while I try to explain. > > Basically, I am working with this application like (I think) any > application would work through a COM object. That said, I can access > python from within the application as well because it is a kind of dev > environment. 3D applications are blended GUI and development > environment and users are expected to use it through both the API and > the GUI. What may seem strange to most people here, is that you will > get hard-core programmers and surface-level users (and everything in > between, like me) working and/or developing in the same environment. > These 3D software applications are quite large and complex. > > The application is called "Softimage|XSI", commonly called "XSI". It > is a 3D application. Most companies will licenses the software but > then build layers on top of it for pipeline productivity and > communication reasons. So, it is standard for a user of the > application to also write scripts or more complex OO models. I > mentioned it was written during the brief period of time where > Softimage was owned by Microsoft because I thought there might be some > precedence for the case sensitivity issues. It was not written by > Microsoft engineers directly, but they did enforce *some* standards. > > The common naming convention in XSI is (using PEP008 terminology) > "CapitalizedWords" for objects and functions/methods, and "mixedCase" > for variables: This is from the C++ API: > > C++ Example: connecting to XSI > // gets the application object, which you can use to communicate > with XSI > Application app; > app.LogMessage( "Welcome to XSI!" ); > > C++ Example: creating an X3DObject > // returns the reference root object > namespace XSI; > Application app; > CRef rootRef = app.GetActiveSceneRoot(); > > // create object with a reference object > X3DObject rootObj(rootRef); > > The python version of the above C++ example looks like this. > from win32com.client.dynamic import Dispatch > XSI = Dispatch('XSI.Application').Application > XSI.LogMessage("Welcome to XSI!") > root = XSI.ActiveSceneRoot > > As for the convention I chose, it is right out of PEP008. > "Function Names > > Function names should be lowercase, with words separated by > underscores > as necessary to improve readability. > > mixedCase is allowed only in contexts where that's already the > prevailing style (e.g. threading.py), to retain backwards > compatibility." > > Too keep my code in line with XSI's API, I took this second part to > hear. All other conventions are in line with PEP008 I believe. Lastly, > though I can see how this might sound confusing, I stick with the XSI > API convension exactly when accessing it directly("CapitalizedWords"), > but anything I write is PEP008 with mixedCase. > > The most important part of all this though is my original issue. For > some reason, the XSI implementation is not case sensitive. This > works!... > > from win32com.client.dynamic import Dispatch > XSI = Dispatch('XSI.Application').Application > XSI.LogMessage("Welcome to XSI!") > XSI.loGmeSSAGE("Welcome to XSI!") > > This is probably totally usless info for this discussion (like I > haven't already provided enough of that!), but the XSI API, or object > model, is a little like a complex XML DOM tree... > > obj = XSI.Dictionary.GetObject("my3DObject") > children = obj.Children > for child in children: > XSI.LogMessage(child.Name) > > To wrap and override the 'name' attribute I use this class. (Note I > had some trouble with __setattr__ but this IS stable. I welcome > comments as this is probably one of the most confusing things to work > with for new python users.) > > class DelegationWrapper(object): > """ > This is a new-style base class that allows python to extend, or > override > attributes of a given X3DObject. > > :parameters: > obj : object instance > If this class (or a sub-class of this class) do not have > an > attribute, this wrapped object will be checked before > failing. > """ > def __init__(self, obj): > """ > Store the object to delegate to. > """ > self.__obj = obj > > def __repr__(self): > """ > Makes the object's name the string representation of the > object, just > like XSI does. > """ > return str(self.__obj.name) > > def __getattr__(self, name): > """ > Tries to delegate any attribute calls not found in this class > to the > X3DObject. > """ > # Try to delegate to the 3DObject. > obj = self.__dict__["__obj"] > try: > return obj.__getattr__(name) > except: > pass > > # Raise an attribute error (Python requires this to avoid > problems) > className = self.__class__.__name__ > raise AttributeError("%s has no attribute '%s'." % (className, > name)) > > def __setattr__(self, name, val): > """ > Tries to delegate any attribute assignment not found in this > class to > the X3DObject. > """ > # This allows sub-classes to add "private" attributes freely. > # dir is checked insteaf od __dict__ because it contains bound > # attributes not available in the instance __dict__. > if name in dir(self) or name.startswith("_"): > object.__setattr__(self, name, val) > return > > # Try to delegate to the X3DObject. > try: > self.__dict__["__obj"].__setattr__(name, val) > return > except TypeError, err: > raise TypeError(err) > except AttributeError: > pass # raised later > except Exception, err: > raise Exception(err) > > # Don't allow addition of new 'public' attributes with > AttributeError > className = self.__class__.__name__ > raise AttributeError("%s has no attribute '%s'." % (className, > name)) > > @property > def name(self): > """ > This doesn't do anything here, but in my real code it does. > The > problem is, if the user types 'Name' this will be bypassed. > """ > return self.__obj.Name > > So is iterating through dir() to force both the members of dir(), and > the requested attribute name, to lower case for a comparison, really > the easiest way? > > Thanks again for sticking with me. I hope I didn't add to the > confusion. What I learn I will of course pass on. > > - Rafe > > On Oct 14, 12:14 am, Matimus <[EMAIL PROTECTED]> wrote: > > > On Oct 13, 4:08 am, Rafe <[EMAIL PROTECTED]> wrote: > > > > Just so I don't hijack my own thread, the issue is 'how to wrap an > > > object which is not case sensitive'. > > > > The reason I am stuck dealing with this?... The application's API is > > > accessed through COM, so I don't know if I can do anything but react > > > to what I get. The API was written while the app (Softimage|XSI - one > > > of 3 leading 3D applications for high-end visual effects) was owned by > > > Microsoft. I'm not sure if it is standard for Microsoft or just the > > > way this app was implemented (perhaps because under-users were > > > scripting in VBscript which is not case sensitive). > > > > XSI allows many languages to be used via COM, even from within the > > > software (there are built-in code editors). In the early days, > > > VBScript was the most common scripting language used while anything > > > more hard-core was done in C++ (of course the C implementation is case > > > sensitive - well as far as I know). Then JScript became the most > > > common, now Python is considered standard. > > > > Anyway, the standard practice is to use mixed-case, so I need to > > > adhere to it as the resulting framework I am creating needs to be > > > intuitive to use (my end-user is still writing code. It's an API for > > > an API I guess...) > > > > I don't *think* I need to worry too much about performance because I'm > > > not doing any serious processing, this is more about convention > > > enforcement and quality control rather than number crunching. I might > > > try to write something generic which gets executed by the wrappers > > > __getattr__ and __setattr__, but I was hoping for some nifty > > > workaround, maybe in the form of a decorator or something? Again... > > > any ideas? > > > > Cheers, > > > > - Rafe > > > > On Oct 13, 4:15 pm, "Diez B. Roggisch" <[EMAIL PROTECTED]> wrote: > > > > > Rafe wrote: > > > > > Hi, > > > > > > I'm working within an application (making a lot of wrappers), but the > > > > > application is not case sensitive. For example, Typing obj.name, > > > > > obj.Name, or even object.naMe is all fine (as far as the app is > > > > > concerned). The problem is, If someone makes a typo, they may get an > > > > > unexpected error due accidentally calling the original attribute > > > > > instead of the wrapped version. Does anyone have a simple solution for > > > > > this? > > > > > > I can protect against some cases just by making an 'alias': > > > > > class AClass(object): > > > > > def name(self): > > > > > print "hello" > > > > > > Name = name > > > > > > ...but this doesn't protect against typos, it gets more complicated > > > > > with multi-word attribute names, and it makes my epydocs confusing to > > > > > read since all spelling versions are shown (I AM concerned about my > > > > > docs being clear, but not as much as stopping typo related errors). > > > > > > I thought about using my wrapper's __getattr__ and __setattr__, but I > > > > > I am concerned about the overhead of every delegated attribute call > > > > > running a search and compare (<paramName>.lower() based compare?). > > > > > > Any ideas or precedence? > > > > > Ideas? Don't do that... > > ... > > read more » -- http://mail.python.org/mailman/listinfo/python-list