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

Add typing to scope() #1170

Merged
merged 16 commits into from Sep 15, 2021
Merged

Add typing to scope() #1170

merged 16 commits into from Sep 15, 2021

Conversation

DanielNoord
Copy link
Collaborator

Steps

  • For new features or bug fixes, add a ChangeLog entry describing what your PR does.
  • Write a good description on what the PR does.

Description

After stumbling across this in pylint-dev/pylint#4995 I thought I might as well make a start with this.

One of the problems I foresee is that in some cases we return None in node_ng.py. I am not sure if this ever happens in a real scenario, but this will trip up mypy for pylint as it will want us to assert that any call to NodeNG.scope() did not return None.
Based on the docstring of that function that might be (legacy) code which is never triggered, but I am not sure. Perhaps a maintainer knows more about this.
In any case, if we can remove the Optional from the return typing this would be much more useful for pylint.

Type of Changes

Type
🔨 Refactoring

Related Issue

@DanielNoord DanielNoord marked this pull request as draft September 13, 2021 12:28
Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

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

Added a few comments. Unfortunately, they will probably result in more work than you expected, sorry about that.

astroid/nodes/scoped_nodes.py Outdated Show resolved Hide resolved
astroid/nodes/node_classes.py Outdated Show resolved Hide resolved
astroid/nodes/node_classes.py Outdated Show resolved Hide resolved
@@ -246,7 +259,7 @@ def frame(self):
"""
return self.parent.frame()

def scope(self):
def scope(self) -> Optional["LocalsDictNodeNG"]:
Copy link
Member

Choose a reason for hiding this comment

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

Regarding LocalsDictNodeNG: I fear that at some point it will just create another circular dependency. Maybe we should start looking into Protocol classes for that 🤔 Haven't really done so myself, thus don't know for certain if it would work.

https://docs.python.org/3/library/typing.html#typing.Protocol

--
Another issue: If at some point some scoped node inherits from another mixin class (not LocalsDictNodeNG, this will break.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Are you sure? Doesn't using "Class" prevent circular dependency?

Copy link
Member

Choose a reason for hiding this comment

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

The current code is fine. As you said, using a string as type annotation does prevent the circular dependency.
It's probably just that I'm not really a fan of the class name itself (LocalsDictNodeNG). Maybe that should be changed at some point 🤔

Anyway, let's leave it for now.

@cdce8p cdce8p added Maintenance Discussion or action around maintaining astroid or the dev workflow Work in progress High effort 🏋 Difficult solution or problem to solve and removed High effort 🏋 Difficult solution or problem to solve labels Sep 13, 2021
@DanielNoord DanielNoord marked this pull request as ready for review September 13, 2021 19:01
astroid/exceptions.py Outdated Show resolved Hide resolved
astroid/exceptions.py Outdated Show resolved Hide resolved
@DanielNoord
Copy link
Collaborator Author

Is this failing because of the recent update to pre-commit? 😕

@cdce8p
Copy link
Member

cdce8p commented Sep 13, 2021

Is this failing because of the recent update to pre-commit? 😕

No. main is fine. It seems to be something in this PR.

Update: I can reproduce the issue when running pylint locally.

@DanielNoord
Copy link
Collaborator Author

It has something to do with the import of nodes. Removing it fixes the issue.
Will investigate tomorrow!

@cdce8p
Copy link
Member

cdce8p commented Sep 13, 2021

It has something to do with the import of nodes. Removing it fixes the issue.
Will investigate tomorrow!

I would suspect some kind of caching issue. Might not be that easy to track down.

@DanielNoord
Copy link
Collaborator Author

I'm not sure if this solution works for you, but adding disable to the new error messages and removing on the unused places seems to solve the issue.
no-member has numerous false positives reported so I presumed this is likely a pylint issue rather than an issue with the actual code. Please correct if I'm wrong or if you would like another solution!

astroid/nodes/node_classes.py Outdated Show resolved Hide resolved
astroid/nodes/node_classes.py Outdated Show resolved Hide resolved
@@ -77,6 +77,8 @@
{"classmethod", "staticmethod", "builtins.classmethod", "builtins.staticmethod"}
)

T = TypeVar("T")
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this part, what does T means ?

Copy link
Collaborator Author

@DanielNoord DanielNoord Sep 15, 2021

Choose a reason for hiding this comment

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

I don't know how it works under the hood. But for

def scope(self: T) -> T:
        """The first parent node defining a new scope.

        :returns: The first parent scope node.
        :rtype: Module or FunctionDef or ClassDef or Lambda or GenExpr
        """
        return self

It makes the function return with the correct typing. It sets the return type to the type of self.

Copy link
Member

Choose a reason for hiding this comment

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

Ok I've read the documentation and I think T = TypeVar("T") is the example for TypeVar from the python doc, but I guess we can change the name to something else ? Maybe Scope (Scope = TypeVar("Scope")) ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

#1170 (comment)

This is something for you to discuss with Marc 😄

Copy link
Member

Choose a reason for hiding this comment

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

@cdce8p what do you think, isn't it better to have an explicit name here ?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry for the discrepancies @DanielNoord I started to not review some MR that Marc is already reviewing because there is a lot to review :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No worries! With the typing PRs it never hurts to have an additional pair of eyes.

Copy link
Member

Choose a reason for hiding this comment

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

It would be possible to rename the TypeVar, I just wouldn't recommend it in this case. T is the usual convention. Additionally, it doesn't have any constraints or bounds. Thus it could be reused in another function later.

That is, for example, different in the TypeVar we used in pylint-dev/pylint#4978.

astroid/nodes/node_classes.py Outdated Show resolved Hide resolved
astroid/nodes/node_ng.py Show resolved Hide resolved
astroid/nodes/node_ng.py Outdated Show resolved Hide resolved
@@ -1606,6 +1608,7 @@ def blockstart_tolineno(self):

:type: int
"""
# pylint: disable-next=no-member
Copy link
Member

Choose a reason for hiding this comment

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

I'm a bit hesitant about these pylint: disable statements. Maybe it would be better to remove the annotations in astroid/exceptions.py for now.
They don't add much as the error is only used in two locations anyway.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm going to fix this in another PR. I'll tag you!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See #1174

Copy link
Member

Choose a reason for hiding this comment

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

I see now! These are actual bugs, only Arguments should be assigned to self.args not a list.
I was under the impression that these are pylint bugs.

In that case, these are ok.

@DanielNoord
Copy link
Collaborator Author

DanielNoord commented Sep 15, 2021

@cdce8p
Copy link
Member

cdce8p commented Sep 15, 2021

Note to self after merging of Fix documentation after changes to astroid.nodes #1175, the linkt to LocalsDictNodeNG needs to be changed in doc/api/astroid.nodes.rst

You don't need to wait for it. That merge conflict should be easy to resolve.

Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

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

Some final comments. Besides that, this LGTM!
Thanks @DanielNoord 🐬

Can be merged if @Pierre-Sassoulas is ok with using T for the generic TypeVar.

astroid/nodes/node_classes.py Outdated Show resolved Hide resolved
astroid/nodes/node_ng.py Outdated Show resolved Hide resolved
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
@cdce8p
Copy link
Member

cdce8p commented Sep 15, 2021

@DanielNoord I've just merged the #1174 and #1175. Can you update this one so it can be merged as well? Let me know if I can help.

@DanielNoord
Copy link
Collaborator Author

@cdce8p Should be good to go after these tests pass!

Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

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

Thanks @DanielNoord 🚀

@cdce8p cdce8p merged commit 2e26f03 into pylint-dev:main Sep 15, 2021
@DanielNoord DanielNoord deleted the typing-scope branch September 15, 2021 14:14
@DanielNoord
Copy link
Collaborator Author

@cdce8p The check on this latest commit failed although main seems to be fine. Might be because I removed the branch mid-check, but thought I would notify you about this.

@cdce8p
Copy link
Member

cdce8p commented Sep 15, 2021

@DanielNoord Thanks. Yeah, this isn't an issue. main is fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Maintenance Discussion or action around maintaining astroid or the dev workflow
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants