Ejemplo n.º 1
0
def test_sys_exitfunc():
    import clr

    inputScript = testpath.test_inputs_dir + "\\exitFuncRuns.py"
    ipi = IronPythonInstance(executable, exec_prefix,
                             extraArgs + " \"" + inputScript + "\"")
    (result, output, output2, exitCode) = ipi.StartAndRunToCompletion()
    AreEqual(exitCode, 0)
    AreEqual(output.find('hello world') > -1, True)
    ipi.End()

    args = extraArgs

    if clr.GetCurrentRuntime().Configuration.DebugMode:
        args = "-D " + args

    inputScript = testpath.test_inputs_dir + "\\exitFuncRaises.py"
    ipi = IronPythonInstance(executable, exec_prefix,
                             args + " \"" + inputScript + "\"")
    (result, output, output2, exitCode) = ipi.StartAndRunToCompletion()
    AreEqual(exitCode, 0)
    AreEqual(output2.find('Error in sys.exitfunc:') > -1, True)

    AreEqual(output2.find('exitFuncRaises.py", line 19, in foo') > -1, True)

    ipi.End()

    # verify sys.exit(True) and sys.exit(False) return 1 and 0

    ipi = IronPythonInstance(executable, exec_prefix,
                             '-c "import sys; sys.exit(False)"')
    res = ipi.StartAndRunToCompletion()
    AreEqual(res[0], True)  # should have started
    AreEqual(res[1], '')  # no std out
    AreEqual(res[2], '')  # no std err
    AreEqual(res[3], 0)  # should return 0

    ipi = IronPythonInstance(executable, exec_prefix,
                             '-c "import sys; sys.exit(True)"')
    res = ipi.StartAndRunToCompletion()
    AreEqual(res[0], True)  # should have started
    AreEqual(res[1], '')  # no std out
    AreEqual(res[2], '')  # no std err
    AreEqual(res[3], 1)  # should return 0

    # and verify it works at the interactive console as well
    ipi = IronPythonInstance(executable, exec_prefix, extraArgs)
    AreEqual(ipi.Start(), True)

    # parameterless exception
    ipi.ExecuteLine("import sys")
    AreEqual(ipi.ExecuteAndExit("sys.exit(False)"), 0)

    # and verify it works at the interactive console as well
    ipi = IronPythonInstance(executable, exec_prefix, extraArgs)
    AreEqual(ipi.Start(), True)

    # parameterless exception
    ipi.ExecuteLine("import sys")
    AreEqual(ipi.ExecuteAndExit("sys.exit(True)"), 1)
Ejemplo n.º 2
0
    def execute_code_work_item(self):
        _debug_write('Executing: ' + repr(self.current_code))
        stripped_code = self.current_code.strip()

        if sys.platform == 'cli':
            code_to_send = ''
            for line in stripped_code.split('\n'):
                stripped = line.strip()
                if (stripped.startswith('#')
                        or not stripped) and not code_to_send:
                    continue
                code_to_send += line + '\n'

            code = python_context.CreateSnippet(code_to_send, None,
                                                SourceCodeKind.InteractiveCode)
            dispatcher = clr.GetCurrentRuntime().GetLanguage(
                PythonContext).GetCommandDispatcher()
            if dispatcher is not None:
                dispatcher(self.python_executor(code))
            else:
                code.Execute(self.exec_mod)
        else:
            code = compile(self.current_code, '<stdin>', 'single',
                           self.code_flags)
            self.code_flags |= (code.co_flags & BasicReplBackend.future_bits)
            exec(code, self.exec_mod.__dict__, self.exec_mod.__dict__)
        self.current_code = None
Ejemplo n.º 3
0
        def parse_text(text):
            errorSink = MyErrorSink()
            sourceUnit = SourceUnit(
                clr.GetCurrentRuntime().GetLanguageByName('python'),
                MyTextContentProvider(text), 'foo', SourceCodeKind.File)

            parser = Parser.CreateParser(
                CompilerContext(sourceUnit, PythonCompilerOptions(),
                                errorSink), PythonOptions())
            parser.ParseFile(True)
            return errorSink
Ejemplo n.º 4
0
    def setUp(self):
        super(MemoryTest, self).setUp()

        import clr
        clr.AddReference("Microsoft.Dynamic")
        from Microsoft.Scripting.Generation import Snippets

        self.skipMemoryCheck = Snippets.Shared.SaveSnippets or clr.GetCurrentRuntime().Configuration.DebugMode
        self.expectedMem = 24000

        # account for adaptive compilation
        if is_cli64:
            self.expectedMem = int(self.expectedMem*1.25)
Ejemplo n.º 5
0
    def get_dynamic_operations_field():
        if ClrClass.dynamic_operations_field:
            return ClrClass.dynamic_operations_field
        python_context = clr.GetCurrentRuntime().GetLanguage(PythonContext)
        dynamic_operations = DynamicOperations(python_context)

        typegen = Snippets.Shared.DefineType(
            "DynamicOperationsHolder" + str(hash(python_context)), object,
            True, False)
        typebld = typegen.TypeBuilder
        typebld.DefineField("DynamicOperations", DynamicOperations,
                            FieldAttributes.Public | FieldAttributes.Static)
        new_type = typebld.CreateType()
        ClrClass.dynamic_operations_field = new_type.GetField(
            "DynamicOperations")

        ClrClass.dynamic_operations_field.SetValue(None, dynamic_operations)

        return ClrClass.dynamic_operations_field
Ejemplo n.º 6
0
    are.Set()


def start():
    try:
        global app
        app = Application()
        app.Startup += on_startup
        app.ShutdownMode = ShutdownMode.OnExplicitShutdown
        app.Run()
    finally:
        clr.SetCommandDispatcher(None)


# If dispatcher is set, then assume that UI issues are already taken care of.
currentDispatcher = clr.GetCurrentRuntime().GetLanguage(
    PythonContext).GetCommandDispatcher()
if currentDispatcher is None:
    if Application.Current is None: dispatcher = None
    else: dispatcher = Application.Current.Dispatcher
    if dispatcher is None:
        t = Thread(ThreadStart(start))
        t.IsBackground = True
        t.ApartmentState = ApartmentState.STA
        t.Start()
        are.WaitOne()
    else:
        clr.SetCommandDispatcher(currentDispatcher)


def DispatchConsoleCommand(consoleCommand):
    if consoleCommand:
Ejemplo n.º 7
0
def test_engine_access_from_within():
    import clr
    from Microsoft.Scripting.Hosting import ScriptEngine
    pc = clr.GetCurrentRuntime().GetLanguageByName('python')
    engine = pc.GetModuleState(clr.GetClrType(ScriptEngine))
    Assert(engine is not None)
Ejemplo n.º 8
0
#
#
#####################################################################################

from iptest.assert_util import *

skiptest("win32")
skiptest("silverlight")  #no time.clock or GetTotalMemory

import clr

clr.AddReference("Microsoft.Dynamic")
from Microsoft.Scripting.Generation import Snippets
import gc

skipMemoryCheck = Snippets.Shared.SaveSnippets or clr.GetCurrentRuntime(
).Configuration.DebugMode

from time import clock


# GetTotalMemory() actually pulls in System
def evalLoop(N):
    for i in range(N):
        func = compile(code, '<>', 'exec')
        eval(func)


def evalTest(N):
    startMem = GetTotalMemory()
    startTime = clock()
    evalLoop(N)
def enable_attach(secret,
                  address=('0.0.0.0', DEFAULT_PORT),
                  certfile=None,
                  keyfile=None,
                  redirect_output=True):
    """Enables Python Tools for Visual Studio to attach to this process remotely
    to debug Python code.

    Parameters
    ----------
    secret : str
        Used to validate the clients - only those clients providing the valid
        secret will be allowed to connect to this server. On client side, the
        secret is prepended to the Qualifier string, separated from the
        hostname by ``'@'``, e.g.: ``'[email protected]:5678'``. If
        secret is ``None``, there's no validation, and any client can connect
        freely.
    address : (str, int), optional
        Specifies the interface and port on which the debugging server should
        listen for TCP connections. It is in the same format as used for
        regular sockets of the `socket.AF_INET` family, i.e. a tuple of
        ``(hostname, port)``. On client side, the server is identified by the
        Qualifier string in the usual ``'hostname:port'`` format, e.g.:
        ``'myhost.cloudapp.net:5678'``. Default is ``('0.0.0.0', 5678)``.
    certfile : str, optional
        Used to enable SSL. If not specified, or if set to ``None``, the
        connection between this program and the debugger will be unsecure,
        and can be intercepted on the wire. If specified, the meaning of this
        parameter is the same as for `ssl.wrap_socket`.
    keyfile : str, optional
        Used together with `certfile` when SSL is enabled. Its meaning is the
        same as for ``ssl.wrap_socket``.
    redirect_output : bool, optional
        Specifies whether any output (on both `stdout` and `stderr`) produced
        by this program should be sent to the debugger. Default is ``True``.

    Notes
    -----
    This function returns immediately after setting up the debugging server,
    and does not block program execution. If you need to block until debugger
    is attached, call `ptvsd.wait_for_attach`. The debugger can be detached
    and re-attached multiple times after `enable_attach` is called.

    This function can only be called once during the lifetime of the process.
    On a second call, `AttachAlreadyEnabledError` is raised. In circumstances
    where the caller does not control how many times the function will be
    called (e.g. when a script with a single call is run more than once by
    a hosting app or framework), the call should be wrapped in ``try..except``.

    Only the thread on which this function is called, and any threads that are
    created after it returns, will be visible in the debugger once it is
    attached. Any threads that are already running before this function is
    called will not be visible.
    """

    if not ssl and (certfile or keyfile):
        raise ValueError(
            'could not import the ssl module - SSL is not supported on this version of Python'
        )

    if sys.platform == 'cli':
        import clr
        x_tracing = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Tracing
        x_frames = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Frames
        if not x_tracing or not x_frames:
            raise RuntimeError(
                'IronPython must be started with -X:Tracing and -X:Frames options to support PTVS remote debugging.'
            )

    global _attach_enabled
    if _attach_enabled:
        raise AttachAlreadyEnabledError(
            'ptvsd.enable_attach() has already been called in this process.')
    _attach_enabled = True

    atexit.register(vspd.detach_process_and_notify_debugger)

    server = socket.socket(proto=socket.IPPROTO_TCP)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(address)
    server.listen(1)

    def server_thread_func():
        while True:
            client = None
            raw_client = None
            try:
                client, addr = server.accept()
                if certfile:
                    client = ssl.wrap_socket(client,
                                             server_side=True,
                                             ssl_version=ssl.PROTOCOL_TLSv1,
                                             certfile=certfile,
                                             keyfile=keyfile)
                write_bytes(client, PTVSDBG)
                write_int(client, PTVSDBG_VER)

                response = read_bytes(client, 7)
                if response != PTVSDBG:
                    continue
                dbg_ver = read_int(client)
                if dbg_ver != PTVSDBG_VER:
                    continue

                client_secret = read_string(client)
                if secret is None or secret == client_secret:
                    write_bytes(client, ACPT)
                else:
                    write_bytes(client, RJCT)
                    continue

                response = read_bytes(client, 4)

                if response == INFO:
                    try:
                        pid = os.getpid()
                    except AttributeError:
                        pid = 0
                    write_int(client, pid)

                    exe = sys.executable or ''
                    write_string(client, exe)

                    try:
                        username = getpass.getuser()
                    except AttributeError:
                        username = ''
                    write_string(client, username)

                    try:
                        impl = platform.python_implementation()
                    except AttributeError:
                        try:
                            impl = sys.implementation.name
                        except AttributeError:
                            impl = 'Python'

                    major, minor, micro, release_level, serial = sys.version_info

                    os_and_arch = platform.system()
                    if os_and_arch == "":
                        os_and_arch = sys.platform
                    try:
                        if sys.maxsize > 2**32:
                            os_and_arch += ' 64-bit'
                        else:
                            os_and_arch += ' 32-bit'
                    except AttributeError:
                        pass

                    version = '%s %s.%s.%s (%s)' % (impl, major, minor, micro,
                                                    os_and_arch)
                    write_string(client, version)

                    client.recv(1)

                elif response == ATCH:
                    debug_options = vspd.parse_debug_options(
                        read_string(client))
                    debug_options.setdefault('rules', []).append({
                        'path':
                        PY_ROOT,
                        'include':
                        False,
                    })
                    if redirect_output:
                        debug_options.add('RedirectOutput')

                    if vspd.DETACHED:
                        write_bytes(client, ACPT)
                        try:
                            pid = os.getpid()
                        except AttributeError:
                            pid = 0
                        write_int(client, pid)

                        major, minor, micro, release_level, serial = sys.version_info
                        write_int(client, major)
                        write_int(client, minor)
                        write_int(client, micro)

                        vspd.attach_process_from_socket(client,
                                                        debug_options,
                                                        report=True)
                        vspd.mark_all_threads_for_break(
                            vspd.STEPPING_ATTACH_BREAK)
                        _attached.set()
                        client = None
                    else:
                        write_bytes(client, RJCT)

                elif response == REPL:
                    if not vspd.DETACHED:
                        write_bytes(client, ACPT)
                        vspd.connect_repl_using_socket(client)
                        client = None
                    else:
                        write_bytes(client, RJCT)

            except (socket.error, OSError):
                pass
            finally:
                if client is not None:
                    client.close()

    server_thread = threading.Thread(target=server_thread_func)
    server_thread.setDaemon(True)
    server_thread.start()

    frames = []
    f = sys._getframe()
    while True:
        f = f.f_back
        if f is None:
            break
        frames.append(f)
    frames.reverse()
    cur_thread = vspd.new_thread()
    for f in frames:
        cur_thread.push_frame(f)

    def replace_trace_func():
        for f in frames:
            f.f_trace = cur_thread.trace_func

    replace_trace_func()
    sys.settrace(cur_thread.trace_func)
    vspd.intercept_threads(for_attach=True)
Ejemplo n.º 10
0
def enable_attach(secret,
                  address=('0.0.0.0', ptvsd.DEFAULT_PORT),
                  certfile=None,
                  keyfile=None,
                  redirect_output=True):
    if not ssl and (certfile or keyfile):
        raise ValueError(
            'could not import the ssl module - SSL is not supported on this version of Python'
        )

    if sys.platform == 'cli':
        # Check that IronPython was launched with -X:Frames and -X:Tracing, since we can't register our trace
        # func on the thread that calls enable_attach otherwise
        import clr
        x_tracing = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Tracing
        x_frames = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Frames
        if not x_tracing or not x_frames:
            raise RuntimeError(
                'IronPython must be started with -X:Tracing and -X:Frames options to support PTVS remote debugging.'
            )

    global _attach_enabled
    if _attach_enabled:
        raise ptvsd.AttachAlreadyEnabledError(
            'ptvsd.enable_attach() has already been called in this process.')
    _attach_enabled = True

    atexit.register(vspd.detach_process_and_notify_debugger)

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM,
                           socket.IPPROTO_TCP)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(address)
    server.listen(1)

    def server_thread_func():
        while True:
            client = None
            connection = None
            try:
                client, addr = server.accept()
                if certfile:
                    client = ssl.wrap_socket(client,
                                             server_side=True,
                                             ssl_version=ssl.PROTOCOL_TLSv1,
                                             certfile=certfile,
                                             keyfile=keyfile)

                connection = AttachLoop(client, secret, redirect_output, None)
                connection.send_event(
                    name='legacyRemoteConnected',
                    debuggerName=PTVSDBG,
                    debuggerProtocolVersion=PTVSDBG_VER,
                )
                connection.process_messages()
            except (socket.error, OSError):
                pass
            finally:
                if connection:
                    connection.close()

    server_thread = threading.Thread(target=server_thread_func)
    server_thread.setDaemon(True)
    server_thread.start()

    frames = []
    f = sys._getframe()
    while f is not None:
        frames.append(f)
        f = f.f_back
    frames.reverse()
    cur_thread = vspd.new_thread()
    for f in frames:
        cur_thread.push_frame(f)

    def replace_trace_func():
        for f in frames:
            f.f_trace = cur_thread.trace_func

    replace_trace_func()
    sys.settrace(cur_thread.trace_func)
    vspd.intercept_threads(for_attach=True)
Ejemplo n.º 11
0
if sys.platform == 'cli':
    # We need special handling to reset the abort for keyboard interrupt exceptions
    class ReplAbortException(Exception): pass

    import clr
    clr.AddReference('Microsoft.Dynamic')
    clr.AddReference('Microsoft.Scripting')
    clr.AddReference('IronPython')
    from Microsoft.Scripting import KeyboardInterruptException
    from Microsoft.Scripting import ParamDictionaryAttribute
    from IronPython.Runtime.Operations import PythonOps
    from IronPython.Runtime import PythonContext
    from Microsoft.Scripting import SourceUnit, SourceCodeKind
    from Microsoft.Scripting.Runtime import Scope

    python_context = clr.GetCurrentRuntime().GetLanguage(PythonContext)

    from System import DBNull, ParamArrayAttribute
    builtin_method_descriptor_type = type(list.append)

    import System
    NamespaceType = type(System)

class _OldClass:
    pass

_OldClassType = type(_OldClass)
_OldInstanceType = type(_OldClass())

class BasicReplBackend(ReplBackend):
    future_bits = 0x3e010   # code flags used to mark future bits
def enable_attach(secret, address = ('0.0.0.0', DEFAULT_PORT), certfile = None, keyfile = None, redirect_output = True):
    if not ssl and (certfile or keyfile):
        raise ValueError('could not import the ssl module - SSL is not supported on this version of Python')

    if sys.platform == 'cli':
        # Check that IronPython was launched with -X:Frames and -X:Tracing, since we can't register our trace
        # func on the thread that calls enable_attach otherwise
        import clr
        x_tracing = clr.GetCurrentRuntime().GetLanguageByExtension('py').Options.Tracing
        x_frames = clr.GetCurrentRuntime().GetLanguageByExtension('py').Options.Frames
        if not x_tracing or not x_frames:
            raise RuntimeError('IronPython must be started with -X:Tracing and -X:Frames options to support PTVS remote debugging.')

    global _attach_enabled
    if _attach_enabled:
        raise AttachAlreadyEnabledError('ptvsd.enable_attach() has already been called in this process.')
    _attach_enabled = True

    atexit.register(vspd.detach_process_and_notify_debugger)

    server = socket.socket(proto=socket.IPPROTO_TCP)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(address)
    server.listen(1)
    def server_thread_func():
        while True:
            client = None
            raw_client = None
            try:
                client, addr = server.accept()
                if certfile:
                    client = ssl.wrap_socket(client, server_side = True, ssl_version = ssl.PROTOCOL_TLSv1, certfile = certfile, keyfile = keyfile)
                write_bytes(client, PTVSDBG)
                write_int(client, PTVSDBG_VER)

                response = read_bytes(client, 7)
                if response != PTVSDBG:
                    continue
                dbg_ver = read_int(client)
                if dbg_ver != PTVSDBG_VER:
                    continue

                client_secret = read_string(client)
                if secret is None or secret == client_secret:
                    write_bytes(client, ACPT)
                else:
                    write_bytes(client, RJCT)
                    continue

                response = read_bytes(client, 4)

                if response == INFO:
                    try:
                        pid = os.getpid()
                    except AttributeError:
                        pid = 0
                    write_int(client, pid)

                    exe = sys.executable or ''
                    write_string(client, exe)

                    try:
                        username = getpass.getuser()
                    except AttributeError:
                        username = ''
                    write_string(client, username)

                    try:
                        impl = platform.python_implementation()
                    except AttributeError:
                        try:
                            impl = sys.implementation.name
                        except AttributeError:
                            impl = 'Python'

                    major, minor, micro, release_level, serial = sys.version_info

                    os_and_arch = platform.system()
                    if os_and_arch == "":
                        os_and_arch = sys.platform
                    try:
                        if sys.maxsize > 2**32:
                            os_and_arch += ' 64-bit'
                        else:
                            os_and_arch += ' 32-bit'
                    except AttributeError:
                        pass

                    version = '%s %s.%s.%s (%s)' % (impl, major, minor, micro, os_and_arch)
                    write_string(client, version)

                    # Don't just drop the connection - let the debugger close it after it finishes reading.
                    client.recv(1)

                elif response == ATCH:
                    debug_options = vspd.parse_debug_options(read_string(client))
                    debug_options.setdefault('rules', []).append({
                        'path': PY_ROOT,
                        'include': False,
                        })
                    if redirect_output:
                        debug_options.add('RedirectOutput')

                    if vspd.DETACHED:
                        write_bytes(client, ACPT)
                        try:
                            pid = os.getpid()
                        except AttributeError:
                            pid = 0
                        write_int(client, pid)

                        major, minor, micro, release_level, serial = sys.version_info
                        write_int(client, major)
                        write_int(client, minor)
                        write_int(client, micro)

                        vspd.attach_process_from_socket(client, debug_options, report = True)
                        vspd.mark_all_threads_for_break(vspd.STEPPING_ATTACH_BREAK)
                        _attached.set()
                        client = None
                    else:
                        write_bytes(client, RJCT)

                elif response == REPL:
                    if not vspd.DETACHED:
                        write_bytes(client, ACPT)
                        vspd.connect_repl_using_socket(client)
                        client = None
                    else:
                        write_bytes(client, RJCT)

            except (socket.error, OSError):
                pass
            finally:
                if client is not None:
                    client.close()

    server_thread = threading.Thread(target = server_thread_func)
    server_thread.setDaemon(True)
    server_thread.start()

    frames = []
    f = sys._getframe()
    while True:
        f = f.f_back
        if f is None:
            break
        frames.append(f)
    frames.reverse()
    cur_thread = vspd.new_thread()
    for f in frames:
        cur_thread.push_frame(f)
    def replace_trace_func():
        for f in frames:
            f.f_trace = cur_thread.trace_func
    replace_trace_func()
    sys.settrace(cur_thread.trace_func)
    vspd.intercept_threads(for_attach = True)
Ejemplo n.º 13
0
def enable_attach(secret,
                  address=('0.0.0.0', DEFAULT_PORT),
                  certfile=None,
                  keyfile=None,
                  redirect_output=True):
    """Enables Visual Studio to attach to this process remotely to debug Python
    code.

    Parameters
    ----------
    secret : str
        Used to validate the clients - only those clients providing the valid
        secret will be allowed to connect to this server. On client side, the
        secret is prepended to the Qualifier string, separated from the
        hostname by ``'@'``, e.g.: ``'[email protected]:5678'``. If
        secret is ``None``, there's no validation, and any client can connect
        freely.
    address : (str, int), optional 
        Specifies the interface and port on which the debugging server should
        listen for TCP connections. It is in the same format as used for
        regular sockets of the `socket.AF_INET` family, i.e. a tuple of
        ``(hostname, port)``. On client side, the server is identified by the
        Qualifier string in the usual ``'hostname:port'`` format, e.g.:
        ``'myhost.cloudapp.net:5678'``. Default is ``('0.0.0.0', 5678)``.
    certfile : str, optional
        Used to enable SSL. If not specified, or if set to ``None``, the
        connection between this program and the debugger will be unsecure,
        and can be intercepted on the wire. If specified, the meaning of this
        parameter is the same as for `ssl.wrap_socket`. 
    keyfile : str, optional
        Used together with `certfile` when SSL is enabled. Its meaning is the
        same as for ``ssl.wrap_socket``.
    redirect_output : bool, optional
        Specifies whether any output (on both `stdout` and `stderr`) produced
        by this program should be sent to the debugger. Default is ``True``.

    Notes
    -----
    This function returns immediately after setting up the debugging server,
    and does not block program execution. If you need to block until debugger
    is attached, call `ptvsd.wait_for_attach`. The debugger can be detached
    and re-attached multiple times after `enable_attach` is called.

    This function can only be called once during the lifetime of the process. 
    On a second call, `AttachAlreadyEnabledError` is raised. In circumstances
    where the caller does not control how many times the function will be
    called (e.g. when a script with a single call is run more than once by
    a hosting app or framework), the call should be wrapped in ``try..except``.

    Only the thread on which this function is called, and any threads that are
    created after it returns, will be visible in the debugger once it is
    attached. Any threads that are already running before this function is
    called will not be visible.
    """

    if not ssl and (certfile or keyfile):
        raise ValueError(
            'could not import the ssl module - SSL is not supported on this version of Python'
        )

    if sys.platform == 'cli':
        # Check that IronPython was launched with -X:Frames and -X:Tracing, since we can't register our trace
        # func on the thread that calls enable_attach otherwise
        import clr
        x_tracing = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Tracing
        x_frames = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Frames
        if not x_tracing or not x_frames:
            raise RuntimeError(
                'IronPython must be started with -X:Tracing and -X:Frames options to support PTVS remote debugging.'
            )

    global _attach_enabled
    if _attach_enabled:
        raise AttachAlreadyEnabledError(
            'ptvsd.enable_attach() has already been called in this process.')
    _attach_enabled = True

    atexit.register(vspd.detach_process_and_notify_debugger)

    server = socket.socket(proto=socket.IPPROTO_TCP)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(address)
    server.listen(1)

    def server_thread_func():
        while True:
            client = None
            connection = None
            try:
                client, addr = server.accept()
                if certfile:
                    client = ssl.wrap_socket(client,
                                             server_side=True,
                                             ssl_version=ssl.PROTOCOL_TLSv1,
                                             certfile=certfile,
                                             keyfile=keyfile)

                connection = AttachLoop(client, secret, redirect_output, None)
                connection.send_event(
                    name='legacyRemoteConnected',
                    debuggerName=PTVSDBG,
                    debuggerProtocolVersion=PTVSDBG_VER,
                )
                connection.process_messages()
            except (socket.error, OSError):
                pass
            finally:
                if connection:
                    connection.close()

    server_thread = threading.Thread(target=server_thread_func)
    server_thread.setDaemon(True)
    server_thread.start()

    frames = []
    f = sys._getframe()
    while True:
        f = f.f_back
        if f is None:
            break
        frames.append(f)
    frames.reverse()
    cur_thread = vspd.new_thread()
    for f in frames:
        cur_thread.push_frame(f)

    def replace_trace_func():
        for f in frames:
            f.f_trace = cur_thread.trace_func

    replace_trace_func()
    sys.settrace(cur_thread.trace_func)
    vspd.intercept_threads(for_attach=True)
Ejemplo n.º 14
0
def enable_attach(secret,
                  address=('0.0.0.0', DEFAULT_PORT),
                  certfile=None,
                  keyfile=None,
                  redirect_output=True):
    """Enables Python Tools for Visual Studio to attach to this process remotely
    to debug Python code.

    The secret parameter is used to validate the clients - only those clients
    providing the valid secret will be allowed to connect to this server. On
    client side, the secret is prepended to the Qualifier string, separated from
    the hostname by '@', e.g.: [email protected]:5678. If secret is
    None, there's no validation, and any client can connect freely.

    The address parameter specifies the interface and port on which the
    debugging server should listen for TCP connections. It is in the same format
    as used for regular sockets of the AF_INET family, i.e. a tuple of
    (hostname, port). On client side, the server is identified by the Qualifier
    string in the usual hostname:port format, e.g.: myhost.cloudapp.net:5678.

    The certfile parameter is used to enable SSL. If not specified, or if set to
    None, the connection between this program and the debugger will be unsecure,
    and can be intercepted on the wire. If specified, the meaning of this
    parameter is the same as for ssl.wrap_socket. 

    The keyfile parameter is used together with certfile when SSL is enabled.
    Its meaning is the same as for ssl.wrap_socket.

    The redirect_output parameter specifies whether any output (on both stdout
    and stderr) produced by this program should be sent to the debugger. 

    This function returns immediately after setting up the debugging server,
    and does not block program execution. If you need to block until debugger
    is attached, call ptvsd.wait_for_attach. The debugger can be detached and
    re-attached multiple times after enable_attach is called.

    Only the thread on which this function is called, and any threads that are
    created after it returns, will be visible in the debugger once it is
    attached. Any threads that are already running before this function is
    called will not be visible.
    """

    if not ssl and (certfile or keyfile):
        raise ValueError(
            'could not import the ssl module - SSL is not supported on this version of Python'
        )

    if sys.platform == 'cli':
        # Check that IronPython was launched with -X:Frames and -X:Tracing, since we can't register our trace
        # func on the thread that calls enable_attach otherwise
        import clr
        x_tracing = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Tracing
        x_frames = clr.GetCurrentRuntime().GetLanguageByExtension(
            'py').Options.Frames
        if not x_tracing or not x_frames:
            raise RuntimeError(
                'IronPython must be started with -X:Tracing and -X:Frames options to support PTVS remote debugging.'
            )

    if redirect_output:
        vspd.enable_output_redirection()

    atexit.register(vspd.detach_process_and_notify_debugger)

    server = socket.socket()
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(address)
    server.listen(1)

    def server_thread_func():
        while True:
            client = None
            raw_client = None
            try:
                client, addr = server.accept()
                if certfile:
                    client = ssl.wrap_socket(client,
                                             server_side=True,
                                             ssl_version=ssl.PROTOCOL_TLSv1,
                                             certfile=certfile,
                                             keyfile=keyfile)
                write_bytes(client, PTVSDBG)
                write_int(client, PTVSDBG_VER)

                response = read_bytes(client, 7)
                if response != PTVSDBG:
                    continue
                dbg_ver = read_int(client)
                if dbg_ver != PTVSDBG_VER:
                    continue

                client_secret = read_string(client)
                if secret is None or secret == client_secret:
                    write_bytes(client, ACPT)
                else:
                    write_bytes(client, RJCT)
                    continue

                response = read_bytes(client, 4)

                if response == INFO:
                    try:
                        pid = os.getpid()
                    except AttributeError:
                        pid = 0
                    write_int(client, pid)

                    exe = sys.executable or ''
                    write_string(client, exe)

                    try:
                        username = getpass.getuser()
                    except AttributeError:
                        username = ''
                    write_string(client, username)

                    try:
                        impl = platform.python_implementation()
                    except AttributeError:
                        try:
                            impl = sys.implementation.name
                        except AttributeError:
                            impl = 'Python'

                    major, minor, micro, release_level, serial = sys.version_info

                    os_and_arch = platform.system()
                    if os_and_arch == "":
                        os_and_arch = sys.platform
                    try:
                        if sys.maxsize > 2**32:
                            os_and_arch += ' 64-bit'
                        else:
                            os_and_arch += ' 32-bit'
                    except AttributeError:
                        pass

                    version = '%s %s.%s.%s (%s)' % (impl, major, minor, micro,
                                                    os_and_arch)
                    write_string(client, version)

                elif response == ATCH:
                    if vspd.DETACHED:
                        write_bytes(client, ACPT)
                        try:
                            pid = os.getpid()
                        except AttributeError:
                            pid = 0
                        write_int(client, pid)

                        major, minor, micro, release_level, serial = sys.version_info
                        write_int(client, major)
                        write_int(client, minor)
                        write_int(client, micro)

                        vspd.attach_process_from_socket(client, report=True)
                        vspd.mark_all_threads_for_break(
                            vspd.STEPPING_ATTACH_BREAK)
                        _attached.set()
                        client = None
                    else:
                        write_bytes(client, RJCT)

                elif response == REPL:
                    if not vspd.DETACHED:
                        write_bytes(client, ACPT)
                        vspd.connect_repl_using_socket(client)
                        client = None
                    else:
                        write_bytes(client, RJCT)

            except (socket.error, OSError):
                pass
            finally:
                if client is not None:
                    client.close()

    server_thread = threading.Thread(target=server_thread_func)
    server_thread.daemon = True
    server_thread.start()

    frames = []
    f = sys._getframe()
    while True:
        f = f.f_back
        if f is None:
            break
        frames.append(f)
    frames.reverse()
    cur_thread = vspd.new_thread()
    for f in frames:
        cur_thread.push_frame(f)

    def replace_trace_func():
        for f in frames:
            f.f_trace = cur_thread.trace_func

    replace_trace_func()
    sys.settrace(cur_thread.trace_func)
    vspd.intercept_threads(for_attach=True)