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... > > > > Seriously: where does that code come from, who's typing it? If it is > > > python, > > > then make people follow python's rules. If it is some sort of homebrewn > > > language you map to python, adapt the mapper to enforce lower-case and > > > make > > > all your properties lower case. > > > > Diez > > So, this application you are writing for allows you to script/write > callbacks in python? They are then somehow accessable through a COM > interface exposed by the application? You are worried that someone > using the application will run into case-sensitivity if they access > the code written in python? > > There isn't much overhead with __getattr__ since it is _only_ called > if the initial look-up didn't find the name. You can do something like > this: > > class C(object): > def __init__(self, ...): > ... > self._lookingup = False > ... > > # If this is re-entered while already looking up a value, > # then we know that there is a problem. Not thread safe. > def __getattr__(self, attr): > try: > if self._lookingup: > raise AttributeError("'C' object has no attribute > %r"%attr) > self._lookingup = True > return getattr(self, attr.lower()) > finally: > self._lookingup = False > > def __setattr__(self, attr, value): > super(C, self).__setattr__(attr.lower(), value) > > Matt -- http://mail.python.org/mailman/listinfo/python-list