Exemplo n.º 1
0
        private static string GetLaunchJsonForVsCodeDebugAdapter(IServiceProvider provider, LaunchConfiguration config)
        {
            JArray envArray = new JArray();

            foreach (var kv in provider.GetPythonToolsService().GetFullEnvironment(config))
            {
                JObject pair = new JObject {
                    ["name"]  = kv.Key,
                    ["value"] = kv.Value
                };
                envArray.Add(pair);
            }

            JObject jsonObj = new JObject {
                ["exe"]           = config.GetInterpreterPath(),
                ["cwd"]           = string.IsNullOrEmpty(config.WorkingDirectory) ? PathUtils.GetParent(config.ScriptName) : config.WorkingDirectory,
                ["remoteMachine"] = "",
                ["args"]          = GetArgs(config),
                ["options"]       = GetOptions(provider, config),
                ["env"]           = envArray
            };

            // Note: these are optional, but special. These override the pkgdef version of the adapter settings
            // for other settings see the documentation for VSCodeDebugAdapterHost Launch Configuration
            // jsonObj["$adapter"] = "{path - to - adapter executable}";
            // jsonObj["$adapterArgs"] = "";
            // jsonObj["$adapterRuntime"] = "";

            return(jsonObj.ToString());
        }
Exemplo n.º 2
0
        private static void RunVTune(SessionNode session, LaunchConfiguration config, bool openReport)
        {
            var interpreter = config.GetInterpreterPath();

            if (!File.Exists(interpreter))
            {
                MessageBox.Show(Strings.CannotFindPythonInterpreter, Strings.ProductTitle);
                return;
            }

            string outPathDir = Path.GetTempPath();
            var    subpath    = Path.Combine(outPathDir, Path.GetRandomFileName());

            while (Directory.Exists(subpath) || File.Exists(subpath))
            {
                subpath = Path.Combine(outPathDir, Path.GetRandomFileName());
            }
            outPathDir = subpath;

            string outPath = Path.Combine(outPathDir, "pythontrace.diagsession");

            var driver = PythonToolsInstallPath.GetFile(ExternalProfilerDriverExe, typeof(PythonProfilingPackage).Assembly);

            var procInfo = new ProcessStartInfo(driver)
            {
                CreateNoWindow = false,
                Arguments      = string.Join(" ", new[] {
                    "-d",
                    ProcessOutput.QuoteSingleArgument(outPathDir),
                    "--",
                    ProcessOutput.QuoteSingleArgument(interpreter),
                    config.InterpreterArguments,
                    string.IsNullOrEmpty(config.ScriptName) ? "" : ProcessOutput.QuoteSingleArgument(config.ScriptName),
                    config.ScriptArguments
                }),
                WorkingDirectory = config.WorkingDirectory,
            };

            var proc = new Process {
                StartInfo = procInfo
            };
            var dte = (EnvDTE.DTE)session._serviceProvider.GetService(typeof(EnvDTE.DTE));

            proc.EnableRaisingEvents = true;
            proc.Exited += (_, args) => {
                if (!File.Exists(Path.Combine(outPathDir, "Sample.dwjson")))
                {
                    MessageBox.Show(Strings.CannotFindGeneratedFile, Strings.ProductTitle);
                }
                else
                {
                    PackageTrace(outPathDir);
                    dte.ItemOperations.OpenFile(Path.Combine(outPathDir, "trace.diagsession"));
                }
            };
            proc.Start();
        }
Exemplo n.º 3
0
        private static string GetLaunchJsonForVsCodeDebugAdapter(IServiceProvider provider, LaunchConfiguration config, Dictionary <string, string> fullEnvironment)
        {
            JArray envArray = new JArray();

            foreach (var kv in fullEnvironment)
            {
                JObject pair = new JObject {
                    ["name"]  = kv.Key,
                    ["value"] = kv.Value
                };
                envArray.Add(pair);
            }

            // get the variable presentation options from Tools -> Options -> Python -> Debugging
            var     pyService = provider.GetPythonToolsService();
            JObject variablePresentationObj = new JObject {
                ["class"]     = pyService.DebuggerOptions.VariablePresentationForClasses.ToString().ToLower(),
                ["function"]  = pyService.DebuggerOptions.VariablePresentationForFunctions.ToString().ToLower(),
                ["protected"] = pyService.DebuggerOptions.VariablePresentationForProtected.ToString().ToLower(),
                ["special"]   = pyService.DebuggerOptions.VariablePresentationForSpecial.ToString().ToLower(),
            };

            JObject jsonObj = new JObject {
                ["exe"]                  = config.GetInterpreterPath(),
                ["cwd"]                  = string.IsNullOrEmpty(config.WorkingDirectory) ? PathUtils.GetParent(config.ScriptName) : config.WorkingDirectory,
                ["remoteMachine"]        = "",
                ["args"]                 = GetArgs(config),
                ["options"]              = GetOptions(provider, config),
                ["env"]                  = envArray,
                ["interpreterArgs"]      = config.InterpreterArguments,
                ["variablePresentation"] = variablePresentationObj,
            };

            if (config.Environment == null)
            {
                jsonObj["scriptName"] = config.ScriptName?.Trim();
                jsonObj["scriptArgs"] = config.ScriptArguments?.Trim();
            }
            else
            {
                jsonObj["scriptName"] = DoSubstitutions(config.Environment, config.ScriptName?.Trim());
                jsonObj["scriptArgs"] = DoSubstitutions(config.Environment, config.ScriptArguments?.Trim());
            }

            // Note: these are optional, but special. These override the pkgdef version of the adapter settings
            // for other settings see the documentation for VSCodeDebugAdapterHost Launch Configuration
            // jsonObj["$adapter"] = "{path - to - adapter executable}";
            // jsonObj["$adapterArgs"] = "";
            // jsonObj["$adapterRuntime"] = "";

            return(jsonObj.ToString());
        }
Exemplo n.º 4
0
        private static void RunProfiler(SessionNode session, LaunchConfiguration config, bool openReport)
        {
            var process = new ProfiledProcess(
                (PythonToolsService)session._serviceProvider.GetService(typeof(PythonToolsService)),
                config.GetInterpreterPath(),
                string.Join(" ", ProcessOutput.QuoteSingleArgument(config.ScriptName), config.ScriptArguments),
                config.WorkingDirectory,
                session._serviceProvider.GetPythonToolsService().GetFullEnvironment(config)
                );

            string baseName = Path.GetFileNameWithoutExtension(session.Filename);
            string date     = DateTime.Now.ToString("yyyyMMdd");
            string outPath  = Path.Combine(Path.GetTempPath(), baseName + "_" + date + ".vsp");

            int count = 1;

            while (File.Exists(outPath))
            {
                outPath = Path.Combine(Path.GetTempPath(), baseName + "_" + date + "(" + count + ").vsp");
                count++;
            }

            process.ProcessExited += (sender, args) => {
                var dte = (EnvDTE.DTE)session._serviceProvider.GetService(typeof(EnvDTE.DTE));
                _profilingProcess     = null;
                _stopCommand.Enabled  = false;
                _startCommand.Enabled = true;
                if (openReport && File.Exists(outPath))
                {
                    for (int retries = 10; retries > 0; --retries)
                    {
                        try {
                            using (new FileStream(outPath, FileMode.Open, FileAccess.Read, FileShare.None)) { }
                            break;
                        } catch (IOException) {
                            Thread.Sleep(100);
                        }
                    }
                    dte.ItemOperations.OpenFile(outPath);
                }
            };

            session.AddProfile(outPath);

            process.StartProfiling(outPath);
            _profilingProcess     = process;
            _stopCommand.Enabled  = true;
            _startCommand.Enabled = false;
        }
Exemplo n.º 5
0
        public static ProcessStartInfo CreateProcessStartInfo(IServiceProvider provider, LaunchConfiguration config)
        {
            var psi = new ProcessStartInfo {
                FileName  = config.GetInterpreterPath(),
                Arguments = string.Join(" ", new[] {
                    config.InterpreterArguments,
                    config.ScriptName == null ? "" : ProcessOutput.QuoteSingleArgument(config.ScriptName),
                    config.ScriptArguments
                }.Where(s => !string.IsNullOrEmpty(s))),
                WorkingDirectory = config.WorkingDirectory,
                UseShellExecute  = false
            };

            if (string.IsNullOrEmpty(psi.FileName))
            {
                throw new FileNotFoundException(Strings.DebugLaunchInterpreterMissing);
            }
            if (!File.Exists(psi.FileName))
            {
                throw new FileNotFoundException(Strings.DebugLaunchInterpreterMissing_Path.FormatUI(psi.FileName));
            }
            if (string.IsNullOrEmpty(psi.WorkingDirectory))
            {
                psi.WorkingDirectory = PathUtils.GetParent(config.ScriptName);
            }
            if (string.IsNullOrEmpty(psi.WorkingDirectory))
            {
                throw new DirectoryNotFoundException(Strings.DebugLaunchWorkingDirectoryMissing);
            }
            if (!Directory.Exists(psi.WorkingDirectory))
            {
                throw new DirectoryNotFoundException(Strings.DebugLaunchWorkingDirectoryMissing_Path.FormatUI(psi.WorkingDirectory));
            }

            foreach (var kv in provider.GetPythonToolsService().GetFullEnvironment(config))
            {
                psi.Environment[kv.Key] = kv.Value;
            }

            var pyService = provider.GetPythonToolsService();
            // Pause if the user has requested it.
            string pauseCommand = null;

            if (config.GetLaunchOption(PythonConstants.NeverPauseOnExit).IsTrue())
            {
                // Do nothing
            }
            else if (pyService.DebuggerOptions.WaitOnAbnormalExit && pyService.DebuggerOptions.WaitOnNormalExit)
            {
                pauseCommand = "pause";
            }
            else if (pyService.DebuggerOptions.WaitOnAbnormalExit && !pyService.DebuggerOptions.WaitOnNormalExit)
            {
                pauseCommand = "if errorlevel 1 pause";
            }
            else if (pyService.DebuggerOptions.WaitOnNormalExit && !pyService.DebuggerOptions.WaitOnAbnormalExit)
            {
                pauseCommand = "if not errorlevel 1 pause";
            }

            if (!string.IsNullOrEmpty(pauseCommand))
            {
                psi.Arguments = string.Format("/c \"{0} {1}\" & {2}",
                                              ProcessOutput.QuoteSingleArgument(psi.FileName),
                                              psi.Arguments,
                                              pauseCommand
                                              );
                psi.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
            }

            return(psi);
        }
Exemplo n.º 6
0
        public static unsafe DebugTargetInfo CreateDebugTargetInfo(IServiceProvider provider, LaunchConfiguration config)
        {
            if (config.Interpreter.Version < new Version(2, 6) && config.Interpreter.Version > new Version(0, 0))
            {
                // We don't support Python 2.5 now that our debugger needs the json module
                throw new NotSupportedException(Strings.DebuggerPythonVersionNotSupported);
            }

            var dti = new DebugTargetInfo(provider);

            try {
                dti.Info.dlo        = DEBUG_LAUNCH_OPERATION.DLO_CreateProcess;
                dti.Info.bstrExe    = config.GetInterpreterPath();
                dti.Info.bstrCurDir = string.IsNullOrEmpty(config.WorkingDirectory) ? PathUtils.GetParent(config.ScriptName) : config.WorkingDirectory;

                dti.Info.bstrRemoteMachine         = null;
                dti.Info.fSendStdoutToOutputWindow = 0;

                bool nativeDebug = config.GetLaunchOption(PythonConstants.EnableNativeCodeDebugging).IsTrue();
                if (!nativeDebug)
                {
                    dti.Info.bstrOptions = GetOptions(provider, config);
                }

                // Environment variables should be passed as a
                // null-terminated block of null-terminated strings.
                // Each string is in the following form:name=value\0
                var buf             = new StringBuilder();
                var fullEnvironment = provider.GetPythonToolsService().GetFullEnvironment(config);
                foreach (var kv in fullEnvironment)
                {
                    buf.AppendFormat("{0}={1}\0", kv.Key, kv.Value);
                }
                if (buf.Length > 0)
                {
                    buf.Append("\0");
                    dti.Info.bstrEnv = buf.ToString();
                }

                dti.Info.bstrArg = GetArgs(config);

                if (nativeDebug)
                {
                    dti.Info.dwClsidCount = 2;
                    dti.Info.pClsidList   = Marshal.AllocCoTaskMem(sizeof(Guid) * 2);
                    var engineGuids = (Guid *)dti.Info.pClsidList;
                    engineGuids[0] = dti.Info.clsidCustom = DkmEngineId.NativeEng;
                    engineGuids[1] = AD7Engine.DebugEngineGuid;
                }
                else
                {
                    var pyService = provider.GetPythonToolsService();
                    // Set the Python debugger
                    dti.Info.clsidCustom = pyService.DebuggerOptions.UseLegacyDebugger ? AD7Engine.DebugEngineGuid : DebugAdapterLauncher.VSCodeDebugEngine;
                    dti.Info.grfLaunch   = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd;

                    if (!pyService.DebuggerOptions.UseLegacyDebugger)
                    {
                        dti.Info.bstrOptions = GetLaunchJsonForVsCodeDebugAdapter(provider, config, fullEnvironment);
                    }
                }

                // Null out dti so that it is not disposed before we return.
                var result = dti;
                dti = null;
                return(result);
            } finally {
                if (dti != null)
                {
                    dti.Dispose();
                }
            }
        }
Exemplo n.º 7
0
        public IXPathNavigable AddRunSettings(IXPathNavigable inputRunSettingDocument, IRunSettingsConfigurationInfo configurationInfo, ILogger log)
        {
            XPathNavigator navigator = inputRunSettingDocument.CreateNavigator();
            var            python    = navigator.Select("/RunSettings");

            if (python.MoveNext())
            {
                using (var writer = python.Current.AppendChild()) {
                    var pyContainers = configurationInfo.TestContainers
                                       .OfType <TestContainer>()
                                       .GroupBy(x => x.Project);

                    writer.WriteStartElement("Python");
                    writer.WriteStartElement("TestCases");

                    foreach (var project in pyContainers)
                    {
                        foreach (var container in project)
                        {
                            writer.WriteStartElement("Project");
                            writer.WriteAttributeString("home", project.Key.ProjectHome);

                            LaunchConfiguration config = null;
                            string nativeCode = "", djangoSettings = "";

                            ThreadHelper.JoinableTaskFactory.Run(async() => {
                                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                                try {
                                    config = project.Key.GetLaunchConfigurationOrThrow();
                                } catch {
                                }
                                nativeCode     = project.Key.GetProperty(PythonConstants.EnableNativeCodeDebugging);
                                djangoSettings = project.Key.GetProperty("DjangoSettingsModule");
                            });

                            if (config == null)
                            {
                                log.Log(
                                    MessageLevel.Warning,
                                    Strings.TestDiscoveryFailedMissingLaunchConfiguration.FormatUI(project.Key.ProjectHome)
                                    );
                                continue;
                            }
                            writer.WriteAttributeString("nativeDebugging", nativeCode);
                            writer.WriteAttributeString("djangoSettingsModule", djangoSettings);

                            writer.WriteAttributeString("workingDir", config.WorkingDirectory);
                            writer.WriteAttributeString("interpreter", config.GetInterpreterPath());
                            writer.WriteAttributeString("pathEnv", config.Interpreter.PathEnvironmentVariable);

                            writer.WriteStartElement("Environment");
                            foreach (var keyValue in config.Environment)
                            {
                                writer.WriteStartElement("Variable");
                                writer.WriteAttributeString("name", keyValue.Key);
                                writer.WriteAttributeString("value", keyValue.Value);
                                writer.WriteEndElement();
                            }
                            writer.WriteEndElement(); // Environment

                            writer.WriteStartElement("SearchPaths");
                            foreach (var path in config.SearchPaths)
                            {
                                writer.WriteStartElement("Search");
                                writer.WriteAttributeString("value", path);
                                writer.WriteEndElement();
                            }
                            writer.WriteEndElement(); // SearchPaths

                            foreach (var test in container.TestCases)
                            {
                                writer.WriteStartElement("Test");
                                writer.WriteAttributeString("className", test.ClassName);
                                writer.WriteAttributeString("file", test.Filename);
                                writer.WriteAttributeString("line", test.StartLine.ToString());
                                writer.WriteAttributeString("column", test.StartColumn.ToString());
                                writer.WriteAttributeString("method", test.MethodName);
                                writer.WriteEndElement(); // Test
                            }

                            writer.WriteEndElement();  // Project
                        }
                    }

                    writer.WriteEndElement(); // TestCases
                    writer.WriteEndElement(); // Python
                }
            }

            // We only care about tweaking the settings for execution...
            if (configurationInfo.RequestState != RunSettingConfigurationInfoState.Execution)
            {
                return(inputRunSettingDocument);
            }

            // And we also only care about doing it when we're all Python containers
#pragma warning disable CS0219 // Variable is assigned but its value is never used
            bool allPython = true, anyPython = false;
#pragma warning restore CS0219 // Variable is assigned but its value is never used
            foreach (var container in configurationInfo.TestContainers)
            {
                if (container is TestContainer)
                {
                    anyPython = true;
                }
                else
                {
                    allPython = false;
                }
            }

            if (!anyPython)
            {
                // Don't mess with code coverage settings if we're not running Python tests
                return(inputRunSettingDocument);
            }

            if (CodeCoverageEnabled)
            {
                // Code coverage is currently enabled.  We don't want it adding it's data
                // collector if ICodeCoverageSettingsService IRunSettingsService runs
                // after ours.  So we tell it that it's been disabled to prevent that
                // from happening.
                navigator = inputRunSettingDocument.CreateNavigator();

                var pythonNode = navigator.Select("/RunSettings/Python");
                if (pythonNode.MoveNext())
                {
                    pythonNode.Current.AppendChild("<EnableCoverage>true</EnableCoverage>");
                }

                if (allPython)
                {
                    // Disable normal code coverage...
                    CodeCoverageEnabled = false;

                    XPathNodeIterator nodes            = navigator.Select("/RunSettings/DataCollectionRunSettings/DataCollectors/DataCollector");
                    XPathNavigator    codeCoverageNode = null;
                    foreach (XPathNavigator dataCollectorNavigator in nodes)
                    {
                        string uri = dataCollectorNavigator.GetAttribute("uri", string.Empty);
                        if (string.Equals(CodeCoverageUriString, uri, StringComparison.OrdinalIgnoreCase))
                        {
                            codeCoverageNode = dataCollectorNavigator;
                            break;
                        }
                    }

                    if (codeCoverageNode != null &&
                        String.IsNullOrWhiteSpace(codeCoverageNode.GetAttribute("x-keep-ptvs", null)))
                    {
                        // Code coverage has been added, which means we (likely) came after
                        // ICodeCoverageSettingsService in the MEF import order.  Let's remove
                        // the node (we allow the user to define x-keep-ptvs to prevent us
                        // from doing this if they've manually patched their runsettings file)
                        codeCoverageNode.DeleteSelf();
                    }
                }
            }

            return(inputRunSettingDocument);
        }
Exemplo n.º 8
0
        bool WriteProjectInfoForContainer(System.Xml.XmlWriter writer, TestContainer container, ILogger log)
        {
            if (container == null)
            {
                return(false);
            }

            string                      nativeCode = "", djangoSettings = "", projectName = "", testFramework = "", unitTestPattern = "", unitTestRootDir = "";
            bool                        isWorkspace     = false;
            ProjectInfo                 projInfo        = null;
            LaunchConfiguration         config          = null;
            Dictionary <string, string> fullEnvironment = null;

            ThreadHelper.JoinableTaskFactory.Run(async() => {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                if (container.Discoverer is TestContainerDiscovererProject)
                {
                    var discoverer = container.Discoverer as TestContainerDiscovererProject;
                    isWorkspace    = discoverer.IsWorkspace;
                    projInfo       = discoverer.GetProjectInfo(container.Project);
                }
                else if (container.Discoverer is TestContainerDiscovererWorkspace)
                {
                    var discoverer = container.Discoverer as TestContainerDiscovererWorkspace;
                    isWorkspace    = discoverer.IsWorkspace;
                    projInfo       = discoverer.GetProjectInfo(container.Project);
                }

                if (projInfo != null)
                {
                    try {
                        config          = projInfo.GetLaunchConfigurationOrThrow();
                        fullEnvironment = LaunchConfigurationUtils.GetFullEnvironment(config, _serviceProvider);
                    } catch {
                    }
                    nativeCode      = projInfo.GetProperty(PythonConstants.EnableNativeCodeDebugging);
                    djangoSettings  = projInfo.GetProperty("DjangoSettingsModule");
                    testFramework   = projInfo.GetProperty(PythonConstants.TestFrameworkSetting);
                    projectName     = projInfo.ProjectName;
                    unitTestRootDir = projInfo.GetProperty(PythonConstants.UnitTestRootDirectorySetting);
                    unitTestPattern = projInfo.GetProperty(PythonConstants.UnitTestPatternSetting);
                }
            });

            if (config == null || projInfo == null)
            {
                log.Log(
                    MessageLevel.Warning,
                    Strings.TestDiscoveryFailedMissingLaunchConfiguration.FormatUI(container.Project)
                    );
                return(false);
            }
            writer.WriteStartElement("Project");
            writer.WriteAttributeString("home", container.Project);
            writer.WriteAttributeString("name", projectName);
            writer.WriteAttributeString("isWorkspace", isWorkspace.ToString());
            writer.WriteAttributeString("useLegacyDebugger", UseLegacyDebugger ? "1" : "0");
            writer.WriteAttributeString("nativeDebugging", nativeCode);
            writer.WriteAttributeString("djangoSettingsModule", djangoSettings);
            writer.WriteAttributeString("testFramework", testFramework);
            writer.WriteAttributeString("workingDir", config.WorkingDirectory);
            writer.WriteAttributeString("interpreter", config.GetInterpreterPath());
            writer.WriteAttributeString("pathEnv", config.Interpreter.PathEnvironmentVariable);
            writer.WriteAttributeString("unitTestRootDir", unitTestRootDir);
            writer.WriteAttributeString("unitTestPattern", unitTestPattern);

            writer.WriteStartElement("Environment");

            Dictionary <string, string> env = fullEnvironment ?? config.Environment;

            foreach (var keyValue in env)
            {
                writer.WriteStartElement("Variable");
                writer.WriteAttributeString("name", keyValue.Key);
                writer.WriteAttributeString("value", keyValue.Value);
                writer.WriteEndElement();
            }
            writer.WriteEndElement(); // Environment

            writer.WriteStartElement("SearchPaths");
            foreach (var path in config.SearchPaths)
            {
                writer.WriteStartElement("Search");
                writer.WriteAttributeString("value", path);
                writer.WriteEndElement();
            }
            writer.WriteEndElement(); // SearchPaths

            return(true);
        }
Exemplo n.º 9
0
        public static unsafe DebugTargetInfo CreateDebugTargetInfo(IServiceProvider provider, LaunchConfiguration config)
        {
            var pyService = provider.GetPythonToolsService();
            var dti       = new DebugTargetInfo(provider);

            try {
                dti.Info.dlo        = DEBUG_LAUNCH_OPERATION.DLO_CreateProcess;
                dti.Info.bstrExe    = config.GetInterpreterPath();
                dti.Info.bstrCurDir = config.WorkingDirectory;
                if (string.IsNullOrEmpty(dti.Info.bstrCurDir))
                {
                    dti.Info.bstrCurDir = PathUtils.GetParent(config.ScriptName);
                }

                dti.Info.bstrRemoteMachine         = null;
                dti.Info.fSendStdoutToOutputWindow = 0;

                bool nativeDebug = config.GetLaunchOption(PythonConstants.EnableNativeCodeDebugging).IsTrue();
                if (!nativeDebug)
                {
                    dti.Info.bstrOptions = string.Join(";",
                                                       GetGlobalDebuggerOptions(pyService)
                                                       .Concat(GetLaunchConfigurationOptions(config))
                                                       .Where(s => !string.IsNullOrEmpty(s))
                                                       .Select(s => s.Replace(";", ";;"))
                                                       );
                }

                // Environment variables should be passed as a
                // null-terminated block of null-terminated strings.
                // Each string is in the following form:name=value\0
                var buf = new StringBuilder();
                foreach (var kv in provider.GetPythonToolsService().GetFullEnvironment(config))
                {
                    buf.AppendFormat("{0}={1}\0", kv.Key, kv.Value);
                }
                if (buf.Length > 0)
                {
                    buf.Append("\0");
                    dti.Info.bstrEnv = buf.ToString();
                }

                var args = string.Join(" ", new[] {
                    config.InterpreterArguments,
                    config.ScriptName == null ? "" : ProcessOutput.QuoteSingleArgument(config.ScriptName),
                    config.ScriptArguments
                }.Where(s => !string.IsNullOrEmpty(s)));

                if (config.Environment != null)
                {
                    args = DoSubstitutions(config.Environment, args);
                }
                dti.Info.bstrArg = args;

                if (nativeDebug)
                {
                    dti.Info.dwClsidCount = 2;
                    dti.Info.pClsidList   = Marshal.AllocCoTaskMem(sizeof(Guid) * 2);
                    var engineGuids = (Guid *)dti.Info.pClsidList;
                    engineGuids[0] = dti.Info.clsidCustom = DkmEngineId.NativeEng;
                    engineGuids[1] = AD7Engine.DebugEngineGuid;
                }
                else
                {
                    // Set the Python debugger
                    dti.Info.clsidCustom = new Guid(AD7Engine.DebugEngineId);
                    dti.Info.grfLaunch   = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd;
                }

                // Null out dti so that it is not disposed before we return.
                var result = dti;
                dti = null;
                return(result);
            } finally {
                if (dti != null)
                {
                    dti.Dispose();
                }
            }
        }