Repository: microsoft/ptvsd

Issue:
AttributeError when debug class overriding __dir__
<!-- Please search existing issues to avoid creating duplicates. -->

## Environment data

- VS Code version: 1.40.2
- Extension version (available under the Extensions sidebar): 2019.11.50794
- OS and version: Windows_NT x64 10.0.17134
- Python version (& distribution if applicable, e.g. Anaconda): Python 3.6.8 64-bit
- Type of virtual environment used (N/A | venv | virtualenv | conda | ...): NA
- Relevant/affected Python packages and their versions: NA
- Jedi or Language Server? (i.e. what is `"python.jediEnabled"` set to; more info microsoft/vscode-python#3977): Language Server

## Expected behaviour

No exception

## Actual behaviour

Exception occur

## Steps to reproduce:

create a python file with below content:
```python
class A():
    def __init__(self):
        self.attr = {}

    def __dir__(self):
        return list(self.attr)

if __name__ == '__main__':
    a = A()
```
add breakpoint on line 3, and start debug.
Once break, there is a variable `self` in `Locals` of `Variables` in debug panel, click to show the properties of `self`.
Then error occur.


It just because calling `__dir__` before it complete `__init__`.
I think the solution is catch `AttributeError` in method `get_names` of `pydevd_resolver.py`, then `names = []` or `names = object.__dir__(var)`

## Logs
Output from `Console` under the `Developer Tools` panel

```
  File "test.py", line 3, in __init__
    self.attr = {}
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_frame.py", line 606, in trace_dispatch
    self.do_wait_suspend(thread, frame, event, arg)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_frame.py", line 97, in do_wait_suspend
    self._args[0].do_wait_suspend(*args, **kwargs)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\pydevd.py", line 1616, in do_wait_suspend
    keep_suspended = self._do_wait_suspend(thread, frame, event, arg, suspend_type, from_this_thread, frames_tracker)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\pydevd.py", line 1644, in _do_wait_suspend
    self.process_internal_commands()
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\pydevd.py", line 1350, in process_internal_commands
    int_cmd.do_it(self)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_comm.py", line 502, in do_it
    self.method(dbg, *self.args, **self.kwargs)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_comm.py", line 675, in internal_get_variable_json
    for child_var in variable.get_children_variables(fmt=fmt):
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_suspended_frames.py", line 111, in get_children_variables
    lst = resolver.get_contents_debug_adapter_protocol(self.value, fmt=fmt)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_resolver.py", line 95, in get_contents_debug_adapter_protocol
    dct, used___dict__ = self._get_py_dictionary(obj)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_resolver.py", line 192, in _get_py_dictionary
    names, used___dict__ = self.get_names(var)
  File "c:\Users\xxxxx\.vscode\extensions\ms-python.python-2019.11.50794\pythonFiles\lib\python\old_ptvsd\ptvsd\_vendored\pydevd\_pydevd_bundle\pydevd_resolver.py", line 170, in get_names
    names = dir(var)
  File "d:\xxxxx\Desktop\test.py", line 6, in __dir__
    return list(self.attr)
AttributeError: 'A' object has no attribute 'attr'
```



Discussion:
@fabioz, can you take a look? The proposed fix - an exception guard + fallback to `object.__dir__()` - makes sense to me.
I'll take a look at it.

Resolving patch:
diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_resolver.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_resolver.py
--- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_resolver.py
+++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_resolver.py
@@ -168,7 +168,7 @@ def get_names(self, var):
         used___dict__ = False
         try:
             names = dir(var)
-        except TypeError:
+        except Exception:
             names = []
         if not names:
             if hasattr(var, '__dict__'):


Test patch:
diff --git a/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_dir_exception.py b/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_dir_exception.py
new file mode 100644
--- /dev/null
+++ b/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_dir_exception.py
@@ -0,0 +1,13 @@
+class A():
+
+    def __init__(self):
+        self.var1 = 10
+        self.attr = {}  # Break here
+
+    def __dir__(self):
+        return list(self.attr)
+
+
+if __name__ == '__main__':
+    a = A()
+    print('TEST SUCEEDED!')
diff --git a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py
--- a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py
+++ b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py
@@ -1093,6 +1093,28 @@ def test_stack_and_variables_dict(case_setup):
         writer.finished_ok = True
 
 
+@pytest.mark.skipif(IS_PY26, reason='__dir__ not customizable on Python 2.6')
+def test_exception_on_dir(case_setup):
+    with case_setup.test_file('_debugger_case_dir_exception.py') as writer:
+        json_facade = JsonFacade(writer)
+
+        writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
+        json_facade.write_make_initial_run()
+
+        json_hit = json_facade.wait_for_thread_stopped()
+        json_hit = json_facade.get_stack_as_json_hit(json_hit.thread_id)
+
+        variables_response = json_facade.get_variables_response(json_hit.frame_id)
+
+        variables_references = json_facade.pop_variables_reference(variables_response.body.variables)
+        variables_response = json_facade.get_variables_response(variables_references[0])
+        assert variables_response.body.variables == [
+            {'variablesReference': 0, 'type': 'int', 'evaluateName': 'self.__dict__[var1]', 'name': 'var1', 'value': '10'}]
+
+        json_facade.write_continue()
+        writer.finished_ok = True
+
+
 @pytest.mark.parametrize('scenario', [
     'step_in',
     'step_next',