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

Add Django 1.10+ request.user attribute fixer #423

Merged
merged 18 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Changelog
=========

* Add Django 1.10+ fixer to rewrite ``request.user`` functions that changed to boolean attributes: ``is_authenticated`` and ``is_anonymous``.

Thanks to Alessandro Ferrini in `PR #423 <https://github.com/adamchainz/django-upgrade/pull/423>`__.

1.15.0 (2023-09-24)
-------------------

Expand Down
14 changes: 13 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,19 @@ Django 1.10

`Release Notes <https://docs.djangoproject.com/en/1.10/releases/1.10/>`__

``request.user`` boolean attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Rewrites calls to ``request.user.is_authenticated()`` and ``request.user.is_anonymous()`` to remove the parentheses, per `the deprecation <https://docs.djangoproject.com/en/1.10/releases/1.10/#using-user-is-authenticated-and-user-is-anonymous-as-methods>`__.

.. code-block:: diff

-request.user.is_authenticated()
+request.user.is_authenticated

-self.request.user.is_anonymous()
+self.request.user.is_anonymous

Compatibility imports
~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -321,7 +334,6 @@ Whilst mentioned in the `Django 2.1 release notes <https://docs.djangoproject.co
-from django.contrib.staticfiles.templatetags.staticfiles import static
+from django.templatetags.static import static


Django 1.11
-----------

Expand Down
67 changes: 67 additions & 0 deletions src/django_upgrade/fixers/request_user_attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Update use of request.user.is_authenticated() to use request.user.is_authenticated
https://docs.djangoproject.com/en/1.10/releases/1.10/#using-user-is-authenticated-and-user-is-anonymous-as-methods
"""

from __future__ import annotations

import ast
from functools import partial
from typing import Iterable

from tokenize_rt import Offset
from tokenize_rt import Token

from django_upgrade.ast import ast_start_offset
from django_upgrade.data import Fixer
from django_upgrade.data import State
from django_upgrade.data import TokenFunc
from django_upgrade.tokens import NAME
from django_upgrade.tokens import OP
from django_upgrade.tokens import find

fixer = Fixer(
__name__,
min_version=(1, 10),
)


@fixer.register(ast.Call)
def visit_Call(
state: State,
node: ast.Call,
parents: list[ast.AST],
) -> Iterable[tuple[Offset, TokenFunc]]:
if (
isinstance(node.func, ast.Attribute)
and node.func.attr in ("is_anonymous", "is_authenticated")
and is_request_or_self_request_user(node.func.value)
and len(node.args) == 0
):
yield (
ast_start_offset(node),
partial(rewrite_user_attribute, attr=node.func.attr),
)


def is_request_or_self_request_user(node: ast.AST) -> bool:
return (
isinstance(node, ast.Attribute)
and node.attr == "user"
and (
(isinstance(node.value, ast.Name) and node.value.id == "request")
or (
isinstance(node.value, ast.Attribute)
and isinstance(node.value.value, ast.Name)
and node.value.value.id == "self"
and node.value.attr == "request"
)
)
)


def rewrite_user_attribute(tokens: list[Token], i: int, *, attr: str) -> None:
j = find(tokens, i, name=NAME, src=attr)
y = find(tokens, j, name=OP, src="(")
z = find(tokens, y, name=OP, src=")")
del tokens[y : z + 1]
213 changes: 213 additions & 0 deletions tests/fixers/test_request_user_attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
from __future__ import annotations

from django_upgrade.data import Settings
from tests.fixers.tools import check_noop
from tests.fixers.tools import check_transformed

settings = Settings(target_version=(1, 10))


def test_not_request():
check_noop(
"""\
user.is_authenticated()
""",
settings,
)


def test_not_self_request():
check_noop(
"""\
self.user.is_authenticated()
""",
settings,
)


def test_not_user():
check_noop(
"""\
request.is_authenticated()
""",
settings,
)


def test_not_self_user():
check_noop(
"""\
self.request.is_authenticated()
""",
settings,
)


def test_request_user_is_anonymous_simple():
check_transformed(
"""\
request.user.is_anonymous()
""",
"""\
request.user.is_anonymous
""",
settings,
)


def test_request_user_is_authenticated_simple():
check_transformed(
"""\
request.user.is_authenticated()
""",
"""\
request.user.is_authenticated
""",
settings,
)


def test_self_request_user_is_anonymous_simple():
check_transformed(
"""\
self.request.user.is_anonymous()
""",
"""\
self.request.user.is_anonymous
""",
settings,
)


def test_self_request_user_is_authenticated_simple():
check_transformed(
"""\
self.request.user.is_authenticated()
""",
"""\
self.request.user.is_authenticated
""",
settings,
)


def test_if_request_user_is_anonymous():
check_transformed(
"""\
if request.user.is_anonymous():
...
""",
"""\
if request.user.is_anonymous:
...
""",
settings,
)


def test_if_request_user_is_authenticated():
check_transformed(
"""\
if request.user.is_authenticated():
...
""",
"""\
if request.user.is_authenticated:
...
""",
settings,
)


def test_if_self_request_user_is_anonymous():
check_transformed(
"""\
if self.request.user.is_anonymous():
...
""",
"""\
if self.request.user.is_anonymous:
...
""",
settings,
)


def test_if_self_request_user_is_authenticated():
check_transformed(
"""\
if self.request.user.is_authenticated():
...
""",
"""\
if self.request.user.is_authenticated:
...
""",
settings,
)


def test_spaces_between_noop():
check_noop(
"request . user . is_authenticated ",
settings,
)


def test_spaces_between():
check_transformed(
"request . user . is_authenticated ( )",
"request . user . is_authenticated ",
settings,
)


def test_comment_between():
check_transformed(
"""\
request.user.is_anonymous( # something
)
""",
"""\
request.user.is_anonymous
""",
settings,
)


def test_spaces_and_comments_noop():
check_noop(
"""\
if (
request
.user
.is_authenticated # bla
):
...
""",
settings,
)


def test_spaces_and_comments():
check_transformed(
"""\
if (
request
.user
.is_authenticated # bla
() # bla
):
...
""",
"""\
if (
request
.user
.is_authenticated # bla
# bla
):
...
""",
settings,
)
Loading