.. _UseClsInClassmethodRule:

=======================
UseClsInClassmethodRule
=======================

Enforces using ``cls`` as the first argument in a ``@classmethod``.

-------
Message
-------
When using @classmethod, the first argument must be `cls`.

----------------
Has Autofix: Yes
----------------

-------------------
VALID Code Examples
-------------------

# 1:







.. code-block:: python


    class foo:
        # classmethod with cls first arg.
        @classmethod
        def cm(cls, a, b, c):
            pass





# 2:







.. code-block:: python


    class foo:
        # non-classmethod with non-cls first arg.
        def nm(self, a, b, c):
            pass





# 3:







.. code-block:: python


    class foo:
        # staticmethod with non-cls first arg.
        @staticmethod
        def sm(a):
            pass





---------------------
INVALID Code Examples
---------------------

# 1:







.. code-block:: python


    class foo:
        # No args at all.
        @classmethod
        def cm():
            pass





Autofix:

.. code-block:: python

    --- 
    +++ 
    @@ -2,5 +2,5 @@
     class foo:
         # No args at all.
         @classmethod
    -    def cm():
    +    def cm(cls):
             pass

# 2:







.. code-block:: python


    class foo:
        # Single arg + reference.
        @classmethod
        def cm(a):
            return a





Autofix:

.. code-block:: python

    --- 
    +++ 
    @@ -2,5 +2,5 @@
     class foo:
         # Single arg + reference.
         @classmethod
    -    def cm(a):
    -        return a
    +    def cm(cls):
    +        return cls

# 3:







.. code-block:: python


    class foo:
        # Another "cls" exists: do not autofix.
        @classmethod
        def cm(a):
            cls = 2





.. container:: toggle


    # 4:







    .. code-block:: python


        class foo:
            # Multiple args + references.
            @classmethod
            async def cm(a, b):
                b = a
                b = a.__name__





    Autofix:

    .. code-block:: python

        --- 
        +++ 
        @@ -2,6 +2,6 @@
         class foo:
             # Multiple args + references.
             @classmethod
        -    async def cm(a, b):
        -        b = a
        -        b = a.__name__
        +    async def cm(cls, b):
        +        b = cls
        +        b = cls.__name__


    # 5:







    .. code-block:: python


        class foo:
            # Do not replace in nested scopes.
            @classmethod
            async def cm(a, b):
                b = a
                b = lambda _: a.__name__
                def g():
                    return a.__name__

                # Same-named vars in sub-scopes should not be replaced.
                b = [a for a in [1,2,3]]
                def f(a):
                    return a + 1





    Autofix:

    .. code-block:: python

        --- 
        +++ 
        @@ -2,11 +2,11 @@
         class foo:
             # Do not replace in nested scopes.
             @classmethod
        -    async def cm(a, b):
        -        b = a
        -        b = lambda _: a.__name__
        +    async def cm(cls, b):
        +        b = cls
        +        b = lambda _: cls.__name__
                 def g():
        -            return a.__name__
        +            return cls.__name__
 
                 # Same-named vars in sub-scopes should not be replaced.
                 b = [a for a in [1,2,3]]


    # 6:







    .. code-block:: python


        # Do not replace in surrounding scopes.
        a = 1

        class foo:
            a = 2

            def im(a):
                a = a

            @classmethod
            def cm(a):
                a[1] = foo.cm(a=a)





    Autofix:

    .. code-block:: python

        --- 
        +++ 
        @@ -9,5 +9,5 @@
                 a = a
 
             @classmethod
        -    def cm(a):
        -        a[1] = foo.cm(a=a)
        +    def cm(cls):
        +        cls[1] = foo.cm(a=cls)


    # 7:







    .. code-block:: python


        def another_decorator(x): pass

        class foo:
            # Multiple decorators.
            @another_decorator
            @classmethod
            @another_decorator
            async def cm(a, b, c):
                pass





    Autofix:

    .. code-block:: python

        --- 
        +++ 
        @@ -6,5 +6,5 @@
             @another_decorator
             @classmethod
             @another_decorator
        -    async def cm(a, b, c):
        +    async def cm(cls, b, c):
                 pass

