1import os
2import sys
3import traceback
4from _pydev_bundle.pydev_imports import xmlrpclib, _queue, Exec
5from  _pydev_bundle._pydev_calltip_util import get_description
6from _pydevd_bundle import pydevd_vars
7from _pydevd_bundle import pydevd_xml
8from _pydevd_bundle.pydevd_constants import (IS_JYTHON, dict_iter_items, NEXT_VALUE_SEPARATOR, get_global_debugger,
9    silence_warnings_decorator)
10from contextlib import contextmanager
11from _pydev_bundle import pydev_log
12from _pydevd_bundle.pydevd_utils import interrupt_main_thread
13
14try:
15    import cStringIO as StringIO  # may not always be available @UnusedImport
16except:
17    try:
18        import StringIO  # @Reimport
19    except:
20        import io as StringIO
21
22
23# =======================================================================================================================
24# BaseStdIn
25# =======================================================================================================================
26class BaseStdIn:
27
28    def __init__(self, original_stdin=sys.stdin, *args, **kwargs):
29        try:
30            self.encoding = sys.stdin.encoding
31        except:
32            # Not sure if it's available in all Python versions...
33            pass
34        self.original_stdin = original_stdin
35
36        try:
37            self.errors = sys.stdin.errors  # Who knew? sys streams have an errors attribute!
38        except:
39            # Not sure if it's available in all Python versions...
40            pass
41
42    def readline(self, *args, **kwargs):
43        # sys.stderr.write('Cannot readline out of the console evaluation\n') -- don't show anything
44        # This could happen if the user had done input('enter number).<-- upon entering this, that message would appear,
45        # which is not something we want.
46        return '\n'
47
48    def write(self, *args, **kwargs):
49        pass  # not available StdIn (but it can be expected to be in the stream interface)
50
51    def flush(self, *args, **kwargs):
52        pass  # not available StdIn (but it can be expected to be in the stream interface)
53
54    def read(self, *args, **kwargs):
55        # in the interactive interpreter, a read and a readline are the same.
56        return self.readline()
57
58    def close(self, *args, **kwargs):
59        pass  # expected in StdIn
60
61    def __iter__(self):
62        # BaseStdIn would not be considered as Iterable in Python 3 without explicit `__iter__` implementation
63        return self.original_stdin.__iter__()
64
65    def __getattr__(self, item):
66        # it's called if the attribute wasn't found
67        if hasattr(self.original_stdin, item):
68            return getattr(self.original_stdin, item)
69        raise AttributeError("%s has no attribute %s" % (self.original_stdin, item))
70
71
72# =======================================================================================================================
73# StdIn
74# =======================================================================================================================
75class StdIn(BaseStdIn):
76    '''
77        Object to be added to stdin (to emulate it as non-blocking while the next line arrives)
78    '''
79
80    def __init__(self, interpreter, host, client_port, original_stdin=sys.stdin):
81        BaseStdIn.__init__(self, original_stdin)
82        self.interpreter = interpreter
83        self.client_port = client_port
84        self.host = host
85
86    def readline(self, *args, **kwargs):
87        # Ok, callback into the client to get the new input
88        try:
89            server = xmlrpclib.Server('http://%s:%s' % (self.host, self.client_port))
90            requested_input = server.RequestInput()
91            if not requested_input:
92                return '\n'  # Yes, a readline must return something (otherwise we can get an EOFError on the input() call).
93            else:
94                # readline should end with '\n' (not doing so makes IPython 5 remove the last *valid* character).
95                requested_input += '\n'
96            return requested_input
97        except KeyboardInterrupt:
98            raise  # Let KeyboardInterrupt go through -- #PyDev-816: Interrupting infinite loop in the Interactive Console
99        except:
100            return '\n'
101
102    def close(self, *args, **kwargs):
103        pass  # expected in StdIn
104
105
106#=======================================================================================================================
107# DebugConsoleStdIn
108#=======================================================================================================================
109class DebugConsoleStdIn(BaseStdIn):
110    '''
111        Object to be added to stdin (to emulate it as non-blocking while the next line arrives)
112    '''
113
114    def __init__(self, py_db, original_stdin):
115        '''
116        :param py_db:
117            If None, get_global_debugger() is used.
118        '''
119        BaseStdIn.__init__(self, original_stdin)
120        self._py_db = py_db
121        self._in_notification = 0
122
123    def __send_input_requested_message(self, is_started):
124        try:
125            py_db = self._py_db
126            if py_db is None:
127                py_db = get_global_debugger()
128
129            if py_db is None:
130                return
131
132            cmd = py_db.cmd_factory.make_input_requested_message(is_started)
133            py_db.writer.add_command(cmd)
134        except Exception:
135            pydev_log.exception()
136
137    @contextmanager
138    def notify_input_requested(self):
139        self._in_notification += 1
140        if self._in_notification == 1:
141            self.__send_input_requested_message(True)
142        try:
143            yield
144        finally:
145            self._in_notification -= 1
146            if self._in_notification == 0:
147                self.__send_input_requested_message(False)
148
149    def readline(self, *args, **kwargs):
150        with self.notify_input_requested():
151            return self.original_stdin.readline(*args, **kwargs)
152
153    def read(self, *args, **kwargs):
154        with self.notify_input_requested():
155            return self.original_stdin.read(*args, **kwargs)
156
157
158class CodeFragment:
159
160    def __init__(self, text, is_single_line=True):
161        self.text = text
162        self.is_single_line = is_single_line
163
164    def append(self, code_fragment):
165        self.text = self.text + "\n" + code_fragment.text
166        if not code_fragment.is_single_line:
167            self.is_single_line = False
168
169
170# =======================================================================================================================
171# BaseInterpreterInterface
172# =======================================================================================================================
173class BaseInterpreterInterface:
174
175    def __init__(self, mainThread, connect_status_queue=None):
176        self.mainThread = mainThread
177        self.interruptable = False
178        self.exec_queue = _queue.Queue(0)
179        self.buffer = None
180        self.banner_shown = False
181        self.connect_status_queue = connect_status_queue
182        self.mpl_modules_for_patching = {}
183        self.init_mpl_modules_for_patching()
184
185    def build_banner(self):
186        return 'print({0})\n'.format(repr(self.get_greeting_msg()))
187
188    def get_greeting_msg(self):
189        return 'PyDev console: starting.\n'
190
191    def init_mpl_modules_for_patching(self):
192        from pydev_ipython.matplotlibtools import activate_matplotlib, activate_pylab, activate_pyplot
193        self.mpl_modules_for_patching = {
194            "matplotlib": lambda: activate_matplotlib(self.enableGui),
195            "matplotlib.pyplot": activate_pyplot,
196            "pylab": activate_pylab
197        }
198
199    def need_more_for_code(self, source):
200        # PyDev-502: PyDev 3.9 F2 doesn't support backslash continuations
201
202        # Strangely even the IPython console is_complete said it was complete
203        # even with a continuation char at the end.
204        if source.endswith('\\'):
205            return True
206
207        if hasattr(self.interpreter, 'is_complete'):
208            return not self.interpreter.is_complete(source)
209        try:
210            # At this point, it should always be single.
211            # If we don't do this, things as:
212            #
213            #     for i in range(10): print(i)
214            #
215            # (in a single line) don't work.
216            # Note that it won't give an error and code will be None (so, it'll
217            # use execMultipleLines in the next call in this case).
218            symbol = 'single'
219            code = self.interpreter.compile(source, '<input>', symbol)
220        except (OverflowError, SyntaxError, ValueError):
221            # Case 1
222            return False
223        if code is None:
224            # Case 2
225            return True
226
227        # Case 3
228        return False
229
230    def need_more(self, code_fragment):
231        if self.buffer is None:
232            self.buffer = code_fragment
233        else:
234            self.buffer.append(code_fragment)
235
236        return self.need_more_for_code(self.buffer.text)
237
238    def create_std_in(self, debugger=None, original_std_in=None):
239        if debugger is None:
240            return StdIn(self, self.host, self.client_port, original_stdin=original_std_in)
241        else:
242            return DebugConsoleStdIn(py_db=debugger, original_stdin=original_std_in)
243
244    def add_exec(self, code_fragment, debugger=None):
245        # In case sys.excepthook called, use original excepthook #PyDev-877: Debug console freezes with Python 3.5+
246        # (showtraceback does it on python 3.5 onwards)
247        sys.excepthook = sys.__excepthook__
248        try:
249            original_in = sys.stdin
250            try:
251                help = None
252                if 'pydoc' in sys.modules:
253                    pydoc = sys.modules['pydoc']  # Don't import it if it still is not there.
254
255                    if hasattr(pydoc, 'help'):
256                        # You never know how will the API be changed, so, let's code defensively here
257                        help = pydoc.help
258                        if not hasattr(help, 'input'):
259                            help = None
260            except:
261                # Just ignore any error here
262                pass
263
264            more = False
265            try:
266                sys.stdin = self.create_std_in(debugger, original_in)
267                try:
268                    if help is not None:
269                        # This will enable the help() function to work.
270                        try:
271                            try:
272                                help.input = sys.stdin
273                            except AttributeError:
274                                help._input = sys.stdin
275                        except:
276                            help = None
277                            if not self._input_error_printed:
278                                self._input_error_printed = True
279                                sys.stderr.write('\nError when trying to update pydoc.help.input\n')
280                                sys.stderr.write('(help() may not work -- please report this as a bug in the pydev bugtracker).\n\n')
281                                traceback.print_exc()
282
283                    try:
284                        self.start_exec()
285                        if hasattr(self, 'debugger'):
286                            self.debugger.enable_tracing()
287
288                        more = self.do_add_exec(code_fragment)
289
290                        if hasattr(self, 'debugger'):
291                            self.debugger.disable_tracing()
292
293                        self.finish_exec(more)
294                    finally:
295                        if help is not None:
296                            try:
297                                try:
298                                    help.input = original_in
299                                except AttributeError:
300                                    help._input = original_in
301                            except:
302                                pass
303
304                finally:
305                    sys.stdin = original_in
306            except SystemExit:
307                raise
308            except:
309                traceback.print_exc()
310        finally:
311            sys.__excepthook__ = sys.excepthook
312
313        return more
314
315    def do_add_exec(self, codeFragment):
316        '''
317        Subclasses should override.
318
319        @return: more (True if more input is needed to complete the statement and False if the statement is complete).
320        '''
321        raise NotImplementedError()
322
323    def get_namespace(self):
324        '''
325        Subclasses should override.
326
327        @return: dict with namespace.
328        '''
329        raise NotImplementedError()
330
331    def __resolve_reference__(self, text):
332        """
333
334        :type text: str
335        """
336        obj = None
337        if '.' not in text:
338            try:
339                obj = self.get_namespace()[text]
340            except KeyError:
341                pass
342
343            if obj is None:
344                try:
345                    obj = self.get_namespace()['__builtins__'][text]
346                except:
347                    pass
348
349            if obj is None:
350                try:
351                    obj = getattr(self.get_namespace()['__builtins__'], text, None)
352                except:
353                    pass
354
355        else:
356            try:
357                last_dot = text.rindex('.')
358                parent_context = text[0:last_dot]
359                res = pydevd_vars.eval_in_context(parent_context, self.get_namespace(), self.get_namespace())
360                obj = getattr(res, text[last_dot + 1:])
361            except:
362                pass
363        return obj
364
365    def getDescription(self, text):
366        try:
367            obj = self.__resolve_reference__(text)
368            if obj is None:
369                return ''
370            return get_description(obj)
371        except:
372            return ''
373
374    def do_exec_code(self, code, is_single_line):
375        try:
376            code_fragment = CodeFragment(code, is_single_line)
377            more = self.need_more(code_fragment)
378            if not more:
379                code_fragment = self.buffer
380                self.buffer = None
381                self.exec_queue.put(code_fragment)
382
383            return more
384        except:
385            traceback.print_exc()
386            return False
387
388    def execLine(self, line):
389        return self.do_exec_code(line, True)
390
391    def execMultipleLines(self, lines):
392        if IS_JYTHON:
393            more = False
394            for line in lines.split('\n'):
395                more = self.do_exec_code(line, True)
396            return more
397        else:
398            return self.do_exec_code(lines, False)
399
400    def interrupt(self):
401        self.buffer = None  # Also clear the buffer when it's interrupted.
402        try:
403            if self.interruptable:
404                # Fix for #PyDev-500: Console interrupt can't interrupt on sleep
405                interrupt_main_thread(self.mainThread)
406
407            self.finish_exec(False)
408            return True
409        except:
410            traceback.print_exc()
411            return False
412
413    def close(self):
414        sys.exit(0)
415
416    def start_exec(self):
417        self.interruptable = True
418
419    def get_server(self):
420        if getattr(self, 'host', None) is not None:
421            return xmlrpclib.Server('http://%s:%s' % (self.host, self.client_port))
422        else:
423            return None
424
425    server = property(get_server)
426
427    def ShowConsole(self):
428        server = self.get_server()
429        if server is not None:
430            server.ShowConsole()
431
432    def finish_exec(self, more):
433        self.interruptable = False
434
435        server = self.get_server()
436
437        if server is not None:
438            return server.NotifyFinished(more)
439        else:
440            return True
441
442    def getFrame(self):
443        xml = StringIO.StringIO()
444        hidden_ns = self.get_ipython_hidden_vars_dict()
445        xml.write("<xml>")
446        xml.write(pydevd_xml.frame_vars_to_xml(self.get_namespace(), hidden_ns))
447        xml.write("</xml>")
448
449        return xml.getvalue()
450
451    @silence_warnings_decorator
452    def getVariable(self, attributes):
453        xml = StringIO.StringIO()
454        xml.write("<xml>")
455        val_dict = pydevd_vars.resolve_compound_var_object_fields(self.get_namespace(), attributes)
456        if val_dict is None:
457            val_dict = {}
458
459        for k, val in dict_iter_items(val_dict):
460            val = val_dict[k]
461            evaluate_full_value = pydevd_xml.should_evaluate_full_value(val)
462            xml.write(pydevd_vars.var_to_xml(val, k, evaluate_full_value=evaluate_full_value))
463
464        xml.write("</xml>")
465
466        return xml.getvalue()
467
468    def getArray(self, attr, roffset, coffset, rows, cols, format):
469        name = attr.split("\t")[-1]
470        array = pydevd_vars.eval_in_context(name, self.get_namespace(), self.get_namespace())
471        return pydevd_vars.table_like_struct_to_xml(array, name, roffset, coffset, rows, cols, format)
472
473    def evaluate(self, expression):
474        xml = StringIO.StringIO()
475        xml.write("<xml>")
476        result = pydevd_vars.eval_in_context(expression, self.get_namespace(), self.get_namespace())
477        xml.write(pydevd_vars.var_to_xml(result, expression))
478        xml.write("</xml>")
479        return xml.getvalue()
480
481    @silence_warnings_decorator
482    def loadFullValue(self, seq, scope_attrs):
483        """
484        Evaluate full value for async Console variables in a separate thread and send results to IDE side
485        :param seq: id of command
486        :param scope_attrs: a sequence of variables with their attributes separated by NEXT_VALUE_SEPARATOR
487        (i.e.: obj\tattr1\tattr2NEXT_VALUE_SEPARATORobj2\attr1\tattr2)
488        :return:
489        """
490        frame_variables = self.get_namespace()
491        var_objects = []
492        vars = scope_attrs.split(NEXT_VALUE_SEPARATOR)
493        for var_attrs in vars:
494            if '\t' in var_attrs:
495                name, attrs = var_attrs.split('\t', 1)
496
497            else:
498                name = var_attrs
499                attrs = None
500            if name in frame_variables:
501                var_object = pydevd_vars.resolve_var_object(frame_variables[name], attrs)
502                var_objects.append((var_object, name))
503            else:
504                var_object = pydevd_vars.eval_in_context(name, frame_variables, frame_variables)
505                var_objects.append((var_object, name))
506
507        from _pydevd_bundle.pydevd_comm import GetValueAsyncThreadConsole
508        py_db = getattr(self, 'debugger', None)
509
510        if py_db is None:
511            py_db = get_global_debugger()
512
513        if py_db is None:
514            from pydevd import PyDB
515            py_db = PyDB()
516
517        t = GetValueAsyncThreadConsole(py_db, self.get_server(), seq, var_objects)
518        t.start()
519
520    def changeVariable(self, attr, value):
521
522        def do_change_variable():
523            Exec('%s=%s' % (attr, value), self.get_namespace(), self.get_namespace())
524
525        # Important: it has to be really enabled in the main thread, so, schedule
526        # it to run in the main thread.
527        self.exec_queue.put(do_change_variable)
528
529    def connectToDebugger(self, debuggerPort, debugger_options=None):
530        '''
531        Used to show console with variables connection.
532        Mainly, monkey-patches things in the debugger structure so that the debugger protocol works.
533        '''
534
535        if debugger_options is None:
536            debugger_options = {}
537        env_key = "PYDEVD_EXTRA_ENVS"
538        if env_key in debugger_options:
539            for (env_name, value) in dict_iter_items(debugger_options[env_key]):
540                existing_value = os.environ.get(env_name, None)
541                if existing_value:
542                    os.environ[env_name] = "%s%c%s" % (existing_value, os.path.pathsep, value)
543                else:
544                    os.environ[env_name] = value
545                if env_name == "PYTHONPATH":
546                    sys.path.append(value)
547
548            del debugger_options[env_key]
549
550        def do_connect_to_debugger():
551            try:
552                # Try to import the packages needed to attach the debugger
553                import pydevd
554                from _pydev_imps._pydev_saved_modules import threading
555            except:
556                # This happens on Jython embedded in host eclipse
557                traceback.print_exc()
558                sys.stderr.write('pydevd is not available, cannot connect\n')
559
560            from _pydevd_bundle.pydevd_constants import set_thread_id
561            from _pydev_bundle import pydev_localhost
562            set_thread_id(threading.currentThread(), "console_main")
563
564            VIRTUAL_FRAME_ID = "1"  # matches PyStackFrameConsole.java
565            VIRTUAL_CONSOLE_ID = "console_main"  # matches PyThreadConsole.java
566            f = FakeFrame()
567            f.f_back = None
568            f.f_globals = {}  # As globals=locals here, let's simply let it empty (and save a bit of network traffic).
569            f.f_locals = self.get_namespace()
570
571            self.debugger = pydevd.PyDB()
572            self.debugger.add_fake_frame(thread_id=VIRTUAL_CONSOLE_ID, frame_id=VIRTUAL_FRAME_ID, frame=f)
573            try:
574                pydevd.apply_debugger_options(debugger_options)
575                self.debugger.connect(pydev_localhost.get_localhost(), debuggerPort)
576                self.debugger.prepare_to_run()
577                self.debugger.disable_tracing()
578            except:
579                traceback.print_exc()
580                sys.stderr.write('Failed to connect to target debugger.\n')
581
582            # Register to process commands when idle
583            self.debugrunning = False
584            try:
585                import pydevconsole
586                pydevconsole.set_debug_hook(self.debugger.process_internal_commands)
587            except:
588                traceback.print_exc()
589                sys.stderr.write('Version of Python does not support debuggable Interactive Console.\n')
590
591        # Important: it has to be really enabled in the main thread, so, schedule
592        # it to run in the main thread.
593        self.exec_queue.put(do_connect_to_debugger)
594
595        return ('connect complete',)
596
597    def handshake(self):
598        if self.connect_status_queue is not None:
599            self.connect_status_queue.put(True)
600        return "PyCharm"
601
602    def get_connect_status_queue(self):
603        return self.connect_status_queue
604
605    def hello(self, input_str):
606        # Don't care what the input string is
607        return ("Hello eclipse",)
608
609    def enableGui(self, guiname):
610        ''' Enable the GUI specified in guiname (see inputhook for list).
611            As with IPython, enabling multiple GUIs isn't an error, but
612            only the last one's main loop runs and it may not work
613        '''
614
615        def do_enable_gui():
616            from _pydev_bundle.pydev_versioncheck import versionok_for_gui
617            if versionok_for_gui():
618                try:
619                    from pydev_ipython.inputhook import enable_gui
620                    enable_gui(guiname)
621                except:
622                    sys.stderr.write("Failed to enable GUI event loop integration for '%s'\n" % guiname)
623                    traceback.print_exc()
624            elif guiname not in ['none', '', None]:
625                # Only print a warning if the guiname was going to do something
626                sys.stderr.write("PyDev console: Python version does not support GUI event loop integration for '%s'\n" % guiname)
627            # Return value does not matter, so return back what was sent
628            return guiname
629
630        # Important: it has to be really enabled in the main thread, so, schedule
631        # it to run in the main thread.
632        self.exec_queue.put(do_enable_gui)
633
634    def get_ipython_hidden_vars_dict(self):
635        return None
636
637
638# =======================================================================================================================
639# FakeFrame
640# =======================================================================================================================
641class FakeFrame:
642    '''
643    Used to show console with variables connection.
644    A class to be used as a mock of a frame.
645    '''
646