datacenter / cobra

Cobra - Python bindings for the ACI REST API
Other
89 stars 41 forks source link

Accessing attributes of an MO that overlap with python reserved words fails #116

Open mtimm opened 8 years ago

mtimm commented 8 years ago

Example:

>>> from cobra.mit.access import MoDirectory
>>> from cobra.mit.session import LoginSession
>>> ls = LoginSession('http://10.1.1.200', 'admin', 'p@ssw0rd)
>>> md = MoDirectory(ls)
>>> md.login()
>>> encap = md.lookupByClass("fvnsEncapBlk")
>>> encap[0].to
'vlan-2230'
>>> encap[0].from
  File "<stdin>", line 1
    encap[0].from
                ^
SyntaxError: invalid syntax
>>> encap[0].from_
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "cobra/mit/mo.py", line 100, in __getattr__
    return BaseMo.__getattr__(self, propName)
  File "cobra/internal/base/moimpl.py", line 288, in __getattr__
    return self.__children._getChildContainer(attrName)
  File "cobra/internal/base/moimpl.py", line 193, in _getChildContainer
    childPrefix)
AttributeError: No class with prefix "from_" found
>>> getattr(encap[0], "from")
'vlan-2220'
>>> 

We need a generic solution to access an attribute that overlaps with a python builtin/reserved keyword or to document how to access attributes like this in a more clear way.

PropMeta shows the original attribute and not the one with an _ appended to it:

>>> pprint(vars(encap[0].meta.props))
{'_props': {'allocMode': <cobra.mit.meta.PropMeta object at 0x1079383d0>,
            'childAction': <cobra.mit.meta.PropMeta object at 0x1079384d0>,
            'descr': <cobra.mit.meta.PropMeta object at 0x1079385d0>,
            'dn': <cobra.mit.meta.PropMeta object at 0x107938610>,
            'from': <cobra.mit.meta.PropMeta object at 0x107938650>,
            'lcOwn': <cobra.mit.meta.PropMeta object at 0x107938690>,
            'modTs': <cobra.mit.meta.PropMeta object at 0x107938810>,
            'name': <cobra.mit.meta.PropMeta object at 0x107938890>,
            'rn': <cobra.mit.meta.PropMeta object at 0x1079388d0>,
            'status': <cobra.mit.meta.PropMeta object at 0x107938910>,
            'to': <cobra.mit.meta.PropMeta object at 0x107938a10>,
            'uid': <cobra.mit.meta.PropMeta object at 0x107938a50>}}
>>> 
JLeClerc commented 8 years ago

getattr() will work:

from cobra.mit.access import MoDirectory
from cobra.mit.session import LoginSession
ls = LoginSession('http://10.1.1.200', 'admin', 'p@ssw0rd)
md = MoDirectory(ls)
md.login()
encap = md.lookupByClass("fvnsEncapBlk")
encap[0].from
#>>> *** SyntaxError: invalid syntax (<stdin>, line 1)
getattr(encap[0], 'from')
#>>> 'vlan-1500'
mtimm commented 8 years ago

Hi Joe,

I included the getattr workaround in my original description of the problem.

Mike

JLeClerc commented 8 years ago

Hi Mike,

Sorry, I read that too quickly the first time. Restating the problem, we cannot access object attributes through dot-notation because they conflict with Python reserved keywords which causes the parser to raise a syntax error. So we either have to change the attribute names or use something other than dot notation.

Solution #1 - obvious and likely a bad idea - change the attribute names:

@property
def From(self):
    return self._from

Solution #2 - using something other than dot-notation (or getattr() function directly) - e.g ElementTree-style access

# getattr
encap[0].attrib['from']
# setattr
encap[0].update({'desc': 'outside encap'})

I could write something similar to #2 - we just need to decide what the syntax should look like.

Thanks, Joe

mtimm commented 8 years ago

When we generate the model for cobra we explicitly change the attribute names that overlap with python reserved words to include an at the end, in this case the model should have from. However, it doesn't appear that we carry this forward inside cobra so when we instantiate the property we do so with the original name which is in propMeta, I haven't looked into why this is though.