Repository: cocotb/cocotb

Issue:
IPython tab complete spews a bunch of _raise_testerror and stacktrace
If I start an embedded IPython shell in my sim and tab complete on dut, I get a bunch of cocotb ERROR messages.
And a stacktrace from the `_raise_testerror` function in `handle.py`.

I've stuck the output of my sim below.

This comes about as we're using `__getattr__` in SimHandle to raise cocotb test errors, when trying to access non-existent attributes (or in our cases simulator signals).
python's dir and IPython's dir2 expect an AttributeError.
In `cocotb/handle.py`, replacing:

``` python
self._raise_testerror("%s contains no object named %s" % (self.name, name))
```

with:

```
raise AttributeError, name
```

makes tab complete work as expected.

The attributes python's builtin dir searches for are -

``` python
__methods__
__members__
```

these seem to be legacy class documentation standards before the python type and class introspection code was added.
There's a description here:
https://docs.python.org/dev/whatsnew/2.2.html#descriptors

The attributes IPython's dir2 searches for are:

``` python
trait_names
_getAttributeNames
```

The comment in the IPython code is pretty self explanatory (from `IPython/utils/dir2.py`):

``` python
    # for objects with Enthought's traits, add trait_names() list
    # for PyCrust-style, add _getAttributeNames() magic method list
```

Seems to me raising an AttributeError when `__getattr__` is called with these arguments will let tab complete work as expected.

I'll submit a pull request with my change.

cheers,
Luke

``` bash
In [1]: dut.    30.01ns ERROR    cocotb.justy_top                              handle.py:110  in _raise_testerror                justy_top contains no object named __members__
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 334, in react
                                                                                                                                   self.schedule(coro, trigger=trigger)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 461, in schedule
                                                                                                                                   result = coroutine.send(sendval)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/decorators.py", line 186, in send
                                                                                                                                   return self._coro.send(value)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/lukes_cocotb_tests/basic_tests.py", line 44, in startup
                                                                                                                                   IPython.embed()
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 268, in embed
                                                                                                                                   shell(header=header, stack_depth=2, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 126, in __call__
                                                                                                                                   global_ns=global_ns, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 209, in mainloop
                                                                                                                                   self.interact(display_banner=display_banner)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 461, in interact
                                                                                                                                   line = self.raw_input(prompt)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 530, in raw_input
                                                                                                                                   line = py3compat.str_to_unicode(self.raw_input_original(prompt))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1167, in rlcomplete
                                                                                                                                   self.complete(text, line_buffer, cursor_pos)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1091, in complete
                                                                                                                                   self.matches.extend(matcher(text))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 717, in python_matches
                                                                                                                                   matches = self.attr_matches(text)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 393, in attr_matches
                                                                                                                                   words = dir2(obj)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/utils/dir2.py", line 64, in dir2
                                                                                                                                   words = set(dir(obj))

    30.01ns ERROR    cocotb.justy_top                              handle.py:110  in _raise_testerror                justy_top contains no object named __methods__
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 334, in react
                                                                                                                                   self.schedule(coro, trigger=trigger)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 461, in schedule
                                                                                                                                   result = coroutine.send(sendval)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/decorators.py", line 186, in send
                                                                                                                                   return self._coro.send(value)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/lukes_cocotb_tests/basic_tests.py", line 44, in startup
                                                                                                                                   IPython.embed()
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 268, in embed
                                                                                                                                   shell(header=header, stack_depth=2, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 126, in __call__
                                                                                                                                   global_ns=global_ns, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 209, in mainloop
                                                                                                                                   self.interact(display_banner=display_banner)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 461, in interact
                                                                                                                                   line = self.raw_input(prompt)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 530, in raw_input
                                                                                                                                   line = py3compat.str_to_unicode(self.raw_input_original(prompt))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1167, in rlcomplete
                                                                                                                                   self.complete(text, line_buffer, cursor_pos)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1091, in complete
                                                                                                                                   self.matches.extend(matcher(text))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 717, in python_matches
                                                                                                                                   matches = self.attr_matches(text)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 393, in attr_matches
                                                                                                                                   words = dir2(obj)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/utils/dir2.py", line 64, in dir2
                                                                                                                                   words = set(dir(obj))

    30.01ns ERROR    cocotb.justy_top                              handle.py:110  in _raise_testerror                justy_top contains no object named trait_names
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 334, in react
                                                                                                                                   self.schedule(coro, trigger=trigger)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 461, in schedule
                                                                                                                                   result = coroutine.send(sendval)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/decorators.py", line 186, in send
                                                                                                                                   return self._coro.send(value)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/lukes_cocotb_tests/basic_tests.py", line 44, in startup
                                                                                                                                   IPython.embed()
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 268, in embed
                                                                                                                                   shell(header=header, stack_depth=2, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 126, in __call__
                                                                                                                                   global_ns=global_ns, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 209, in mainloop
                                                                                                                                   self.interact(display_banner=display_banner)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 461, in interact
                                                                                                                                   line = self.raw_input(prompt)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 530, in raw_input
                                                                                                                                   line = py3compat.str_to_unicode(self.raw_input_original(prompt))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1167, in rlcomplete
                                                                                                                                   self.complete(text, line_buffer, cursor_pos)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1091, in complete
                                                                                                                                   self.matches.extend(matcher(text))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 717, in python_matches
                                                                                                                                   matches = self.attr_matches(text)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 393, in attr_matches
                                                                                                                                   words = dir2(obj)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/utils/dir2.py", line 78, in dir2
                                                                                                                                   func = getattr(obj, attr)

    30.01ns ERROR    cocotb.justy_top                              handle.py:110  in _raise_testerror                justy_top contains no object named _getAttributeNames
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 334, in react
                                                                                                                                   self.schedule(coro, trigger=trigger)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/scheduler.py", line 461, in schedule
                                                                                                                                   result = coroutine.send(sendval)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/cocotb/cocotb/decorators.py", line 186, in send
                                                                                                                                   return self._coro.send(value)
                                                                                                                                 File "/mnt/mag_drive/projects/justy/work/luke/justy/sim/chipsim/lukes_cocotb_tests/basic_tests.py", line 44, in startup
                                                                                                                                   IPython.embed()
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 268, in embed
                                                                                                                                   shell(header=header, stack_depth=2, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 126, in __call__
                                                                                                                                   global_ns=global_ns, compile_flags=compile_flags)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/embed.py", line 209, in mainloop
                                                                                                                                   self.interact(display_banner=display_banner)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 461, in interact
                                                                                                                                   line = self.raw_input(prompt)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 530, in raw_input
                                                                                                                                   line = py3compat.str_to_unicode(self.raw_input_original(prompt))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1167, in rlcomplete
                                                                                                                                   self.complete(text, line_buffer, cursor_pos)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 1091, in complete
                                                                                                                                   self.matches.extend(matcher(text))
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 717, in python_matches
                                                                                                                                   matches = self.attr_matches(text)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/core/completer.py", line 393, in attr_matches
                                                                                                                                   words = dir2(obj)
                                                                                                                                 File "/tools/oss/packages/x86_64-rhel5/python/2.7.5/lib/python2.7/site-packages/IPython/utils/dir2.py", line 78, in dir2
                                                                                                                                   func = getattr(obj, attr)


dut.fullname           dut.getvalue           dut.log                dut.name               dut.setcachedvalue     dut.setimmediatevalue  dut.value              

In [1]: dut.
```



Discussion:

Resolving patch:
diff --git a/cocotb/handle.py b/cocotb/handle.py
--- a/cocotb/handle.py
+++ b/cocotb/handle.py
@@ -80,6 +80,10 @@ def __getattr__(self, name):
         """ Query the simulator for a object with the specified name
             and cache the result to build a tree
         """
+        # python's builtin dir and IPython's dir2 search for these, 
+        # raise an AttributeError to avoid incorrect calls to _raise_testerror
+        if name in ["__methods__","__members__","trait_names","_getAttributeNames"]:
+            raise AttributeError(name)
         if name in self._sub_handles:
             return self._sub_handles[name]
         new_handle = simulator.get_handle_by_name(self._handle, name)


Test patch: