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 inference of Compare nodes #979

Merged
merged 3 commits into from
Sep 14, 2021

Conversation

nelfin
Copy link
Contributor

@nelfin nelfin commented Apr 29, 2021

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

This change adds a first attempt at inferring the boolean value of Compare nodes.

Type of Changes

Type
✨ New feature

Related Issue

Closes #846

@nelfin nelfin force-pushed the feature/846-literal-compare branch 2 times, most recently from 50545b9 to eca9202 Compare August 18, 2021 05:57
@nelfin nelfin marked this pull request as ready for review August 18, 2021 06:01
@nelfin
Copy link
Contributor Author

nelfin commented Aug 18, 2021

Updated to reflect latest changes in astroid API and to catch an edge case I found in later testing. Since this is a new feature (even if it's small) this might be better as part of a minor release instead of a point release so I'm happy to wait for 2.8.x before merging.

@Pierre-Sassoulas Pierre-Sassoulas added this to the 2.8.0 milestone Aug 18, 2021
@Pierre-Sassoulas Pierre-Sassoulas added Enhancement ✨ Improvement to a component Needs review 🔍 Needs to be reviewed by one or multiple more persons and removed Work in progress labels Aug 18, 2021
@Pierre-Sassoulas Pierre-Sassoulas self-requested a review August 27, 2021 06:08
Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

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

Hey, thank you for this, it looks awesome and will definitely go in 2.8.0. I don't have time for a full review yet, but could you add the typing for new or modified function please ? Circular import might appear, you can use if TYPE_CHECKING: to import if that's the case.

astroid/inference.py Outdated Show resolved Hide resolved
@nelfin nelfin force-pushed the feature/846-literal-compare branch from eca9202 to 154f60c Compare August 27, 2021 13:23
@nelfin
Copy link
Contributor Author

nelfin commented Aug 27, 2021

Bleeeeergh, I set __future__.annotations because pylint wouldn't pass the pre-commit checks otherwise, I forgot that it wasn't defined for 3.6. I'll see what needs to be done to work around that for 3.6-3.10

Ref pylint-dev#846.

Identity checks are currently Uninferable as there is no sensible way to
infer that two Instances refer to the same object without accurately
modelling control flow.
@nelfin nelfin force-pushed the feature/846-literal-compare branch from 154f60c to 030f4d0 Compare August 27, 2021 13:39
@Pierre-Sassoulas Pierre-Sassoulas self-requested a review August 27, 2021 18:30
Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

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

Looks good, the tests are on point and very thorough.

astroid/inference.py Show resolved Hide resolved
@Pierre-Sassoulas Pierre-Sassoulas removed the Needs review 🔍 Needs to be reviewed by one or multiple more persons label Sep 13, 2021
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.

Great work @nelfin 🚀
I now, I'm a bit late for the review. Notice some small things that I wanted to mention nevertheless.

@@ -790,6 +792,98 @@ def infer_binop(self, context=None):
nodes.BinOp._infer_binop = _infer_binop
nodes.BinOp._infer = infer_binop

COMPARE_OPS = {
Copy link
Member

Choose a reason for hiding this comment

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

COMPARE_OPS: Dict[str, Callable[[Any, Any], bool]] = { ... }

That would help inferring op_func and expr correctly.

Comment on lines +805 to +808
UNINFERABLE_OPS = {
"is",
"is not",
}
Copy link
Member

Choose a reason for hiding this comment

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

This could be a frozenset

Comment on lines +813 to +814
# Is this the stupidest idea or the simplest idea?
return ast.literal_eval(node.as_string())
Copy link
Member

Choose a reason for hiding this comment

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

I like that! Something like this here would also work, but isn't as clean

    if isinstance(node, nodes.Const):
        return node.value
    if isinstance(node, nodes.Tuple):
        return tuple(_to_literal(val) for val in node.elts)
    if isinstance(node, nodes.List):
        return [_to_literal(val) for val in node.elts]
    if isinstance(node, nodes.Set):
        return set(_to_literal(val) for val in node.elts)
    if isinstance(node, nodes.Dict):
        return {_to_literal(k): _to_literal(v) for k, v in node.items}

return retval # it was all the same value


def _infer_compare(self: nodes.Compare, context: InferenceContext) -> Any:
Copy link
Member

Choose a reason for hiding this comment

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

In almost all _infer_xxx methods context is annotated as Optional[InferenceContext] with None as default. It works either way, but it might be nice to use the current default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement ✨ Improvement to a component
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compare node inferring
3 participants