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