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

[flake8-pyi] Implement PYI063 #11699

Merged
merged 6 commits into from
Jun 4, 2024
Merged

Conversation

tusharsadhwani
Copy link
Contributor

Summary

Implements Y063 from flake8-pyi.

Test Plan

cargo test / cargo insta review

let semantic = checker.semantic();
// TODO: this scope is wrong.
let scope = semantic.current_scope();
let function_type = function_type::classify(
Copy link
Contributor Author

@tusharsadhwani tusharsadhwani Jun 2, 2024

Choose a reason for hiding this comment

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

This call currently doesn't correctly identify methods, which is why the issue is not correctly raised on line 26 of PYI063.pyi. I suspect it is because scope is not correct.

I didn't look super hard into it, but I don't see a very straightforward way to get the correct scope from a FunctionStmt node.

Copy link
Member

Choose a reason for hiding this comment

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

I fixed this by moving it out of the definition phase and into the standard statement checker.

Copy link
Contributor

github-actions bot commented Jun 2, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+23 -0 violations, +0 -0 fixes in 4 projects; 46 projects unchanged)

apache/airflow (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview --select ALL

+ airflow/utils/hashlib_wrapper.py:28:9: PYI063 Use PEP 570 syntax for positional-only arguments

pandas-dev/pandas (+3 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ pandas/_typing.py:282:20: PYI063 Use PEP 570 syntax for positional-only arguments
+ pandas/_typing.py:297:20: PYI063 Use PEP 570 syntax for positional-only arguments
+ pandas/_typing.py:303:21: PYI063 Use PEP 570 syntax for positional-only arguments

python-trio/trio (+18 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ src/trio/_socket.py:1072:26: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:1102:21: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:1133:25: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:1151:17: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:1166:26: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:1178:15: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:1183:15: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:1212:13: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:652:22: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:662:17: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:678:13: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:690:13: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:696:22: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:701:15: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:707:9: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/_socket.py:722:13: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/testing/_fake_net.py:469:15: PYI063 Use PEP 570 syntax for positional-only arguments
+ src/trio/testing/_fake_net.py:475:9: PYI063 Use PEP 570 syntax for positional-only arguments

pytest-dev/pytest (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ testing/example_scripts/dataclasses/test_compare_dataclasses_with_custom_eq.py:11:26: PYI063 Use PEP 570 syntax for positional-only arguments

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
PYI063 23 23 0 0 0

@charliermarsh charliermarsh self-assigned this Jun 3, 2024
@charliermarsh charliermarsh added rule Implementing or modifying a lint rule preview Related to preview mode features labels Jun 3, 2024
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Nice! The code here looks really clean. Charlie's assigned this to himself so I'll leave a full review to him, but two quick points:

Comment on lines 153 to 155
if checker.enabled(Rule::OldStylePositionalOnlyArg) {
flake8_pyi::rules::old_style_positional_only_arg(checker, definition);
}
Copy link
Member

Choose a reason for hiding this comment

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

We should make sure only to run this rule if the target version is set to Python 3.8 or greater (Ruff still supports Python 3.7), or we'll be recommending invalid syntax for Python 3.7 users

Copy link
Member

Choose a reason for hiding this comment

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

Any reason not to do this for .py files as well? I think type checkers understand the pre-PEP-570 convention for runtime source code as well as stubs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For regular python files, code like:

def add(__a, __b):
    return __a + __b

It's not necessary that the user intended to make them positional only. Whereas in stub files it is intended. Raising it on python files can cause false positives.

Copy link
Member

Choose a reason for hiding this comment

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

Although you certainly can do calls such as add(__a=1, __b=2), in my opinion, I think the vast majority of Python functions with parameters like that have probably been written to take advantage of the type-checker convention to understand those parameters as being positional-only. But let's see what Charlie thinks!

Copy link
Member

Choose a reason for hiding this comment

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

I ended up enabling this based on Alex's suggestion.

def okay(__x__: int) -> None: ...
# The first argument isn't positional-only, so logically the second can't be either:
def also_okay(x: int, __y: str) -> None: ...
def fine(x: bytes, /) -> None: ...
Copy link
Contributor

Choose a reason for hiding this comment

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

Can I suggest the test case

def still_fine(_x: int) -> None: ...

This should be fine right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

seems good, I'll add it.

if is_old_style_positional_only_arg(second_arg) {
checker.diagnostics.push(Diagnostic::new(
OldStylePositionalOnlyArg,
second_arg.range(),
Copy link
Member

Choose a reason for hiding this comment

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

Why is the check limited to the first two arguments?

Copy link
Member

Choose a reason for hiding this comment

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

Ah I see, ok.

Copy link
Member

@charliermarsh charliermarsh left a comment

Choose a reason for hiding this comment

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

Thanks!

@charliermarsh charliermarsh enabled auto-merge (squash) June 4, 2024 02:51
@charliermarsh charliermarsh merged commit e1133a2 into astral-sh:main Jun 4, 2024
17 checks passed
carljm added a commit that referenced this pull request Jun 4, 2024
* main:
  [`flake8-pyi`] Implement `PYI063` (#11699)
  Fix `red-knot` compilation (#11727)
@tusharsadhwani tusharsadhwani deleted the pyi-063 branch June 5, 2024 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
preview Related to preview mode features rule Implementing or modifying a lint rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants