Making class attributes non-case-sensitive?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Rafe

    Making class attributes non-case-sensitive?

    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>.lo wer() based compare?).

    Any ideas or precedence?


    Cheers,

    - Rafe
  • Diez B. Roggisch

    #2
    Re: Making class attributes non-case-sensitive?

    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>.lo wer() 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

    Comment

    • Rafe

      #3
      Re: Making class attributes non-case-sensitive?

      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" <de...@nospam.w eb.dewrote:
      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>.lo wer() 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

      Comment

      • Diez B. Roggisch

        #4
        Re: Making class attributes non-case-sensitive?

        Rafe 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?
        I still don't get the full picture - anyway, what I infer is this:

        - for your own sake, you want to stick with "proper" naming, whatever that
        means

        - you can't control what will be called.

        Then I'd go with the __getattr__-way, plus maybe a meta-class (or
        postprocessing) that maps all attributes to a lower-case-variant as well,
        so that the lookup is efficient.

        Does that help?

        Diez

        Comment

        • Fuzzyman

          #5
          Re: Making class attributes non-case-sensitive?

          On Oct 13, 10:11 am, Rafe <rafesa...@gmai l.comwrote:
          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>.lo wer() based compare?).
          >
          Any ideas or precedence?
          If you define '__getattr__' then it will only be called for attribute
          names that don't exist. So only explicitly define the names you want
          in the lowercase variant and then have something like the following:

          def __getattr__(sel f, name):
          return object.__getatt r__(self, name.lower())

          That way each name only appears once and you only get the extra
          '__getattr__' in your epydoc docs.

          Michael

          >
          Cheers,
          >
          - Rafe
          --
          Pedestrian accidents can happen in the blink of an eye, changing lives forever. When you're out for a stroll or crossing the street, an unexpected collision

          Comment

          • Peter Pearson

            #6
            Re: Making class attributes non-case-sensitive?

            On Mon, 13 Oct 2008 04:08:03 -0700 (PDT), Rafe <rafesacks@gmai l.comwrote:
            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,
            [snip]
            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.
            [Much other stuff I didn't understand is snipped here.]

            I apologize in advance if this appears unhelpful. I
            couldn't make hide nor hair of the above explanation.

            The apparent requirement that there be no boundary between
            the software's developers (who presumably are trained and
            can learn case conventions) and its users is a completely
            new one to me. Can you possibly make such software
            reliable? Doesn't this open you up to the mother of all SQL
            injection attacks? I really would like to understand the
            circumstances in which "Keep the users out of the code" (or,
            pretty much equivalent, "Don't let the implementation
            language drive the user interface") isn't the right answer.

            --
            To email me, substitute nowhere->spamcop, invalid->net.

            Comment

            • Matimus

              #7
              Re: Making class attributes non-case-sensitive?

              On Oct 13, 4:08 am, Rafe <rafesa...@gmai l.comwrote:
              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" <de...@nospam.w eb.dewrote:
              >
              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>.lo wer() 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__(sel f, 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__(sel f, attr, value):
              super(C, self).__setattr __(attr.lower() , value)

              Matt

              Comment

              • Rafe

                #8
                Re: Making class attributes non-case-sensitive?

                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)
                "CapitalizedWor ds" 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.GetActiveSc eneRoot();

                // 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.A pplication').Ap plication
                XSI.LogMessage( "Welcome to XSI!")
                root = XSI.ActiveScene Root


                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("Capit alizedWords"),
                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.A pplication').Ap plication
                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("my3D Object")
                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 DelegationWrapp er(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__(sel f, 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__(sel f, 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.__setatt r__(self, name, val)
                return

                # Try to delegate to the X3DObject.
                try:
                self.__dict__["__obj"].__setattr__(na me, 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 <mccre...@gmail .comwrote:
                On Oct 13, 4:08 am, Rafe <rafesa...@gmai l.comwrote:
                >
                >
                >
                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" <de...@nospam.w eb.dewrote:
                >
                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__, butI
                I am concerned about the overhead of every delegated attribute call
                running a search and compare (<paramName>.lo wer() 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__(sel f, 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__(sel f, attr, value):
                        super(C, self).__setattr __(attr.lower() , value)
                >
                Matt

                Comment

                • Rafe

                  #9
                  Re: Making class attributes non-case-sensitive?

                  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 DelegationWrapp er(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__(sel f, 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__(sel f, 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.__setatt r__(self, name, val)
                  return

                  # Try to delegate to the X3DObject.
                  try:
                  self.__dict__["__obj"].__setattr__(na me, 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 <rafesa...@gmai l.comwrote:
                  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)
                  "CapitalizedWor ds" 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.GetActiveSc eneRoot();
                  >
                      // 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.A pplication').Ap plication
                      XSI.LogMessage( "Welcome to XSI!")
                      root = XSI.ActiveScene Root
                  >
                  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("Capit alizedWords"),
                  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.A pplication').Ap plication
                  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("my3D Object")
                  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 DelegationWrapp er(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__(sel f, 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__(sel f, 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.__setatt r__(self, name, val)
                              return
                  >
                          # Try to delegate to the X3DObject.
                          try:
                              self.__dict__["__obj"].__setattr__(na me, 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 <mccre...@gmail .comwrote:
                  >
                  On Oct 13, 4:08 am, Rafe <rafesa...@gmai l.comwrote:
                  >
                  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" <de...@nospam.w eb.dewrote:
                  >
                  Rafe wrote:
                  Hi,
                  >
                  I'm working within an application (making a lot of wrappers), butthe
                  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 getan
                  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>.lo wer() based compare?)..
                  >
                  Any ideas or precedence?
                  >
                  Ideas? Don't do that...
                  >
                  ...
                  >
                  read more »

                  Comment

                  • Rafe

                    #10
                    Re: Making class attributes non-case-sensitive?

                    [I posted a version of the following but it contained a broken
                    example. I deleted it through GoogleGroups, but I'm adding this
                    message in case the old version is still visible on the list. If it
                    isn't ignore this.]


                    I really appreciate the replies. I hope you guys 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)
                    "CapitalizedWor ds" 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.GetActiveSc eneRoot();

                    // 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.A pplication').Ap plication
                    XSI.LogMessage( "Welcome to XSI!")
                    root = XSI.ActiveScene Root

                    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("Capit alizedWords"),
                    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.A pplication').Ap plication
                    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("my3D Object")
                    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 DelegationWrapp er(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__(sel f, name):
                    """
                    Tries to delegate any attribute calls not found in
                    this class to the X3DObject.
                    """
                    # Try to delegate to the 3DObject.
                    obj = self.__dict__["_DelegationWra pper__obj"]
                    try:
                    return getattr(obj, 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__(sel f, 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 ("_"):
                    super(Delegatio nWrapper, self).__setattr __(name, val)
                    return

                    # Try to delegate to the X3DObject.
                    obj = self.__dict__["_DelegationWra pper__obj"]
                    try:
                    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)


                    def set_name(self, val):
                    self.__obj.name = val

                    def get_name(self):
                    return self.__obj.name

                    name = property(get_na me, set_name)


                    # Usage...
                    class A(object):
                    name = "a name"
                    test = "a test"

                    a = A()
                    b = DelegationWrapp er(a)
                    print b.name
                    print b.test
                    b.name = "new name"
                    print b.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 <mccre...@gmail .comwrote:
                    On Oct 13, 4:08 am, Rafe <rafesa...@gmai l.comwrote:
                    >
                    >
                    >
                    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" <de...@nospam.w eb.dewrote:
                    >
                    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__, butI
                    I am concerned about the overhead of every delegated attribute call
                    running a search and compare (<paramName>.lo wer() 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__(sel f, 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__(sel f, attr, value):
                            super(C, self).__setattr __(attr.lower() , value)
                    >
                    Matt

                    Comment

                    • Matimus

                      #11
                      Re: Making class attributes non-case-sensitive?

                      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
                      It still isn't clear to me _why_ you are wrapping this COM object. You
                      aren't adding any functionality. If you are using win32com and the TLB
                      object you are using has a tlb, then you can generate wrapper classes
                      for them automatically using makepy. You can extend those. If you want
                      to do it by hand you should be able to just create a class and inherit
                      win32com.client .DispatchBaseCl ass (and object if you want to make it
                      new-style). Unless your users are screaming for this feature, or there
                      is some technical reason that it is required, then implementing it is
                      a waste of time. Anybody who is used to developing at all is going to
                      accept that the software is case sensitive.

                      Matt

                      Comment

                      • Rafe

                        #12
                        Re: Making class attributes non-case-sensitive?

                        Thanks for the COM pointers Matt. I'll definitely look in to these.
                        Perhaps this will become a non-issue when I use one of these COM
                        wrappers...

                        Anybody who is used to developing at all is going to
                        accept that the software is case sensitive.
                        Case sensitive? Yes. Letting types create hard to debug behaviors that
                        raise either no exceptions or strange ones? No. This is what I am
                        trying to add. Protection.

                        It still isn't clear to me _why_ you are wrapping this COM object. You
                        aren't adding any functionality.
                        I've actually been able to add a lot of functionality. I just didn't
                        post the details of how I'm using it because I didn't think it had any
                        bearing on the original question. I can add a lot of automation and
                        convention enforcement to the API by wrapping and extending the
                        applications object-model. If you want me to give some real-world
                        examples (which would be related to 3D animation production) I
                        wouldn't mind doing so at all. I was just trying really hard to keep
                        the question generic (and failed it seems).


                        Thanks again for sticking with the discussion!

                        - Rafe


                        On Oct 15, 4:03 am, Matimus <mccre...@gmail .comwrote:
                        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
                        >
                        It still isn't clear to me _why_ you are wrapping this COM object. You
                        aren't adding any functionality. If you are using win32com and the TLB
                        object you are using has a tlb, then you can generate wrapper classes
                        for them automatically using makepy. You can extend those. If you want
                        to do it by hand you should be able to just create a class and inherit
                        win32com.client .DispatchBaseCl ass (and object if you want to make it
                        new-style). Unless your users are screaming for this feature, or there
                        is some technical reason that it is required, then implementing it is
                        a waste of time. Anybody who is used to developing at all is going to
                        accept that the software is case sensitive.
                        >
                        Matt

                        Comment

                        Working...