Skip to content

Commit 88860a3

Browse files
committed
Merge pull request #715 from zooba/v2.1
V2.1
2 parents a5935c5 + fbc1339 commit 88860a3

13 files changed

+137
-72
lines changed

Python/Product/Analysis/Analyzer/ExpressionEvaluator.cs

+2
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ private static NameExpression[] GetNamedArguments(IList<Arg> args) {
305305
}
306306

307307
res[i - (args.Count - res.Length)] = (NameExpression)args[i].NameExpression;
308+
} else if (res != null) {
309+
res[i - (args.Count - res.Length)] = NameExpression.Empty;
308310
}
309311
}
310312
return res ?? EmptyNames;

Python/Product/Analysis/Interpreter/PythonInterpreterFactoryWithDatabase.cs

+13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Threading.Tasks;
2323
using Microsoft.PythonTools.Analysis;
2424
using Microsoft.PythonTools.Interpreter.Default;
25+
using Microsoft.PythonTools.Parsing;
2526
using Microsoft.VisualStudioTools;
2627

2728
namespace Microsoft.PythonTools.Interpreter {
@@ -68,6 +69,18 @@ bool watchLibraryForChanges
6869
_id = id;
6970
_config = config;
7071

72+
if (_config == null) {
73+
throw new ArgumentNullException("config");
74+
}
75+
76+
// Avoid creating a interpreter with an unsupported version.
77+
// https://github.com/Microsoft/PTVS/issues/706
78+
try {
79+
var langVer = _config.Version.ToLanguageVersion();
80+
} catch (InvalidOperationException ex) {
81+
throw new ArgumentException(ex.Message, ex);
82+
}
83+
7184
if (watchLibraryForChanges && Directory.Exists(_config.LibraryPath)) {
7285
_refreshIsCurrentTrigger = new Timer(RefreshIsCurrentTimer_Elapsed);
7386

Python/Product/Analysis/Parsing/Ast/NameExpression.cs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
namespace Microsoft.PythonTools.Parsing.Ast {
1818
public class NameExpression : Expression {
1919
public static readonly NameExpression[] EmptyArray = new NameExpression[0];
20+
public static readonly NameExpression Empty = new NameExpression("");
2021

2122
private readonly string _name;
2223

Python/Product/Analysis/Parsing/PythonLanguageVersion.cs

+5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public static Version ToVersion(this PythonLanguageVersion version) {
5252

5353
public static PythonLanguageVersion ToLanguageVersion(this Version version) {
5454
switch (version.Major) {
55+
case 0:
56+
switch (version.Minor) {
57+
case 0: return PythonLanguageVersion.None;
58+
}
59+
break;
5560
case 2:
5661
switch (version.Minor) {
5762
case 4: return PythonLanguageVersion.V24;

Python/Product/Analysis/PythonAnalyzer.Specializations.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,10 @@ int index
187187
for (int i = 0, j = args.Length - keywordArgNames.Length;
188188
i < keywordArgNames.Length && j < args.Length;
189189
++i, ++j) {
190-
if (keywordArgNames[i].Name == name) {
190+
var kwArg = keywordArgNames[i];
191+
if (kwArg == null) {
192+
Debug.Fail("Null keyword argument");
193+
} else if (kwArg.Name == name) {
191194
return args[j];
192195
}
193196
}

Python/Product/Django/Project/DjangoAnalyzer.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,10 @@ private static IAnalysisSet GetArg(
477477
for (int i = 0, j = args.Length - keywordArgNames.Length;
478478
i < keywordArgNames.Length && j < args.Length;
479479
++i, ++j) {
480-
if (keywordArgNames[i].Name == name) {
480+
var kwArg = keywordArgNames[i];
481+
if (kwArg == null) {
482+
Debug.Fail("Null keyword argument");
483+
} else if (kwArg.Name == name) {
481484
return args[j];
482485
}
483486
}

Python/Product/PythonTools/PythonTools/Commands/ExecuteInReplCommand.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ private void QueryStatusMethod(object sender, EventArgs args) {
7777
var interpreterService = PythonToolsPackage.ComponentModel.GetService<IInterpreterOptionsService>();
7878
string filename, dir;
7979
if (!PythonToolsPackage.TryGetStartupFileAndDirectory(out filename, out dir, out analyzer) ||
80+
string.IsNullOrEmpty(filename) ||
8081
interpreterService == null ||
8182
interpreterService.NoInterpretersValue == analyzer.InterpreterFactory) {
8283
// no interpreters installed, disable the command.
@@ -113,7 +114,9 @@ public override void DoCommand(object sender, EventArgs args) {
113114
VsProjectAnalyzer analyzer;
114115
string filename, dir;
115116
var pyProj = CommonPackage.GetStartupProject() as PythonProjectNode;
116-
if (!PythonToolsPackage.TryGetStartupFileAndDirectory(out filename, out dir, out analyzer)) {
117+
if (!PythonToolsPackage.TryGetStartupFileAndDirectory(out filename, out dir, out analyzer) ||
118+
string.IsNullOrEmpty(filename)
119+
) {
117120
// TODO: Error reporting
118121
return;
119122
}

Python/Product/PythonTools/PythonTools/Project/PythonProjectNode.cs

+14-3
Original file line numberDiff line numberDiff line change
@@ -1979,7 +1979,12 @@ await VirtualEnv.CreateAndInstallDependencies(
19791979
);
19801980
}
19811981

1982-
var existing = _interpreters.FindInterpreter(path);
1982+
var interpreters = _interpreters;
1983+
if (interpreters == null) {
1984+
return null;
1985+
}
1986+
1987+
var existing = interpreters.FindInterpreter(path);
19831988
if (existing != null) {
19841989
return existing;
19851990
}
@@ -1996,8 +2001,14 @@ await VirtualEnv.CreateAndInstallDependencies(
19962001
throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
19972002
}
19982003

1999-
var id = _interpreters.CreateInterpreterFactory(options);
2000-
return _interpreters.FindInterpreter(id, options.LanguageVersion);
2004+
Guid id;
2005+
try {
2006+
id = interpreters.CreateInterpreterFactory(options);
2007+
} catch (ArgumentException ex) {
2008+
TaskDialog.ForException(Site, ex, issueTrackerUrl: IssueTrackerUrl).ShowModal();
2009+
return null;
2010+
}
2011+
return interpreters.FindInterpreter(id, options.LanguageVersion);
20012012
}
20022013

20032014

Python/Product/PythonTools/PythonToolsPackage.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,17 @@ private void RefreshReplCommands(object sender, EventArgs e) {
808808

809809
private List<OpenReplCommand> GetReplCommands() {
810810
var replCommands = new List<OpenReplCommand>();
811-
var interpreterService = ComponentModel.GetService<IInterpreterOptionsService>();
811+
812+
var compModel = ComponentModel;
813+
if (compModel == null) {
814+
return replCommands;
815+
}
816+
817+
var interpreterService = compModel.GetService<IInterpreterOptionsService>();
818+
if (interpreterService == null) {
819+
return replCommands;
820+
}
821+
812822
var factories = interpreterService.Interpreters.ToList();
813823
if (factories.Count == 0) {
814824
return replCommands;

Python/Product/VSInterpreters/CPythonInterpreterFactoryProvider.cs

+20-13
Original file line numberDiff line numberDiff line change
@@ -159,19 +159,26 @@ private bool RegisterInterpreters(HashSet<string> registeredPaths, RegistryKey p
159159
}
160160

161161
if (!_interpreters.Any(f => f.Id == id && f.Configuration.Version == version)) {
162-
_interpreters.Add(InterpreterFactoryCreator.CreateInterpreterFactory(
163-
new InterpreterFactoryCreationOptions {
164-
LanguageVersion = version,
165-
Id = id,
166-
Description = string.Format("{0} {1}", description, version),
167-
InterpreterPath = Path.Combine(basePath, CPythonInterpreterFactoryConstants.ConsoleExecutable),
168-
WindowInterpreterPath = Path.Combine(basePath, CPythonInterpreterFactoryConstants.WindowsExecutable),
169-
LibraryPath = Path.Combine(basePath, CPythonInterpreterFactoryConstants.LibrarySubPath),
170-
PathEnvironmentVariableName = CPythonInterpreterFactoryConstants.PathEnvironmentVariableName,
171-
Architecture = actualArch ?? ProcessorArchitecture.None,
172-
WatchLibraryForNewModules = true
173-
}
174-
));
162+
IPythonInterpreterFactory fact;
163+
try {
164+
fact = InterpreterFactoryCreator.CreateInterpreterFactory(
165+
new InterpreterFactoryCreationOptions {
166+
LanguageVersion = version,
167+
Id = id,
168+
Description = string.Format("{0} {1}", description, version),
169+
InterpreterPath = Path.Combine(basePath, CPythonInterpreterFactoryConstants.ConsoleExecutable),
170+
WindowInterpreterPath = Path.Combine(basePath, CPythonInterpreterFactoryConstants.WindowsExecutable),
171+
LibraryPath = Path.Combine(basePath, CPythonInterpreterFactoryConstants.LibrarySubPath),
172+
PathEnvironmentVariableName = CPythonInterpreterFactoryConstants.PathEnvironmentVariableName,
173+
Architecture = actualArch ?? ProcessorArchitecture.None,
174+
WatchLibraryForNewModules = true
175+
}
176+
);
177+
} catch (ArgumentException) {
178+
continue;
179+
}
180+
181+
_interpreters.Add(fact);
175182
anyAdded = true;
176183
}
177184
}

Python/Tests/Analysis/AnalysisTest.cs

+35-7
Original file line numberDiff line numberDiff line change
@@ -6465,13 +6465,13 @@ class A:
64656465
public void RecursiveDecorators() {
64666466
// See https://github.com/Microsoft/PTVS/issues/542
64676467
// Should not crash/OOM
6468-
var code = @"
6469-
def f():
6470-
def d(fn):
6471-
@f()
6472-
def g(): pass
6473-
6474-
return d
6468+
var code = @"
6469+
def f():
6470+
def d(fn):
6471+
@f()
6472+
def g(): pass
6473+
6474+
return d
64756475
";
64766476

64776477
var cancelAt = new CancellationTokenSource(TimeSpan.FromSeconds(10));
@@ -6484,6 +6484,34 @@ def g(): pass
64846484
}
64856485
}
64866486

6487+
[TestMethod, Priority(0)]
6488+
public void NullNamedArgument() {
6489+
CallDelegate callable = (node, unit, args, keywordArgNames) => {
6490+
bool anyNull = false;
6491+
Console.WriteLine("fn({0})", string.Join(", ", keywordArgNames.Select(n => {
6492+
if (n == null) {
6493+
anyNull = true;
6494+
return "(null)";
6495+
} else {
6496+
return n.Name + "=(value)";
6497+
}
6498+
})));
6499+
Assert.IsFalse(anyNull, "Some arguments were null");
6500+
return AnalysisSet.Empty;
6501+
};
6502+
6503+
using (var state = CreateAnalyzer(PythonLanguageVersion.V27)) {
6504+
state.SpecializeFunction("NullNamedArgument", "fn", callable);
6505+
6506+
var entry1 = state.AddModule("NullNamedArgument", "NullNamedArgument.py");
6507+
Prepare(entry1, GetSourceUnit("def fn(**kwargs): pass", "NullNamedArgument"), state.LanguageVersion);
6508+
entry1.Analyze(CancellationToken.None);
6509+
var entry2 = state.AddModule("test", "test.py");
6510+
Prepare(entry2, GetSourceUnit("import NullNamedArgument; NullNamedArgument.fn(a=0, ]]])", "test"), state.LanguageVersion);
6511+
entry2.Analyze(CancellationToken.None);
6512+
}
6513+
}
6514+
64876515
#endregion
64886516

64896517
#region Helpers

Python/Tests/Core.UI/BuildTasksUITests.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* ***************************************************************************/
1414

1515
using System;
16+
using System.Collections.Generic;
1617
using System.Diagnostics;
1718
using System.IO;
1819
using System.Linq;
@@ -246,14 +247,14 @@ public void CustomCommandsRunProcessInConsole() {
246247
EnvDTE.Project proj;
247248
OpenProject(app, "Commands3.sln", out node, out proj);
248249

249-
var existingProcesses = Process.GetProcessesByName("cmd");
250+
var existingProcesses = new HashSet<int>(Process.GetProcessesByName("cmd").Select(p => p.Id));
250251

251252
Execute(node, "Write to Console");
252253

253254
Process newProcess = null;
254255
for (int retries = 100; retries > 0 && newProcess == null; --retries) {
255256
Thread.Sleep(100);
256-
newProcess = Process.GetProcessesByName("cmd").Except(existingProcesses).FirstOrDefault();
257+
newProcess = Process.GetProcessesByName("cmd").Where(p => !existingProcesses.Contains(p.Id)).FirstOrDefault();
257258
}
258259
Assert.IsNotNull(newProcess, "Process did not start");
259260
try {

Python/Tests/VSInterpretersTests/VSInterpretersTests.cs

+21-43
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using System.Reflection;
2222
using System.Text.RegularExpressions;
2323
using Microsoft.PythonTools.Interpreter;
24+
using Microsoft.PythonTools.Parsing;
2425
using Microsoft.VisualStudio.Shell.Interop;
2526
using Microsoft.VisualStudio.TestTools.UnitTesting;
2627
using TestUtilities;
@@ -48,49 +49,6 @@ public static void RemoveFiles() {
4849
}
4950
}
5051

51-
[TestMethod, Priority(0)]
52-
public void MinimumAssembliesLoaded() {
53-
var assembliesBefore = new HashSet<Assembly>(AppDomain.CurrentDomain.GetAssemblies());
54-
// This assembly is probably already loaded, but let's pretend that
55-
// we've loaded it again for this test.
56-
assembliesBefore.Remove(typeof(IInterpreterOptionsService).Assembly);
57-
58-
var catalog = new AssemblyCatalog(typeof(IInterpreterOptionsService).Assembly);
59-
var container = new CompositionContainer(catalog);
60-
var service = container.GetExportedValue<IInterpreterOptionsService>();
61-
62-
Assert.IsInstanceOfType(service, typeof(InterpreterOptionsService));
63-
64-
// Ensure these assemblies were loaded.
65-
var expectedAssemblies = new HashSet<string> {
66-
"Microsoft.PythonTools.Analysis",
67-
"Microsoft.PythonTools.VSInterpreters",
68-
"Microsoft.PythonTools.IronPython.Interpreter"
69-
};
70-
71-
// Ensure these assemblies were not loaded. In the out-of-VS
72-
// scenario, we cannot always resolve these and so will crash.
73-
// For tests, they are always available, and when installed they may
74-
// always be available in the GAC, but we want to ensure that they
75-
// are not loaded anyway.
76-
var notExpectedAssemblies = new HashSet<string> {
77-
"Microsoft.PythonTools",
78-
"Microsoft.VisualStudio.ReplWindow"
79-
};
80-
81-
Console.WriteLine("Loaded assemblies:");
82-
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) {
83-
if (!assembliesBefore.Remove(assembly)) {
84-
var name = assembly.GetName().Name;
85-
Console.WriteLine("{0}: {1}", name, assembly.FullName);
86-
expectedAssemblies.Remove(name);
87-
Assert.IsFalse(notExpectedAssemblies.Remove(name), assembly.FullName + " should not have been loaded");
88-
}
89-
}
90-
91-
Assert.AreEqual(0, expectedAssemblies.Count, "Was not loaded: " + string.Join(", ", expectedAssemblies));
92-
}
93-
9452
private static string CompileString(string csharpCode, string outFile) {
9553
var provider = new Microsoft.CSharp.CSharpCodeProvider();
9654
var parameters = new System.CodeDom.Compiler.CompilerParameters {
@@ -323,5 +281,25 @@ public void ProviderLoadLog_SuccessAndFailure() {
323281

324282
Assert.AreEqual(1, service.KnownProviders.Count());
325283
}
284+
285+
[TestMethod, Priority(0)]
286+
public void InvalidInterpreterVersion() {
287+
try {
288+
var lv = new Version(1, 0).ToLanguageVersion();
289+
Assert.Fail("Expected InvalidOperationException");
290+
} catch (InvalidOperationException) {
291+
}
292+
293+
try {
294+
InterpreterFactoryCreator.CreateInterpreterFactory(new InterpreterFactoryCreationOptions {
295+
Id = Guid.NewGuid(),
296+
LanguageVersionString = "1.0"
297+
});
298+
Assert.Fail("Expected ArgumentException");
299+
} catch (ArgumentException ex) {
300+
// Expect version number in message
301+
AssertUtil.Contains(ex.Message, "1.0");
302+
}
303+
}
326304
}
327305
}

0 commit comments

Comments
 (0)