Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #3437 Typeshed integration #4264

Merged
merged 12 commits into from
Jun 5, 2018
Merged

Fixes #3437 Typeshed integration #4264

merged 12 commits into from
Jun 5, 2018

Conversation

zooba
Copy link
Member

@zooba zooba commented May 25, 2018

Fixes #3437 Typeshed integration
Enables value merging from typeshed
Improves some handling of type annotations in AST imported files

Enables value merging from typeshed
Improves some handling of type annotations in AST imported files
@zooba
Copy link
Member Author

zooba commented May 25, 2018

@MikhailArkhipov In case you want to watch my work in progress on this. The basics are in there, just need to beef up the tests and the handling of the typing module when doing AST imports.

/// This should be used in place of:
/// <c>Path.GetDirectoryName(CommonUtils.TrimEndSeparator(path)) + Path.DirectorySeparatorChar</c>
/// </remarks>
public static string GetParent(string path) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can technically do Path.GetFullPath(Path.Combine(path, ".."))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's much slower and far more pedantic about paths (it will actually validate the paths...)

if (typeShedPaths != null) {
return typeShedPaths;
}
lock (_searchPathsLock) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like duplicate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a double check after taking the lock, which we then release immediately to do the asynchronous collection. But I'll move the re-lock earlier so we are less likely to search for the paths multiple times.

zooba added 3 commits May 29, 2018 15:17
@zooba zooba changed the title [WIP] Fixes #3437 Typeshed integration Fixes #3437 Typeshed integration May 31, 2018
@zooba
Copy link
Member Author

zooba commented Jun 1, 2018

@MikhailArkhipov @huguesv This is ready for review

@@ -0,0 +1,55 @@
using System;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing header

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, this whole file is unused and not meant to be checked in yet... whoops

@@ -289,15 +289,15 @@ internal bool RemoveVariable(string name, out VariableDef value)
}

internal virtual void ClearNodeValues() {
_nodeValues.Clear();
_nodeValues = new AnalysisDictionary<Node, NodeValue>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

References to these dictionaries are publicly available through properties. Is it safe to change the instance instead of calling Clear()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. We only change them on the thread that accesses it, and we replace it specifically so that references obtained through the properties continue to point at the old dictionary.

DeclaringModule = original.DeclaringModule;
DeclaringType = original.DeclaringType;
Name = original.Name;
_doc = (original as AstPythonFunction)?._doc ?? original.Documentation;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AstPythonFunction.Documentation first checks for _doc as well, no need to check for it separately.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to copy the null from _doc, but this doesn't do that either :) So a slightly different change coming

IsClassMethod = original.IsClassMethod;
IsStatic = original.IsStatic;
_overloads = original.Overloads.ToList();
Locations = (original as AstPythonFunction)?.Locations ?? (original as ILocatedMember)?.Locations ?? Array.Empty<LocationInfo>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AstPythonFunction implements ILocatedMember, so no need to check AstPythonFunction by itself


private IReadOnlyList<string> GetTypeShedPaths(int timeout) {
// First check
var typeShedPaths = _typeShedPaths;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_typeShedPaths is accessed outside of the lock

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deliberately, so we can avoid locking for the search if the search has already been done (it'll only ever be done once - we never change _typeShedPaths after initialization - but it depends on context too much to make it Lazy<T>).

Copy link
Contributor

@AlexanderSher AlexanderSher Jun 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since _searchPathsLock is used only for locking, it will be a thin lock and the overhead of using it is close to nothing:
https://blogs.msdn.microsoft.com/seteplia/2017/09/06/managed-object-internals-part-2-object-header-layout-and-the-cost-of-locking/
(removed second article cause it is using custom testing technique instead of reliable benchmark)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not using it has no overhead, and it's only for initialization.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also read outside the async to avoid any overhead there.

PythonPaths.Versions.LastOrDefault(v => Directory.Exists(Path.Combine(v.PrefixPath, "Lib", "site-packages", "typeshed")));

[TestMethod, Priority(0)]
public void TypeShedElementTree() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hacked this test to run under a version of python that doesn't have typeshed installed, and it still passes. I'm not sure what to make of that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:( It means our analysis is so good that typeshed doesn't actually help here. Which version did you run it on? The one I tried seemed to need it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.6

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, an easy way to disable type shed is to go into AstPythonInterpreter, search for IncludeTypeShed and set it to false (which I'm currently turning into one of our secret registry key settings)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the latest code, you can disable it by setting: HKEY_CURRENT_USER\Software\Microsoft\PythonTools\15.0\Analysis\Project@UseTypeStubPackages to 0 (defaults to 1). You can also set UseTypeStubPackagesExclusively to 1 to not merge with the original results.

return mmy;
} else if (mmx != null && mmy != null) {
mmx.AddModules(mmy._modules);
return mmx;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter anywhere that we return mmx instead of mmy?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. This should only be being used while we're constructing objects and before the analyzer ever gets a hold of it (great question though)

@@ -39,6 +39,13 @@ class AstPythonMultipleMembers : IPythonMultipleMembers, ILocatedMember {
_checkForLazy = true;
}

public IMember Trim() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if _checkForLazy is true? Will the caller know/expect to see a ILazyMember? If not you can return Members[0] which will do the lazy get.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, calling Members might resize _members potentially going from size 1 to 0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point though, should really check that here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, decided not to change it. If we trim down to a single lazy member, we should probably leave it lazy even if it will eventually (depending on context) resolve down to nothing.

@huguesv
Copy link
Contributor

huguesv commented Jun 1, 2018

With typeshed installed:
image

Without:
image

@huguesv
Copy link
Contributor

huguesv commented Jun 1, 2018

I was expecting to see the types for the urlopen parameters. Error list is from running mypy.
image
Are they removed intentionally? For my own method with type hints, the type appears:
image

@zooba
Copy link
Member Author

zooba commented Jun 1, 2018

About to push a fix for the module members issue, and it seems we're currently not resolving parameter annotations into displayable types, so there's a bit more work to do there. The default values of ... need to be ignored properly as well.

Fixes module members not combining shared names.
Fixes crash when parsing tuple assignment.
// Assume caller has already done the quick checks

IReadOnlyList<string> typeShedPaths;
var typeshed = await FindModuleInSearchPathAsync("typeshed");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ok that FindModuleInSearchPathAsync can be called several times concurrently before _typeShedPaths is finally assigned?

Copy link
Member Author

@zooba zooba Jun 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. We could call it every time if we wanted, it doesn't change any state. But since its results (rarely) change, better to cache it.

@zooba
Copy link
Member Author

zooba commented Jun 4, 2018

Still need to fix that test before merging, but that's all I'm doing

}

public IList<IPythonType> ReturnTypes => _returnTypes;
public IList<IPythonType> ReturnTypes => _overload.ReturnTypes;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

according to the constructor, _overload can be null.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's used in a few other places without checks, so I suppose ctor should throw if null.

@huguesv
Copy link
Contributor

huguesv commented Jun 4, 2018

Just that one comment.

zooba added 2 commits June 4, 2018 15:16
Fixes mishandling of linked variables that was breaking tests
@zooba zooba merged commit 814dd9b into microsoft:master Jun 5, 2018
@zooba zooba deleted the issue-3437 branch June 5, 2018 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants