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

PEP 702 (@deprecated): consider all possible type positions #17926

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

tyralla
Copy link
Contributor

@tyralla tyralla commented Oct 11, 2024

This pull request generalises #17899.

Initially, it started with extending #17899 to function signatures only, as can be seen from the following initial comments and the subsequent discussions.


@ilevkivskyi

This is part two of the checker.py chase.

I had to extend InstanceDeprecatedVisitor so that it refrains from reporting that self in the signature of a deprecated class' method refers to this deprecated class. This seems to suggest that a strictly uniform handling for all possible type positions might not be possible. Do you think the same?

However, searching for more central locations to apply InstanceDeprecatedVisitor is certainly a good idea. I can try it in this or the next PR, as you prefer.

This comment has been minimized.

@tyralla
Copy link
Contributor Author

tyralla commented Oct 11, 2024

On second thought: InstanceDeprecatedVisitor already knows the necessary context to solve this problem without external help.

    def visit_instance(self, t: Instance) -> None:
        super().visit_instance(t)
        if not (
            isinstance(defn := self.context, FuncDef)
            and defn.info and
            (t.type.fullname == defn.info.fullname)
        ):
            self.typechecker.check_deprecated(t.type, self.context)

@tyralla
Copy link
Contributor Author

tyralla commented Oct 12, 2024

After a bit of experimenting, I think extending TypeArgumentAnalyzer a little could be the way to go. I would try it if you agree.

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

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

Generally looks good to me. But, maybe we should simplify this to ignore_self? And just ignore first args in class / instance methods?

@ilevkivskyi
Copy link
Member

I think the whole visitor should be replaced with a single check in analyze_type_with_type_info() in typeanal.py: simply check if TypeInfo is deprecated and it will cover all cases at once. Conveniently, the current class is available there as self.api.type, so it is very easy to skip self types.

Another thought is that we need to update the TypeInfo branch in snapshot_definition() in astdiff.py and add fine grained test case(s) for deprecating classes.

@tyralla Could you please re-purpose this PR for the above two things?

@ilevkivskyi
Copy link
Member

Note btw what I say above may require moving around some existing code for emitting error messages, since you can't import checker.py in typeanal.py.

@tyralla
Copy link
Contributor Author

tyralla commented Oct 16, 2024

Generally looks good to me. But, maybe we should simplify this to ignore_self? And just ignore first args in class / instance methods?

Thanks for the review, @sobolevn. Could you explain why you suggest simplifying? I see now that a reference to the relevant class (TypeInfo) always seems to be available somehow. Or do you expect other problems with my approach?

I think the whole visitor should be replaced with a single check in analyze_type_with_type_info() in typeanal.py: simply check if TypeInfo is deprecated and it will cover all cases at once. Conveniently, the current class is available there as self.api.type, so it is very easy to skip self types.

And thanks for the suggestion, @ilevkivskyi. analyze_type_with_type_info seems, in fact, convenient for doing the discussed checks, with one exception perhaps. self.api is of type SemanticAnalyzerCoreInterface. If it is SementicAnalyzer during runtime, I can use the cur_mod_node attribute to determine how the class has been imported (via MypyFile.imports). Narrowing self.api to SementicAnalyzer via isinstance does not work right away because importing SementicAnalyzer at the module header causes import cycle problems. Is importing SementicAnalyzer locally (within analyze_type_with_type_info) or extending SemanticAnalyzerCoreInterface okay? Or do you see a better way to determine if and how a class has been imported?

@tyralla
Copy link
Contributor Author

tyralla commented Oct 16, 2024

Or do you see a better way to determine if and how a class has been imported?

Or a function, of course.

This comment has been minimized.

@tyralla
Copy link
Contributor Author

tyralla commented Oct 17, 2024

As an alternative suggestion, I generalised InstanceDeprecatedVisitor.

The Mypy diff for tanjun is correct. BasicContext is in fact deprecated.

I did not investigate why the deprecation warnings were raised when executing the Python evaluation suite.

Whether we proceed this way or via extending analyze_type_with_type_info, we still need to add more test cases.

This comment has been minimized.

@tyralla
Copy link
Contributor Author

tyralla commented Oct 18, 2024

Another thought is that we need to update the TypeInfo branch in snapshot_definition() in astdiff.py and add fine grained test case(s) for deprecating classes.

I did so. There is a problem for:

import b
y: b.D

This comment has been minimized.

This comment has been minimized.

@tyralla
Copy link
Contributor Author

tyralla commented Oct 20, 2024

I could fix the y: b.D problem and split the fine-grained dependency tests for the cache and the nocache options where necessary.

I will add more tests to check-deprecated tomorrow.

Regarding the Python evaluation suite, I am stuck. Adding type: ignore[deprecated] to these lines helps as expected, but what is the right way to proceed? (@ilevkivskyi and @sobolevn)

@tyralla tyralla changed the title PEP 702 (@deprecated): consider type hints in function signatures PEP 702 (@deprecated): consider all possible type positions Oct 21, 2024
@tyralla
Copy link
Contributor Author

tyralla commented Oct 21, 2024

I filed a PR to typeshed, added a few more tests (all passed without further effort), and renamed this PR. So, if the InstanceDeprecatedVisitor approach is okay, this should be ready, in my opinion.

@tyralla tyralla requested a review from sobolevn October 21, 2024 08:41
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

Tanjun (https://github.com/FasterSpeeding/Tanjun)
+ tanjun/context/base.py:48: note: class alluka._context.BasicContext is deprecated: Use Context or CachingContext  [deprecated]
+ tanjun/context/autocomplete.py:54: note: class alluka._context.BasicContext is deprecated: Use Context or CachingContext  [deprecated]

core (https://github.com/home-assistant/core)
+ homeassistant/runner.py:84: note: class asyncio.unix_events.AbstractChildWatcher is deprecated: Deprecated as of Python 3.12; will be removed in Python 3.14  [deprecated]

@JelleZijlstra JelleZijlstra added the topic-pep-702 PEP 702, @deprecated label Oct 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-pep-702 PEP 702, @deprecated
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants