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.
arameters:
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
...
read more »