-
-
Notifications
You must be signed in to change notification settings - Fork 280
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
Create infer_object
#2167
Create infer_object
#2167
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #2167 +/- ##
==========================================
- Coverage 92.53% 92.52% -0.02%
==========================================
Files 94 94
Lines 10804 10864 +60
==========================================
+ Hits 9998 10052 +54
- Misses 806 812 +6
Flags with carried forward coverage won't be shown. Click here to find out more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what the right approach is, but shouldn't we remove more code in node_classe and scope_nodes if we refactor the way it's done right now ?
node: nodes.NodeNG, context: InferenceContext | None = None, **kwargs: Any | ||
) -> Generator[InferenceResult, None, None]: | ||
"""Find the infer method for the given node and call it.""" | ||
if isinstance( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the number of time this is going to be called it might be a good idea to do stats on the most common one so it's tested first if we go with this approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think we might want to refactor this anyway before releasing the final version.
For now I'd say, let's use this as a start and see how we can optimise. I think there are a lot of other small optimisations we could do here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even with a statistical approach, I'm nervous about this approach, it feels like a code smell that we should be using polymorphism, which is more like the existing way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also use a dictionary of nodes types and associated methods, which makes it (almost) O(1)
. However, I think there might be good reason to eventually refactor this inference function to be part of an instantiated AstroidManager
object instead of having it rely on one global AstroidManager
class (as this makes parallelisation much harder).
Thus, too many optimisations to this don't make sense as the moment I think. It's more about the intent of decoupling nodes from the interaction with nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @jacobtylerwalls about the code smell. Couldn't we put this in the nodes instead of outside the node ? Sometime the deferred creation of the infer function wasn't required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just look at the imports that are needed in this file. If we want to put this in astroid.nodes
we would have to do all of those within the methods. See also my other comment in the main thread.
This design really boils down whether the nodes should know how to infer themselves. I don't think they do as it heavily complicates the structure of the code and so far we haven't found a good way to combine it in one file.
No, this works already because we don't remove the old way of doing inference with this PR. |
Before offering a view on whether this is the right direction, I'd like to understand a bit more of the benefits.
Can you elaborate on this? I'm not sure I see the immediate upside. |
One of the issue (imo) with the current code structure is that the node objects serve two purposes: they 1) encode information about the node, its position, children, parent, etc. and 2) have a lot of methods that interact with them. However, this second category doesn't actually need to be "on" the nodes and gives a lot of issues such as this 1000 line file of method assignments. |
And ast nodes are very well typed so inheriting from ast nodes would be nice. We could use composition inside NodeNG for inference instead of using an external function that check the type of its argument hough. |
The method assignments are definitely lame, but we can solve that in two ways: either your proposal, or just overriding Also, I don't think we should merge either approach to main just yet--I think we should still review and merge incremental PRs, but just merge them to a dedicated branch. With something this disruptive it would be nice to wait to merge to main until the docs are done and we're sure the performance has improved. (In other words, I'd like the chance to have a final go/no-go decision.) |
This doesn't solve the issue that many inference functions use parts of the |
I could help review such as PR. I have tried previously to fix this, but the import dependency were just too sever to define them cleanly on the nodes themselves.
I can understand that, but do think this creates a very high risk of becoming another |
Thank you! Taking a break, but I made some good progress earlier today on this. |
Superseded by #2171 |
Sounds like I prematurely closed this @DanielNoord, sorry π
For me, this was one of the main flaws I felt with this approach. If we reintroduce a dynamic mapping of nodes to inference functions, we've reintroduced the original indirection we were trying to improve on. If it's not dynamic, then it's coded with a match/case or a storm of isinstance checks. |
I think if we hardcode the mapping there is much less indirection. For me the main issue was that the node objects are defined across multiple files and you can't see what methods they have at runtime. |
And then in this case, we lose the static analysis/type checking benefits of the polymorphism approach. See this disable on my branch necessitated from better inference. |
I'm starting to wonder if we're solving two different problems or if we're just coming from two different ideas of what makes better Python design. Or both π !
Would you be able to flesh this out a little more? I'm not sure what you're referring to when you say you can't see what methods they have at runtime. |
Well, I'm in general not a big fan of composition when it involves setting instance attributes. The current base nodes "work" because they "upgrade" (or build upon) the node that they inherit from them and give some more functionality.
Well, by looking at the definition of a node in the current code you can't see they will have a However, I still wonder whether it makes sense to have that much code in the So, I'm not necessarily opposed to your PR as it is definitely an improvement. However, on a higher level I think we should move in another direction and we could start doing so with this issue/fix. |
@jacobtylerwalls gentle ping on this issue as I don't want to lose all the work you put into the other PR (and this discussion). |
Sounds like we need a decision. Should we get more views from others? |
@Pierre-Sassoulas @mbyrnepr2 @cdce8p Do you have an opinion on the matter? |
I think #2171 is the best approach because the implementation would be in the node class where I'd personally expect it to be. |
Nick weighed in in favor of #2171 at pylint-dev/pylint#8735 (comment). |
I mean, Nick would probably also be in favour of an approach where we split inference from the nodes as long as the module isn't so "gnarly". I must confess it's a bit frustrating that I feel that some of my points (e.g., the use of global state and its impact on future multiprocessing improvements, composition with incompatible |
One problem is that we have splintered conversation across a couple of PRs. DaniΓ«l, I'd be glad to open an issue and summarize the discussion we've had so far. I'd like to make sure that all points get a hearing before we take a decision. Will that work well for you? |
(It's possible that for the issues you feel strongly about, I just failed to see clearly their connection with the changesets we're discussing--but that could become clearer for me once we have a side-by-side pros-n-cons table. I'll tag you to collaborate on it when it's ready!) |
I view Regarding the limitation of global states and multiprocessing, I'm not sure I followed well enough because I don't see how the proposed design would affect it ? Could you summarize the main argument in another issue like Jacob suggested ? If there's a limitation with the approach from #2171 we need to take it into account before investing in a refactor, for sure. |
I'm assuming Jacob will make an issue, or am I misunderstanding you here? |
I will when I have time in the next few days! |
Turns out we had an existing issue! See #679 (comment). @DanielNoord I would be very grateful if you would read and respond when you have time, including fleshing out the parts where I didn't want to speak for you or didn't fully understand your argument. (I would like to be able to π !) |
Type of Changes
Description
Perhaps I should have created an issue for this, but:
This is my proposal to remove the import hell from
astroid
and the method assignment we do for theinference.py
file.Instead of calling
node.infer()
we would now just callinfer_object(node)
.This decouples the nodes and their meta-information from the actual
astroid
magic that needs and uses that information. Next steps would be to change calls in theastroid
code base and remove_infer
everywhere.The migration in
pylint
seems rather straightforward as there are not that many calls toinfer()
actually.I haven't made a news fragment as I'd like to do this after we have finalised the internal transition.
Let me know what you think guys!