-
Notifications
You must be signed in to change notification settings - Fork 675
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add PythonProfilderCommandService to support new profiler (#8150)
* set up the user input service * refactor the structure * remove tests * address feedback part 1 * update Args description * address feedback - part 2 rename file and method names * update comments
- Loading branch information
1 parent
396e364
commit dbac8cc
Showing
13 changed files
with
369 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
175 changes: 175 additions & 0 deletions
175
Python/Product/Profiling/Profiling/CommandArgumentBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
// Python Tools for Visual Studio | ||
// Copyright(c) Microsoft Corporation | ||
// All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the License); you may not use | ||
// this file except in compliance with the License. You may obtain a copy of the | ||
// License at http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY | ||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
// MERCHANTABILITY OR NON-INFRINGEMENT. | ||
// | ||
// See the Apache Version 2.0 License for specific language governing | ||
// permissions and limitations under the License. | ||
|
||
|
||
|
||
namespace Microsoft.PythonTools.Profiling { | ||
using System; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Windows; | ||
using Microsoft.PythonTools.Infrastructure; | ||
using Microsoft.PythonTools.Interpreter; | ||
|
||
internal class CommandArgumentBuilder { | ||
|
||
/// <summary> | ||
/// Constructs a <see cref="PythonProfilingCommandArgs"/> based on the provided profiling target. | ||
/// </summary> | ||
public PythonProfilingCommandArgs BuildCommandArgsFromTarget(ProfilingTarget target) { | ||
if (target == null) { | ||
return null; | ||
} | ||
|
||
try { | ||
var pythonProfilingPackage = PythonProfilingPackage.Instance; | ||
var joinableTaskFactory = pythonProfilingPackage.JoinableTaskFactory; | ||
|
||
PythonProfilingCommandArgs command = null; | ||
|
||
joinableTaskFactory.Run(async () => { | ||
await joinableTaskFactory.SwitchToMainThreadAsync(); | ||
|
||
var name = target.GetProfilingName(pythonProfilingPackage, out var save); | ||
var explorer = await pythonProfilingPackage.ShowPerformanceExplorerAsync(); | ||
var session = explorer.Sessions.AddTarget(target, name, save); | ||
|
||
command = SelectBuilder(target, session); | ||
|
||
}); | ||
|
||
return command; | ||
} catch (Exception ex) { | ||
Debug.Fail($"Error building command: {ex.Message}"); | ||
throw; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Select the appropriate builder based on the provided profiling target. | ||
/// </summary> | ||
private PythonProfilingCommandArgs SelectBuilder(ProfilingTarget target, SessionNode session) { | ||
var projectTarget = target.ProjectTarget; | ||
var standaloneTarget = target.StandaloneTarget; | ||
|
||
if (projectTarget != null) { | ||
return BuildProjectCommandArgs(projectTarget, session); | ||
} else if (standaloneTarget != null) { | ||
return BuildStandaloneCommandArgs(standaloneTarget, session); | ||
} | ||
return null; | ||
} | ||
|
||
private PythonProfilingCommandArgs BuildProjectCommandArgs(ProjectTarget projectTarget, SessionNode session) { | ||
var solution = PythonProfilingPackage.Instance.Solution; | ||
var project = solution.EnumerateLoadedPythonProjects() | ||
.SingleOrDefault(p => p.GetProjectIDGuidProperty() == projectTarget.TargetProject); | ||
|
||
if (project == null) { | ||
return null; | ||
} | ||
|
||
LaunchConfiguration config = null; | ||
try { | ||
config = project?.GetLaunchConfigurationOrThrow(); | ||
} catch (NoInterpretersException ex) { | ||
PythonToolsPackage.OpenNoInterpretersHelpPage(session._serviceProvider, ex.HelpPage); | ||
return null; | ||
} catch (MissingInterpreterException ex) { | ||
MessageBox.Show(ex.Message, Strings.ProductTitle); | ||
return null; | ||
} catch (IOException ex) { | ||
MessageBox.Show(ex.Message, Strings.ProductTitle); | ||
return null; | ||
} | ||
if (config == null) { | ||
MessageBox.Show(Strings.ProjectInterpreterNotFound.FormatUI(project.GetNameProperty()), Strings.ProductTitle); | ||
return null; | ||
} | ||
|
||
if (string.IsNullOrEmpty(config.ScriptName)) { | ||
MessageBox.Show(Strings.NoProjectStartupFile, Strings.ProductTitle); | ||
return null; | ||
} | ||
|
||
if (string.IsNullOrEmpty(config.WorkingDirectory) || config.WorkingDirectory == ".") { | ||
config.WorkingDirectory = project.ProjectHome; | ||
if (string.IsNullOrEmpty(config.WorkingDirectory)) { | ||
config.WorkingDirectory = Path.GetDirectoryName(config.ScriptName); | ||
} | ||
} | ||
|
||
var pythonExePath = config.GetInterpreterPath(); | ||
var scriptPath = string.Join(" ", ProcessOutput.QuoteSingleArgument(config.ScriptName), config.ScriptArguments); | ||
var workingDir = config.WorkingDirectory; | ||
var envVars = session._serviceProvider.GetPythonToolsService().GetFullEnvironment(config); | ||
|
||
var command = new PythonProfilingCommandArgs { | ||
PythonExePath = pythonExePath, | ||
ScriptPath = scriptPath, | ||
WorkingDir = workingDir, | ||
Args = Array.Empty<string>(), | ||
EnvVars = envVars | ||
}; | ||
return command; | ||
} | ||
|
||
private PythonProfilingCommandArgs BuildStandaloneCommandArgs(StandaloneTarget standaloneTarget, SessionNode session) { | ||
if (standaloneTarget == null) { | ||
return null; | ||
} | ||
|
||
LaunchConfiguration config = null; | ||
|
||
if (standaloneTarget.InterpreterPath != null) { | ||
config = new LaunchConfiguration(null); | ||
} | ||
|
||
if (standaloneTarget.PythonInterpreter != null) { | ||
var registry = session._serviceProvider.GetComponentModel().GetService<IInterpreterRegistryService>(); | ||
var interpreter = registry.FindConfiguration(standaloneTarget.PythonInterpreter.Id); | ||
if (interpreter == null) { | ||
return null; | ||
} | ||
|
||
config = new LaunchConfiguration(interpreter); | ||
} | ||
|
||
config.InterpreterPath = standaloneTarget.InterpreterPath; | ||
config.ScriptName = standaloneTarget.Script; | ||
config.ScriptArguments = standaloneTarget.Arguments; | ||
config.WorkingDirectory = standaloneTarget.WorkingDirectory; | ||
|
||
var argsInput = standaloneTarget.Arguments; | ||
var parsedArgs = string.IsNullOrWhiteSpace(argsInput) | ||
? Array.Empty<string>() | ||
: argsInput.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); | ||
|
||
var envVars = session._serviceProvider.GetPythonToolsService().GetFullEnvironment(config); | ||
|
||
return new PythonProfilingCommandArgs { | ||
PythonExePath = config.GetInterpreterPath(), | ||
WorkingDir = standaloneTarget.WorkingDirectory, | ||
ScriptPath = standaloneTarget.Script, | ||
Args = parsedArgs, | ||
EnvVars = envVars | ||
}; | ||
} | ||
} | ||
} | ||
|
||
|
28 changes: 28 additions & 0 deletions
28
Python/Product/Profiling/Profiling/IPythonProfilerCommandService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Python Tools for Visual Studio | ||
// Copyright(c) Microsoft Corporation | ||
// All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the License); you may not use | ||
// this file except in compliance with the License. You may obtain a copy of the | ||
// License at http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY | ||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
// MERCHANTABILITY OR NON-INFRINGEMENT. | ||
// | ||
// See the Apache Version 2.0 License for specific language governing | ||
// permissions and limitations under the License. | ||
|
||
namespace Microsoft.PythonTools.Profiling { | ||
|
||
/// <summary> | ||
/// Defines a service interface for collecting user input and converting to Python profiling command arguments. | ||
/// </summary> | ||
public interface IPythonProfilerCommandService { | ||
/// <summary> | ||
/// Collects user input via a dialog and converts it into a <see cref="IPythonProfilingCommandArgs"/>. | ||
/// </summary> | ||
IPythonProfilingCommandArgs GetCommandArgsFromUserInput(); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
Python/Product/Profiling/Profiling/IPythonProfilingCommandArgs.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Python Tools for Visual Studio | ||
// Copyright(c) Microsoft Corporation | ||
// All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the License); you may not use | ||
// this file except in compliance with the License. You may obtain a copy of the | ||
// License at http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY | ||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
// MERCHANTABILITY OR NON-INFRINGEMENT. | ||
// | ||
// See the Apache Version 2.0 License for specific language governing | ||
// permissions and limitations under the License. | ||
|
||
using System.Collections.Generic; | ||
|
||
namespace Microsoft.PythonTools.Profiling | ||
{ | ||
/// <summary> | ||
/// Contains the arguments for a Python profiling command. | ||
/// </summary> | ||
public interface IPythonProfilingCommandArgs { | ||
string PythonExePath { get; set; } | ||
string WorkingDir { get; set; } | ||
string ScriptPath { get; set; } | ||
string[] Args { get; set; } | ||
Dictionary<string, string> EnvVars { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
Python/Product/Profiling/Profiling/PythonProfilerCommandService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Python Tools for Visual Studio | ||
// Copyright(c) Microsoft Corporation | ||
// All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the License); you may not use | ||
// this file except in compliance with the License. You may obtain a copy of the | ||
// License at http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY | ||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
// MERCHANTABILITY OR NON-INFRINGEMENT. | ||
// | ||
// See the Apache Version 2.0 License for specific language governing | ||
// permissions and limitations under the License. | ||
|
||
namespace Microsoft.PythonTools.Profiling { | ||
using System; | ||
using System.ComponentModel.Composition; | ||
using System.Diagnostics; | ||
using System.Windows; | ||
|
||
/// <summary> | ||
/// Implements a service to collect user input for profiling and convert to a <see cref="PythonProfilingCommandArgs"/>. | ||
/// </summary> | ||
[Export(typeof(IPythonProfilerCommandService))] | ||
class PythonProfilerCommandService : IPythonProfilerCommandService { | ||
private readonly CommandArgumentBuilder _commandArgumentBuilder; | ||
private readonly UserInputDialog _userInputDialog; | ||
|
||
public PythonProfilerCommandService() { | ||
_commandArgumentBuilder = new CommandArgumentBuilder(); | ||
_userInputDialog = new UserInputDialog(); | ||
} | ||
|
||
/// <summary> | ||
/// Collects user input and constructs a <see cref="PythonProfilingCommandArgs"/> object. | ||
/// </summary> | ||
/// <returns> | ||
/// A <see cref="PythonProfilingCommandArgs"/> object based on user input, or <c>null</c> if canceled. | ||
/// </returns> | ||
public IPythonProfilingCommandArgs GetCommandArgsFromUserInput() { | ||
try { | ||
var pythonProfilingPackage = PythonProfilingPackage.Instance; | ||
var targetView = new ProfilingTargetView(pythonProfilingPackage); | ||
|
||
if (_userInputDialog.ShowDialog(targetView)) { | ||
var target = targetView.GetTarget(); | ||
return _commandArgumentBuilder.BuildCommandArgsFromTarget(target); | ||
} | ||
} catch (Exception ex) { | ||
Debug.Fail($"Error displaying user input dialog: {ex.Message}"); | ||
MessageBox.Show($"An unexpected error occurred: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
Python/Product/Profiling/Profiling/PythonProfilingCommandArgs.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Python Tools for Visual Studio | ||
// Copyright(c) Microsoft Corporation | ||
// All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the License); you may not use | ||
// this file except in compliance with the License. You may obtain a copy of the | ||
// License at http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY | ||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
// MERCHANTABILITY OR NON-INFRINGEMENT. | ||
// | ||
// See the Apache Version 2.0 License for specific language governing | ||
// permissions and limitations under the License. | ||
|
||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
|
||
namespace Microsoft.PythonTools.Profiling { | ||
/// <summary> | ||
/// Represents the arguments for a Python profiling command. | ||
/// </summary> | ||
[Export(typeof(IPythonProfilingCommandArgs))] | ||
public class PythonProfilingCommandArgs : IPythonProfilingCommandArgs { | ||
public string PythonExePath { get; set; } | ||
public string WorkingDir { get; set; } | ||
public string ScriptPath { get; set; } | ||
public string[] Args { get; set; } | ||
public Dictionary<string, string> EnvVars { get; set; } | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.