public async Task HoverGenericClass() { const string code = @" from typing import TypeVar, Generic _T = TypeVar('_T') class Box(Generic[_T]): def __init__(self, v: _T): self.v = v def get(self) -> _T: return self.v boxedint = Box(1234) x = boxedint.get() boxedstr = Box('str') y = boxedstr.get() "; var analysis = await GetAnalysisAsync(code, PythonVersions.LatestAvailable3X); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(14, 15), "Box.get() -> int", new SourceSpan(14, 13, 14, 17)); AssertHover(hs, analysis, new SourceLocation(17, 15), "Box.get() -> str", new SourceSpan(17, 13, 17, 17)); }
public void OnPointerEnter(PointerEventData eventData) { if (enableHoverSound == true) { HoverSource.PlayOneShot(hoverSound); } }
public async Task AssignmentExpressions() { const string code = @" (a := 1) "; var analysis = await GetAnalysisAsync(code, PythonVersions.Required_Python38X); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(2, 2), @"a: int", new SourceSpan(2, 2, 2, 3)); }
public async Task ImportAsNameHover() { const string code = @" import datetime as d123 "; var analysis = await GetAnalysisAsync(code, PythonVersions.LatestAvailable3X); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(2, 11), "module datetime*", new SourceSpan(2, 8, 2, 16)); AssertHover(hs, analysis, new SourceLocation(2, 21), "module datetime*", new SourceSpan(2, 20, 2, 24)); }
public async Task FromImportParts() { const string code = @" from time import time "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(2, 7), @"module time*", new SourceSpan(2, 6, 2, 10)); AssertHover(hs, analysis, new SourceLocation(2, 22), @"time() -> float*", new SourceSpan(2, 18, 2, 22)); }
public async Task FromImportHover() { const string code = @" from os import path as p "; var analysis = await GetAnalysisAsync(code, PythonVersions.LatestAvailable3X); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(2, 6), "module os*", new SourceSpan(2, 6, 2, 8)); AssertHover(hs, analysis, new SourceLocation(2, 16), "module*", new SourceSpan(2, 16, 2, 20)); AssertHover(hs, analysis, new SourceLocation(2, 24), "module*", new SourceSpan(2, 24, 2, 25)); }
public async Task ImmediateClassScopeVar() { const string code = @" class A: x = 1 y = x "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(4, 7), @"x: int", new SourceSpan(4, 7, 4, 8)); }
public async Task CompiledCode() { const string code = @" import os os.mkdir() "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); var hover = hs.GetHover(analysis, new SourceLocation(3, 6)); hover.contents.value.Should().Contain("Create a directory"); }
public async Task HoverSpanCheck(bool is3x) { const string code = @" import datetime datetime.datetime.now().day "; var analysis = await GetAnalysisAsync(code, PythonVersions.LatestAvailable3X); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(3, 2), "module datetime*", new SourceSpan(3, 1, 3, 9)); AssertHover(hs, analysis, new SourceLocation(3, 11), "class datetime*", new SourceSpan(3, 9, 3, 18)); AssertHover(hs, analysis, new SourceLocation(3, 20), @"datetime.now(tz: tzinfo) -> datetime*", new SourceSpan(3, 18, 3, 22)); }
public async Task OsPath() { const string code = @" import os.path as PATH "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(2, 9), @"module os*", new SourceSpan(2, 8, 2, 10)); var name = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"ntpath" : @"posixpath"; AssertHover(hs, analysis, new SourceLocation(2, 12), $"module {name}*", new SourceSpan(2, 11, 2, 15)); AssertHover(hs, analysis, new SourceLocation(2, 20), $"module {name}*", new SourceSpan(2, 19, 2, 23)); }
public async Task BasicTypes() { const string code = @" x = 'str' class C: '''Class C is awesome''' def method(self, a:int, b) -> float: '''Returns a float!!!''' return 1.0 def func(a, b): '''Does nothing useful''' return 1 y = func(1, 2) string = str "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); var hover = hs.GetHover(analysis, new SourceLocation(2, 2)); hover.contents.value.Should().Be("x: str"); hover = hs.GetHover(analysis, new SourceLocation(2, 7)); hover.Should().BeNull(); hover = hs.GetHover(analysis, new SourceLocation(4, 7)); hover.contents.value.Should().Be("class C\n\nClass C is awesome"); hover = hs.GetHover(analysis, new SourceLocation(6, 9)); hover.contents.value.Should().Be("C.method(a: int, b) -> float\n\nReturns a float!!!"); hover = hs.GetHover(analysis, new SourceLocation(6, 22)); hover.contents.value.Should().Be("a: int"); hover = hs.GetHover(analysis, new SourceLocation(10, 7)); hover.contents.value.Should().Be("func(a, b)\n\nDoes nothing useful"); hover = hs.GetHover(analysis, new SourceLocation(14, 2)); hover.contents.value.Should().Be("y: int"); hover = hs.GetHover(analysis, new SourceLocation(15, 2)); hover.contents.value.Should().StartWith("class str\n\nstr(object='') -> str"); }
public async Task FromOsPath() { const string code = @" from os.path import join as JOIN "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(2, 7), @"module os*", new SourceSpan(2, 6, 2, 8)); var name = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"ntpath" : @"posixpath"; AssertHover(hs, analysis, new SourceLocation(2, 10), $"module {name}*", new SourceSpan(2, 9, 2, 13)); AssertHover(hs, analysis, new SourceLocation(2, 22), @"join(path: str, paths: str) -> str", new SourceSpan(2, 21, 2, 25)); AssertHover(hs, analysis, new SourceLocation(2, 30), @"join(path: str, paths: str) -> str", new SourceSpan(2, 29, 2, 33)); }
public async Task MissingSelf() { const string code = @" class A: def __init__(self): self.instance_var = 1 def do(self): y = instance_var y = do() "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertNoHover(hs, analysis, new SourceLocation(7, 15)); AssertNoHover(hs, analysis, new SourceLocation(8, 14)); }
public async Task FStringExpressions() { const string code = @" some = '' f'{some' Fr'{some' f'{some}' f'hey {some}' "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(3, 4), @"some: str", new SourceSpan(3, 4, 3, 8)); AssertHover(hs, analysis, new SourceLocation(4, 5), @"some: str", new SourceSpan(4, 5, 4, 9)); AssertHover(hs, analysis, new SourceLocation(5, 4), @"some: str", new SourceSpan(5, 4, 5, 8)); hs.GetHover(analysis, new SourceLocation(6, 3)).Should().BeNull(); AssertHover(hs, analysis, new SourceLocation(6, 8), @"some: str", new SourceSpan(6, 8, 6, 12)); }
public async Task SelfHover() { const string code = @" class Base(object): def fob_base(self): pass class Derived(Base): def fob_derived(self): self.fob_base() pass "; var analysis = await GetAnalysisAsync(code, PythonVersions.LatestAvailable3X); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(3, 19), "class Base*", new SourceSpan(3, 18, 3, 22)); AssertHover(hs, analysis, new SourceLocation(8, 8), "class Derived*", new SourceSpan(8, 8, 8, 12)); }
private static void AssertHover(HoverSource hs, IDocumentAnalysis analysis, SourceLocation position, string hoverText, SourceSpan?span = null) { var hover = hs.GetHover(analysis, position); if (hoverText.EndsWith("*")) { // Check prefix first, but then show usual message for mismatched value if (!hover.contents.value.StartsWith(hoverText.Remove(hoverText.Length - 1))) { Assert.AreEqual(hoverText, hover.contents.value); } } else { Assert.AreEqual(hoverText, hover.contents.value); } if (span.HasValue) { hover.range.Should().Be((Range)span.Value); } }
public async Task MemberWithSelf() { const string code = @" class A: def __init__(self): self.instance_var = 1 def do(self): y = self.instance_var z1 = func() z2 = self.func() def func(self): ... "; var analysis = await GetAnalysisAsync(code); var hs = new HoverSource(new PlainTextDocumentationSource()); AssertHover(hs, analysis, new SourceLocation(7, 19), @"instance_var: int", new SourceSpan(7, 17, 7, 30)); AssertNoHover(hs, analysis, new SourceLocation(8, 15)); AssertHover(hs, analysis, new SourceLocation(9, 20), @"A.func()", new SourceSpan(9, 18, 9, 23)); }
public async Task InitializedAsync(InitializedParams @params, CancellationToken cancellationToken = default, IReadOnlyList <string> userConfiguredPaths = null) { var initializationOptions = _initParams?.initializationOptions; _services.AddService(new DiagnosticsService(_services)); _analyzer = new PythonAnalyzer(_services); _services.AddService(_analyzer); _analyzer.AnalysisComplete += OnAnalysisComplete; _disposableBag.Add(() => _analyzer.AnalysisComplete -= OnAnalysisComplete); _services.AddService(new RunningDocumentTable(_services)); _rdt = _services.GetService <IRunningDocumentTable>(); var interpeterPath = initializationOptions?.interpreter.properties?.InterpreterPath; Version version = null; if (!string.IsNullOrWhiteSpace(interpeterPath)) { Version.TryParse(initializationOptions?.interpreter.properties?.Version, out version); } else { var fs = _services.GetService <IFileSystem>(); var exePath = PathUtils.LookPath(fs, "python"); if (exePath != null && TryGetPythonVersion(exePath, out version)) { _log?.Log(TraceEventType.Information, Resources.UsingPythonFromPATH); interpeterPath = exePath; } else { interpeterPath = null; } } var configuration = new InterpreterConfiguration( interpreterPath: interpeterPath, version: version ); //_services.AddService(new ModuleDatabase(_services)); var typeshedPath = initializationOptions?.typeStubSearchPaths.FirstOrDefault(); userConfiguredPaths = userConfiguredPaths ?? initializationOptions?.searchPaths; _interpreter = await PythonInterpreter.CreateAsync(configuration, Root, _services, typeshedPath, userConfiguredPaths.ToImmutableArray(), cancellationToken); _log?.Log(TraceEventType.Information, string.IsNullOrEmpty(_interpreter.Configuration.InterpreterPath) ? Resources.InitializingForGenericInterpreter : Resources.InitializingForPythonInterpreter.FormatInvariant(_interpreter.Configuration.InterpreterPath)); var fileSystem = _services.GetService <IFileSystem>(); _indexManager = new IndexManager(fileSystem, _interpreter.LanguageVersion, Root, initializationOptions?.includeFiles, initializationOptions?.excludeFiles, _services.GetService <IIdleTimeService>()); _indexManager.IndexWorkspace().DoNotWait(); _analyzer.AnalysisComplete += IndexLibraries; _disposableBag.Add(() => _analyzer.AnalysisComplete -= IndexLibraries); _services.AddService(_indexManager); _disposableBag.Add(_indexManager); var textDocCaps = _initParams?.capabilities?.textDocument; _completionSource = new CompletionSource( ChooseDocumentationSource(textDocCaps?.completion?.completionItem?.documentationFormat), Settings.completion, Services ); _hoverSource = new HoverSource( ChooseDocumentationSource(textDocCaps?.hover?.contentFormat) ); var sigInfo = textDocCaps?.signatureHelp?.signatureInformation; _signatureSource = new SignatureSource( ChooseDocumentationSource(sigInfo?.documentationFormat), sigInfo?.parameterInformation?.labelOffsetSupport == true ); _initialized = true; }
public async Task <InitializeResult> InitializeAsync(InitializeParams @params, CancellationToken cancellationToken) { _disposableBag.ThrowIfDisposed(); _clientCaps = @params.capabilities; _log = _services.GetService <ILogger>(); _services.AddService(new DiagnosticsService(_services)); var analyzer = new PythonAnalyzer(_services); _services.AddService(analyzer); _services.AddService(new RunningDocumentTable(_services)); _rdt = _services.GetService <IRunningDocumentTable>(); // TODO: multi-root workspaces. var rootDir = @params.rootUri != null? @params.rootUri.ToAbsolutePath() : PathUtils.NormalizePath(@params.rootPath); Version.TryParse(@params.initializationOptions.interpreter.properties?.Version, out var version); var configuration = new InterpreterConfiguration(null, null, interpreterPath: @params.initializationOptions.interpreter.properties?.InterpreterPath, moduleCachePath: @params.initializationOptions.interpreter.properties?.DatabasePath, version: version ) { // TODO: Remove this split once the extension is updated and no longer passes the interpreter search paths directly. // This is generally harmless to keep around. SearchPaths = @params.initializationOptions.searchPaths.Select(p => p.Split(';', StringSplitOptions.RemoveEmptyEntries)).SelectMany().ToList(), TypeshedPath = @params.initializationOptions.typeStubSearchPaths.FirstOrDefault() }; _interpreter = await PythonInterpreter.CreateAsync(configuration, rootDir, _services, cancellationToken); _services.AddService(_interpreter); var fileSystem = _services.GetService <IFileSystem>(); _indexManager = new IndexManager(fileSystem, _interpreter.LanguageVersion, rootDir, @params.initializationOptions.includeFiles, @params.initializationOptions.excludeFiles, _services.GetService <IIdleTimeService>()); _indexManager.IndexWorkspace().DoNotWait(); _services.AddService(_indexManager); _disposableBag.Add(_indexManager); DisplayStartupInfo(); _completionSource = new CompletionSource( ChooseDocumentationSource(_clientCaps?.textDocument?.completion?.completionItem?.documentationFormat), Settings.completion ); _hoverSource = new HoverSource( ChooseDocumentationSource(_clientCaps?.textDocument?.hover?.contentFormat) ); _signatureSource = new SignatureSource( ChooseDocumentationSource(_clientCaps?.textDocument?.signatureHelp?.signatureInformation?.documentationFormat) ); return(GetInitializeResult()); }
public async Task <InitializeResult> InitializeAsync(InitializeParams @params, CancellationToken cancellationToken) { _disposableBag.ThrowIfDisposed(); _clientCaps = @params.capabilities; _log = _services.GetService <ILogger>(); _services.AddService(new DiagnosticsService(_services)); var cacheFolderPath = @params.initializationOptions.cacheFolderPath; var fs = _services.GetService <IFileSystem>(); if (cacheFolderPath != null && !fs.DirectoryExists(cacheFolderPath)) { _log?.Log(TraceEventType.Warning, Resources.Error_InvalidCachePath); cacheFolderPath = null; } var analyzer = new PythonAnalyzer(_services, cacheFolderPath); _services.AddService(analyzer); analyzer.AnalysisComplete += OnAnalysisComplete; _disposableBag.Add(() => analyzer.AnalysisComplete -= OnAnalysisComplete); _services.AddService(new RunningDocumentTable(_services)); _rdt = _services.GetService <IRunningDocumentTable>(); _rootDir = @params.rootUri != null? @params.rootUri.ToAbsolutePath() : @params.rootPath; if (_rootDir != null) { _rootDir = PathUtils.NormalizePathAndTrim(_rootDir); } Version.TryParse(@params.initializationOptions.interpreter.properties?.Version, out var version); var configuration = new InterpreterConfiguration(null, null, interpreterPath: @params.initializationOptions.interpreter.properties?.InterpreterPath, version: version ) { // Split on ';' to support older VS Code extension versions which send paths as a single entry separated by ';'. TODO: Eventually remove. // Note that the actual classification of these paths as user/library is done later in MainModuleResolution.ReloadAsync. SearchPaths = @params.initializationOptions.searchPaths .Select(p => p.Split(';', StringSplitOptions.RemoveEmptyEntries)).SelectMany() .ToList(), TypeshedPath = @params.initializationOptions.typeStubSearchPaths.FirstOrDefault() }; _interpreter = await PythonInterpreter.CreateAsync(configuration, _rootDir, _services, cancellationToken); _services.AddService(_interpreter); var fileSystem = _services.GetService <IFileSystem>(); _indexManager = new IndexManager(fileSystem, _interpreter.LanguageVersion, _rootDir, @params.initializationOptions.includeFiles, @params.initializationOptions.excludeFiles, _services.GetService <IIdleTimeService>()); _indexManager.IndexWorkspace().DoNotWait(); _services.AddService(_indexManager); _disposableBag.Add(_indexManager); DisplayStartupInfo(); _completionSource = new CompletionSource( ChooseDocumentationSource(_clientCaps?.textDocument?.completion?.completionItem?.documentationFormat), Settings.completion ); _hoverSource = new HoverSource( ChooseDocumentationSource(_clientCaps?.textDocument?.hover?.contentFormat) ); var sigInfo = _clientCaps?.textDocument?.signatureHelp?.signatureInformation; _signatureSource = new SignatureSource( ChooseDocumentationSource(sigInfo?.documentationFormat), sigInfo?.parameterInformation?.labelOffsetSupport == true ); return(GetInitializeResult()); }
public async Task <InitializeResult> InitializeAsync(InitializeParams @params, CancellationToken cancellationToken) { _disposableBag.ThrowIfDisposed(); _clientCaps = @params.capabilities; _log = _services.GetService <ILogger>(); _services.AddService(new DiagnosticsService(_services)); var analyzer = new PythonAnalyzer(_services); _services.AddService(analyzer); _services.AddService(new RunningDocumentTable(_services)); _rdt = _services.GetService <IRunningDocumentTable>(); _rootDir = @params.rootUri != null? @params.rootUri.ToAbsolutePath() : @params.rootPath; if (_rootDir != null) { _rootDir = PathUtils.NormalizePath(_rootDir); _rootDir = PathUtils.TrimEndSeparator(_rootDir); } Version.TryParse(@params.initializationOptions.interpreter.properties?.Version, out var version); var configuration = new InterpreterConfiguration(null, null, interpreterPath: @params.initializationOptions.interpreter.properties?.InterpreterPath, moduleCachePath: @params.initializationOptions.interpreter.properties?.DatabasePath, version: version ) { // 1) Split on ';' to support older VS Code extension versions which send paths as a single entry separated by ';'. TODO: Eventually remove. // 2) Normalize paths. // 3) If a path isn't rooted, then root it relative to the workspace root. If _rootDir is null, then accept the path as-is. // 4) Trim off any ending separator for a consistent style. // 5) Filter out any entries which are the same as the workspace root; they are redundant. Also ignore "/" to work around the extension (for now). // 6) Remove duplicates. SearchPaths = @params.initializationOptions.searchPaths .Select(p => p.Split(';', StringSplitOptions.RemoveEmptyEntries)).SelectMany() .Select(PathUtils.NormalizePath) .Select(p => _rootDir == null || Path.IsPathRooted(p) ? p : Path.GetFullPath(p, _rootDir)) .Select(PathUtils.TrimEndSeparator) .Where(p => !string.IsNullOrWhiteSpace(p) && p != "/" && !p.PathEquals(_rootDir)) .Distinct(PathEqualityComparer.Instance) .ToList(), TypeshedPath = @params.initializationOptions.typeStubSearchPaths.FirstOrDefault() }; _interpreter = await PythonInterpreter.CreateAsync(configuration, _rootDir, _services, cancellationToken); _services.AddService(_interpreter); var fileSystem = _services.GetService <IFileSystem>(); _indexManager = new IndexManager(fileSystem, _interpreter.LanguageVersion, _rootDir, @params.initializationOptions.includeFiles, @params.initializationOptions.excludeFiles, _services.GetService <IIdleTimeService>()); _indexManager.IndexWorkspace().DoNotWait(); _services.AddService(_indexManager); _disposableBag.Add(_indexManager); DisplayStartupInfo(); _completionSource = new CompletionSource( ChooseDocumentationSource(_clientCaps?.textDocument?.completion?.completionItem?.documentationFormat), Settings.completion ); _hoverSource = new HoverSource( ChooseDocumentationSource(_clientCaps?.textDocument?.hover?.contentFormat) ); _signatureSource = new SignatureSource( ChooseDocumentationSource(_clientCaps?.textDocument?.signatureHelp?.signatureInformation?.documentationFormat) ); return(GetInitializeResult()); }
private static void AssertNoHover(HoverSource hs, IDocumentAnalysis analysis, SourceLocation position) { var hover = hs.GetHover(analysis, position); hover.Should().BeNull(); }
public async Task InitializedAsync(InitializedParams @params, CancellationToken cancellationToken = default, IReadOnlyList <string> userConfiguredPaths = null) { var initializationOptions = _initParams?.initializationOptions; _services.AddService(new DiagnosticsService(_services)); var cacheFolderPath = initializationOptions?.cacheFolderPath; var fs = _services.GetService <IFileSystem>(); if (cacheFolderPath != null && !fs.DirectoryExists(cacheFolderPath)) { _log?.Log(TraceEventType.Warning, Resources.Error_InvalidCachePath); cacheFolderPath = null; } var analyzer = new PythonAnalyzer(_services, cacheFolderPath); _services.AddService(analyzer); analyzer.AnalysisComplete += OnAnalysisComplete; _disposableBag.Add(() => analyzer.AnalysisComplete -= OnAnalysisComplete); _services.AddService(new RunningDocumentTable(_services)); _rdt = _services.GetService <IRunningDocumentTable>(); Version.TryParse(initializationOptions?.interpreter.properties?.Version, out var version); var configuration = new InterpreterConfiguration(null, null, interpreterPath: initializationOptions?.interpreter.properties?.InterpreterPath, version: version ); var typeshedPath = initializationOptions?.typeStubSearchPaths.FirstOrDefault(); userConfiguredPaths = userConfiguredPaths ?? initializationOptions?.searchPaths; _interpreter = await PythonInterpreter.CreateAsync(configuration, Root, _services, typeshedPath, userConfiguredPaths.ToImmutableArray(), cancellationToken); _services.AddService(_interpreter); _log?.Log(TraceEventType.Information, string.IsNullOrEmpty(_interpreter.Configuration.InterpreterPath) ? Resources.InitializingForGenericInterpreter : Resources.InitializingForPythonInterpreter.FormatInvariant(_interpreter.Configuration.InterpreterPath)); var fileSystem = _services.GetService <IFileSystem>(); _indexManager = new IndexManager(fileSystem, _interpreter.LanguageVersion, Root, initializationOptions?.includeFiles, initializationOptions?.excludeFiles, _services.GetService <IIdleTimeService>()); _indexManager.IndexWorkspace().DoNotWait(); _services.AddService(_indexManager); _disposableBag.Add(_indexManager); var textDocCaps = _initParams?.capabilities?.textDocument; _completionSource = new CompletionSource( ChooseDocumentationSource(textDocCaps?.completion?.completionItem?.documentationFormat), Settings.completion ); _hoverSource = new HoverSource( ChooseDocumentationSource(textDocCaps?.hover?.contentFormat) ); var sigInfo = textDocCaps?.signatureHelp?.signatureInformation; _signatureSource = new SignatureSource( ChooseDocumentationSource(sigInfo?.documentationFormat), sigInfo?.parameterInformation?.labelOffsetSupport == true ); }