Skip to content

Commit a5b78ed

Browse files
committed
Merge pull request #1323 from zooba/issue-1251
Fixes #1251 No completions in virtual env REPL
2 parents 546ffac + 2c69ea7 commit a5b78ed

13 files changed

+116
-32
lines changed

Python/Product/Analysis/Interpreter/IInterpreterRegistryService.cs

+11
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ public interface IInterpreterRegistryService {
4545

4646
InterpreterConfiguration FindConfiguration(string id);
4747

48+
/// <summary>
49+
/// Gets a property value relating to a specific interpreter.
50+
///
51+
/// If the property is not set, returns <c>null</c>.
52+
/// </summary>
53+
/// <param name="id">The interpreter identifier.</param>
54+
/// <param name="propName">A case-sensitive string identifying the
55+
/// property. Values will be compared by ordinal.</param>
56+
/// <returns>The property value, or <c>null</c> if not set.</returns>
57+
object GetProperty(string id, string propName);
58+
4859
/// <summary>
4960
/// Raised when the set of interpreters changes. This is not raised when
5061
/// the set is first initialized.

Python/Product/Analysis/Interpreter/IPythonInterpreterFactoryProvider.cs

+11
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ public interface IPythonInterpreterFactoryProvider {
4646
/// Gets a specific configured interpreter
4747
/// </summary>
4848
IPythonInterpreterFactory GetInterpreterFactory(string id);
49+
50+
/// <summary>
51+
/// Gets a property value associated with the specified interpreter. If
52+
/// the property is not set or available, return <c>null</c>.
53+
///
54+
/// Property values should not change over the process lifetime.
55+
/// </summary>
56+
/// <param name="id">The interpreter id.</param>
57+
/// <param name="propName">A case-sensitive string identifying the name
58+
/// of the property. Values will be compared by ordinal.</param>
59+
object GetProperty(string id, string propName);
4960
}
5061

5162
public static class PythonInterpreterExtensions {

Python/Product/Analysis/Interpreter/InterpreterRegistryService.cs

+5
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,11 @@ public InterpreterConfiguration FindConfiguration(string id) {
361361
return null;
362362
}
363363

364+
public object GetProperty(string id, string propName) {
365+
var factoryProvider = GetFactoryProvider(id);
366+
return factoryProvider?.GetProperty(id, propName);
367+
}
368+
364369
private IPythonInterpreterFactoryProvider GetFactoryProvider(string id) {
365370
var interpAndId = id.Split(new[] { '|' }, 2);
366371
if (interpAndId.Length == 2) {

Python/Product/CanopyInterpreter/CanopyInterpreterFactoryProvider.cs

+2
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ public IPythonInterpreterFactory GetInterpreterFactory(string id) {
230230
.FirstOrDefault();
231231
}
232232

233+
public object GetProperty(string id, string propName) => null;
234+
233235
public event EventHandler InterpreterFactoriesChanged;
234236

235237
private void OnInterpreterFactoriesChanged() {

Python/Product/IronPython/Interpreter/IronPythonInterpreterFactoryProvider.cs

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ private void DiscoverInterpreterFactories() {
171171

172172
public event EventHandler InterpreterFactoriesChanged;
173173

174+
public object GetProperty(string id, string propName) => null;
174175

175176
#endregion
176177

Python/Product/PythonTools/PythonTools/Extensions.cs

+17-3
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,15 @@ internal static bool TryGetAnalysisEntry(this ITextView view, ITextBuffer buffer
290290

291291
string path = buffer.GetFilePath();
292292
if (path != null) {
293-
var docTable = provider.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable4;
294-
var cookie = docTable.GetDocumentCookie(path);
293+
var docTable = (IVsRunningDocumentTable4)provider.GetService(typeof(SVsRunningDocumentTable));
294+
var cookie = VSConstants.VSCOOKIE_NIL;
295+
try {
296+
cookie = docTable.GetDocumentCookie(path);
297+
} catch (ArgumentException) {
298+
// Exception may be raised while VS is shutting down
299+
entry = null;
300+
return false;
301+
}
295302
VsProjectAnalyzer analyzer = null;
296303
if (cookie != VSConstants.VSCOOKIE_NIL) {
297304
IVsHierarchy hierarchy;
@@ -486,7 +493,14 @@ internal static PythonProjectNode GetProjectFromFile(this IServiceProvider servi
486493
IVsHierarchy hierarchy;
487494
uint itemid;
488495
docTable.GetDocumentHierarchyItem(cookie, out hierarchy, out itemid);
489-
return hierarchy.GetProject()?.GetPythonProject();
496+
var project = hierarchy.GetProject();
497+
if (project != null) {
498+
return project.GetPythonProject();
499+
}
500+
501+
object projectObj;
502+
ErrorHandler.ThrowOnFailure(hierarchy.GetProperty(itemid, (int)__VSHPROPID.VSHPROPID_ExtObject, out projectObj));
503+
return (projectObj as EnvDTE.Project)?.GetPythonProject();
490504
}
491505
return null;
492506
}

Python/Product/PythonTools/PythonTools/Repl/PythonInteractiveEvaluator.cs

+41-29
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,43 @@ internal virtual void OnConnected() { }
122122
internal virtual void OnAttach() { }
123123
internal virtual void OnDetach() { }
124124

125+
private PythonProjectNode GetAssociatedPythonProject(InterpreterConfiguration interpreter = null) {
126+
var moniker = ProjectMoniker;
127+
if (interpreter == null) {
128+
interpreter = Configuration?.Interpreter;
129+
}
130+
131+
if (string.IsNullOrEmpty(moniker) && interpreter != null) {
132+
var interpreterService = _serviceProvider.GetComponentModel().GetService<IInterpreterRegistryService>();
133+
moniker = interpreterService.GetProperty(interpreter.Id, "ProjectMoniker") as string;
134+
}
135+
136+
if (string.IsNullOrEmpty(moniker)) {
137+
return null;
138+
}
139+
140+
return _serviceProvider.GetProjectFromFile(moniker);
141+
}
142+
143+
125144
public VsProjectAnalyzer Analyzer {
126145
get {
127146
if (_analyzer != null) {
128147
return _analyzer;
129148
}
130149

131-
var interpreterService = _serviceProvider.GetComponentModel().GetService<IInterpreterRegistryService>();
132150
var config = Configuration;
133151

134152
if (config == null) {
135153
_analyzer = _serviceProvider.GetPythonToolsService().DefaultAnalyzer;
136154
} else {
137-
_analyzer = new VsProjectAnalyzer(_serviceProvider, interpreterService.FindInterpreter(config.Interpreter.Id));
155+
var projectFile = GetAssociatedPythonProject(config.Interpreter)?.BuildProject;
156+
var interpreterService = _serviceProvider.GetComponentModel().GetService<IInterpreterRegistryService>();
157+
_analyzer = new VsProjectAnalyzer(
158+
_serviceProvider,
159+
interpreterService.FindInterpreter(config.Interpreter.Id),
160+
projectFile: projectFile
161+
);
138162
}
139163
return _analyzer;
140164
}
@@ -283,22 +307,20 @@ protected async Task<CommandProcessorThread> EnsureConnectedAsync() {
283307
}
284308

285309
return await _serviceProvider.GetUIThread().InvokeTask(async () => {
286-
if (!string.IsNullOrEmpty(ProjectMoniker)) {
287-
try {
288-
UpdatePropertiesFromProjectMoniker();
289-
} catch (NoInterpretersException ex) {
290-
WriteError(ex.ToString());
291-
return null;
292-
} catch (MissingInterpreterException ex) {
293-
WriteError(ex.ToString());
294-
return null;
295-
} catch (DirectoryNotFoundException ex) {
296-
WriteError(ex.ToString());
297-
return null;
298-
} catch (Exception ex) when (!ex.IsCriticalException()) {
299-
WriteError(ex.ToUnhandledExceptionMessage(GetType()));
300-
return null;
301-
}
310+
try {
311+
UpdatePropertiesFromProjectMoniker();
312+
} catch (NoInterpretersException ex) {
313+
WriteError(ex.ToString());
314+
return null;
315+
} catch (MissingInterpreterException ex) {
316+
WriteError(ex.ToString());
317+
return null;
318+
} catch (DirectoryNotFoundException ex) {
319+
WriteError(ex.ToString());
320+
return null;
321+
} catch (Exception ex) when (!ex.IsCriticalException()) {
322+
WriteError(ex.ToUnhandledExceptionMessage(GetType()));
323+
return null;
302324
}
303325

304326
var scriptsPath = ScriptsPath;
@@ -351,17 +373,7 @@ protected virtual async Task ExecuteStartupScripts(string scriptsPath) {
351373
}
352374

353375
internal void UpdatePropertiesFromProjectMoniker() {
354-
var solution = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution;
355-
if (solution == null) {
356-
return;
357-
}
358-
359-
IVsHierarchy hier;
360-
if (string.IsNullOrEmpty(ProjectMoniker) ||
361-
ErrorHandler.Failed(solution.GetProjectOfUniqueName(ProjectMoniker, out hier))) {
362-
return;
363-
}
364-
var pyProj = hier?.GetProject()?.GetPythonProject();
376+
var pyProj = GetAssociatedPythonProject();
365377
if (pyProj == null) {
366378
return;
367379
}

Python/Product/Uwp.Interpreter/PythonUwpInterpreterFactoryProvider.cs

+2
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,7 @@ public IPythonInterpreterFactory GetInterpreterFactory(string id) {
120120
.Where(x => x.Configuration.Id == id)
121121
.FirstOrDefault();
122122
}
123+
124+
public object GetProperty(string id, string propName) => null;
123125
}
124126
}

Python/Product/VSInterpreters/CPythonInterpreterFactoryProvider.cs

+10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using System.Text.RegularExpressions;
2525
using System.Threading;
2626
using Microsoft.PythonTools.Infrastructure;
27+
using Microsoft.PythonTools.Parsing;
2728
using Microsoft.Win32;
2829

2930
namespace Microsoft.PythonTools.Interpreter {
@@ -180,6 +181,13 @@ private static void TryRegisterInterpreter(Dictionary<string, InterpreterInforma
180181
version = new Version(2, 7);
181182
}
182183

184+
try {
185+
var langVer = version.ToLanguageVersion();
186+
} catch (InvalidOperationException) {
187+
// Version is not currently supported
188+
return;
189+
}
190+
183191
var archStr = interpKey.GetValue("Architecture") as string;
184192
switch (archStr) {
185193
case "x64": arch = ProcessorArchitecture.Amd64; break;
@@ -353,6 +361,8 @@ private void OnInterpreterFactoriesChanged() {
353361
_interpFactoriesChanged?.Invoke(this, EventArgs.Empty);
354362
}
355363

364+
public object GetProperty(string id, string propName) => null;
365+
356366
#endregion
357367

358368
class InterpreterInformation {

Python/Product/VSInterpreters/MSBuildProjectInterpreterFactoryProvider.cs

+8
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ public IPythonInterpreterFactory GetInterpreterFactory(string id) {
129129
return null;
130130
}
131131

132+
public object GetProperty(string id, string propName) {
133+
if (propName == "ProjectMoniker") {
134+
var moniker = id.Substring(id.LastIndexOf('|') + 1);
135+
return PathUtils.IsValidPath(moniker) ? moniker : null;
136+
}
137+
return null;
138+
}
139+
132140
public static string GetInterpreterId(string file, string id) {
133141
return String.Join("|", MSBuildProviderName, id, file);
134142
}

Python/Tests/Core/ReplEvaluatorTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ public IPythonInterpreterFactory GetInterpreterFactory(string id) {
235235
.FirstOrDefault();
236236
}
237237

238+
public object GetProperty(string id, string propName) => null;
239+
238240
public event EventHandler InterpreterFactoriesChanged { add { } remove { } }
239241
}
240242

Python/Tests/Utilities.Python.Analysis/MockInterpreterOptionsService.cs

+4
Original file line numberDiff line numberDiff line change
@@ -165,5 +165,9 @@ public InterpreterConfiguration FindConfiguration(string id) {
165165
public string AddConfigurableInterpreter(string name, InterpreterConfiguration config) {
166166
throw new NotImplementedException();
167167
}
168+
169+
public object GetProperty(string id, string propName) {
170+
throw new NotImplementedException();
171+
}
168172
}
169173
}

Python/Tests/Utilities.Python.Analysis/MockPythonInterpreterFactoryProvider.cs

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public IPythonInterpreterFactory GetInterpreterFactory(string id) {
9090
.FirstOrDefault();
9191
}
9292

93+
public object GetProperty(string id, string propName) => null;
94+
9395
public event EventHandler InterpreterFactoriesChanged;
9496
}
9597
}

0 commit comments

Comments
 (0)