Skip to content

Commit

Permalink
Handle positional-only args in class methods (fixes #157)
Browse files Browse the repository at this point in the history
  • Loading branch information
bryanforbes committed Feb 16, 2021
1 parent 836139b commit 664f92b
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 1 deletion.
2 changes: 1 addition & 1 deletion bugbear.py
Expand Up @@ -459,7 +459,7 @@ def check_for_b902(self, node):
expected_first_args = B902.self
kind = "instance"

args = node.args.args
args = getattr(node.args, "posonlyargs", []) + node.args.args
vararg = node.args.vararg
kwarg = node.args.kwarg
kwonlyargs = node.args.kwonlyargs
Expand Down
102 changes: 102 additions & 0 deletions tests/b902_py38.py
@@ -0,0 +1,102 @@
def not_a_method(arg1, /):
...


class NoWarnings:
def __init__(self, /):
def not_a_method_either(arg1, /):
...

def __new__(cls, /, *args, **kwargs):
...

def method(self, arg1, /, *, yeah):
...

async def async_method(self, arg1, /, *, yeah):
...

@classmethod
def someclassmethod(cls, arg1, with_default=None, /):
...

@staticmethod
def not_a_problem(arg1, /):
...


class Warnings:
def __init__(i_am_special, /):
...

def almost_a_class_method(cls, arg1, /):
...

def almost_a_static_method():
...

@classmethod
def wat(self, i_like_confusing_people, /):
...

def i_am_strange(*args, **kwargs):
self = args[0]

def defaults_anyone(self=None, /):
...

def invalid_kwargs_only(**kwargs):
...

def invalid_keyword_only(*, self):
...

async def async_invalid_keyword_only(*, self):
...


class Meta(type):
def __init__(cls, name, bases, d, /):
...

@classmethod
def __prepare__(metacls, name, bases, /):
return {}


class OtherMeta(type):
def __init__(self, name, bases, d, /):
...

@classmethod
def __prepare__(cls, name, bases, /):
return {}

@classmethod
def first_arg_mcs_allowed(mcs, value, /):
...


def type_factory():
return object


class CrazyBases(Warnings, type_factory(), metaclass=type):
def __init__(self):
...


class RuntimeError("This is not a base"):
def __init__(self):
...


class ImplicitClassMethods:
def __new__(cls, /, *args, **kwargs):
...

def __init_subclass__(cls, /, *args, **kwargs):
...

def __class_getitem__(cls, key, /):
...
22 changes: 22 additions & 0 deletions tests/test_bugbear.py
Expand Up @@ -3,6 +3,7 @@
from pathlib import Path
import site
import subprocess
import sys
import unittest

from hypothesis import HealthCheck, given, settings
Expand Down Expand Up @@ -260,6 +261,27 @@ def test_b902(self):
),
)

@unittest.skipIf(sys.version_info < (3, 8), "requires 3.8+")
def test_b902_py38(self):
filename = Path(__file__).absolute().parent / "b902_py38.py"
bbc = BugBearChecker(filename=str(filename))
errors = list(bbc.run())
self.assertEqual(
errors,
self.errors(
B902(29, 17, vars=("'i_am_special'", "instance", "self")),
B902(32, 30, vars=("'cls'", "instance", "self")),
B902(35, 4, vars=("(none)", "instance", "self")),
B902(39, 12, vars=("'self'", "class", "cls")),
B902(42, 22, vars=("*args", "instance", "self")),
B902(48, 30, vars=("**kwargs", "instance", "self")),
B902(51, 32, vars=("*, self", "instance", "self")),
B902(54, 44, vars=("*, self", "instance", "self")),
B902(68, 17, vars=("'self'", "metaclass instance", "cls")),
B902(72, 20, vars=("'cls'", "metaclass class", "metacls")),
),
)

def test_b903(self):
filename = Path(__file__).absolute().parent / "b903.py"
bbc = BugBearChecker(filename=str(filename))
Expand Down

0 comments on commit 664f92b

Please sign in to comment.