mirror of https://github.com/zulip/zulip.git
python: Clean up getattr, setattr, delattr calls with literal names.
These were useful as a transitional workaround to ignore type errors that only show up with django-stubs, while avoiding errors about unused type: ignore comments without django-stubs. Now that the django-stubs transition is complete, switch to type: ignore comments so that mypy will tell us if they become unnecessary. Many already have. Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
5e1ebf2861
commit
1385a827c2
|
@ -368,7 +368,7 @@ def webhook_view(
|
|||
|
||||
# Store the event types registered for this webhook as an attribute, which can be access
|
||||
# later conveniently in zerver.lib.test_classes.WebhookTestCase.
|
||||
setattr(_wrapped_func_arguments, "_all_event_types", all_event_types)
|
||||
_wrapped_func_arguments._all_event_types = all_event_types # type: ignore[attr-defined] # custom attribute
|
||||
return _wrapped_func_arguments
|
||||
|
||||
return _wrapped_view_func
|
||||
|
@ -793,7 +793,7 @@ def process_as_post(
|
|||
if not request.POST:
|
||||
# Only take action if POST is empty.
|
||||
if request.content_type == "multipart/form-data":
|
||||
POST, _files = MultiPartParser(
|
||||
POST, files = MultiPartParser(
|
||||
request.META,
|
||||
BytesIO(request.body),
|
||||
request.upload_handlers,
|
||||
|
@ -809,10 +809,7 @@ def process_as_post(
|
|||
# See also: https://github.com/typeddjango/django-stubs/pull/925#issue-1206399444
|
||||
POST._mutable = False
|
||||
request.POST = cast("_ImmutableQueryDict", POST)
|
||||
# Note that request._files is just the private attribute that backs the
|
||||
# FILES property, so we are essentially setting request.FILES here. (In
|
||||
# Django 3.2 FILES was still a read-only property.)
|
||||
setattr(request, "_files", _files)
|
||||
request.FILES.update(files)
|
||||
elif request.content_type == "application/x-www-form-urlencoded":
|
||||
request.POST = QueryDict(request.body, encoding=request.encoding)
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ def copy_default_settings(
|
|||
target_profile.save()
|
||||
return
|
||||
|
||||
setattr(target_profile, "full_name", settings_source.full_name)
|
||||
setattr(target_profile, "timezone", canonicalize_timezone(settings_source.timezone))
|
||||
target_profile.full_name = settings_source.full_name
|
||||
target_profile.timezone = canonicalize_timezone(settings_source.timezone)
|
||||
target_profile.save()
|
||||
|
||||
if settings_source.avatar_source == UserProfile.AVATAR_FROM_USER:
|
||||
|
|
|
@ -892,7 +892,7 @@ def import_uploads(
|
|||
process_avatars(record)
|
||||
else:
|
||||
connection.close()
|
||||
_cache = getattr(cache, "_cache")
|
||||
_cache = cache._cache # type: ignore[attr-defined] # not in stubs
|
||||
assert isinstance(_cache, bmemcached.Client)
|
||||
_cache.disconnect_all()
|
||||
with ProcessPoolExecutor(max_workers=processes) as executor:
|
||||
|
|
|
@ -197,12 +197,10 @@ class ZulipFormatter(logging.Formatter):
|
|||
return " ".join(pieces)
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
if not getattr(record, "zulip_decorated", False):
|
||||
# The `setattr` calls put this logic explicitly outside the bounds of the
|
||||
# type system; otherwise mypy would complain LogRecord lacks these attributes.
|
||||
setattr(record, "zulip_level_abbrev", abbrev_log_levelname(record.levelname))
|
||||
setattr(record, "zulip_origin", find_log_origin(record))
|
||||
setattr(record, "zulip_decorated", True)
|
||||
if not hasattr(record, "zulip_decorated"):
|
||||
record.zulip_level_abbrev = abbrev_log_levelname(record.levelname)
|
||||
record.zulip_origin = find_log_origin(record)
|
||||
record.zulip_decorated = True
|
||||
return super().format(record)
|
||||
|
||||
|
||||
|
@ -227,12 +225,12 @@ class ZulipWebhookFormatter(ZulipFormatter):
|
|||
|
||||
request = get_current_request()
|
||||
if not request:
|
||||
setattr(record, "user", None)
|
||||
setattr(record, "client", None)
|
||||
setattr(record, "url", None)
|
||||
setattr(record, "content_type", None)
|
||||
setattr(record, "custom_headers", None)
|
||||
setattr(record, "payload", None)
|
||||
record.user = None
|
||||
record.client = None
|
||||
record.url = None
|
||||
record.content_type = None
|
||||
record.custom_headers = None
|
||||
record.payload = None
|
||||
return super().format(record)
|
||||
|
||||
if request.content_type == "application/json":
|
||||
|
@ -257,12 +255,12 @@ class ZulipWebhookFormatter(ZulipFormatter):
|
|||
assert client is not None
|
||||
|
||||
assert request.user.is_authenticated
|
||||
setattr(record, "user", f"{request.user.delivery_email} ({request.user.realm.string_id})")
|
||||
setattr(record, "client", client.name)
|
||||
setattr(record, "url", request.META.get("PATH_INFO", None))
|
||||
setattr(record, "content_type", request.content_type)
|
||||
setattr(record, "custom_headers", header_text or None)
|
||||
setattr(record, "payload", payload)
|
||||
record.user = f"{request.user.delivery_email} ({request.user.realm.string_id})"
|
||||
record.client = client.name
|
||||
record.url = request.META.get("PATH_INFO", None)
|
||||
record.content_type = request.content_type
|
||||
record.custom_headers = header_text or None
|
||||
record.payload = payload
|
||||
return super().format(record)
|
||||
|
||||
|
||||
|
|
|
@ -474,9 +474,9 @@ def get_current_request() -> Optional[HttpRequest]:
|
|||
|
||||
|
||||
def set_request(req: HttpRequest) -> None:
|
||||
setattr(local, "request", req)
|
||||
local.request = req
|
||||
|
||||
|
||||
def unset_request() -> None:
|
||||
if hasattr(local, "request"):
|
||||
delattr(local, "request")
|
||||
del local.request
|
||||
|
|
|
@ -394,7 +394,7 @@ def instrument_url(f: UrlFuncT) -> UrlFuncT:
|
|||
info = "<bytes>"
|
||||
elif isinstance(info, dict):
|
||||
info = {
|
||||
k: "<file object>" if hasattr(v, "read") and callable(getattr(v, "read")) else v
|
||||
k: "<file object>" if hasattr(v, "read") and callable(v.read) else v
|
||||
for k, v in info.items()
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ def transfer_avatars_to_s3(processes: int) -> None:
|
|||
_transfer_avatar_to_s3(user)
|
||||
else: # nocoverage
|
||||
connection.close()
|
||||
_cache = getattr(cache, "_cache")
|
||||
_cache = cache._cache # type: ignore[attr-defined] # not in stubs
|
||||
assert isinstance(_cache, bmemcached.Client)
|
||||
_cache.disconnect_all()
|
||||
with ProcessPoolExecutor(max_workers=processes) as executor:
|
||||
|
@ -76,7 +76,7 @@ def transfer_message_files_to_s3(processes: int) -> None:
|
|||
_transfer_message_files_to_s3(attachment)
|
||||
else: # nocoverage
|
||||
connection.close()
|
||||
_cache = getattr(cache, "_cache")
|
||||
_cache = cache._cache # type: ignore[attr-defined] # not in stubs
|
||||
assert isinstance(_cache, bmemcached.Client)
|
||||
_cache.disconnect_all()
|
||||
with ProcessPoolExecutor(max_workers=processes) as executor:
|
||||
|
@ -111,7 +111,7 @@ def transfer_emoji_to_s3(processes: int) -> None:
|
|||
_transfer_emoji_to_s3(realm_emoji)
|
||||
else: # nocoverage
|
||||
connection.close()
|
||||
_cache = getattr(cache, "_cache")
|
||||
_cache = cache._cache # type: ignore[attr-defined] # not in stubs
|
||||
assert isinstance(_cache, bmemcached.Client)
|
||||
_cache.disconnect_all()
|
||||
with ProcessPoolExecutor(max_workers=processes) as executor:
|
||||
|
|
|
@ -192,7 +192,7 @@ def get_fixture_http_headers(integration_name: str, fixture_name: str) -> Dict["
|
|||
# TODO: We may want to migrate to a more explicit registration
|
||||
# strategy for this behavior rather than a try/except import.
|
||||
view_module = importlib.import_module(view_module_name)
|
||||
fixture_to_headers = getattr(view_module, "fixture_to_headers")
|
||||
fixture_to_headers = view_module.fixture_to_headers
|
||||
except (ImportError, AttributeError):
|
||||
return {}
|
||||
return fixture_to_headers(fixture_name)
|
||||
|
|
|
@ -228,9 +228,8 @@ class Command(makemessages.Command):
|
|||
process_all = self.frontend_all
|
||||
|
||||
# After calling super().handle(), default_locale_path gets set on self
|
||||
# so that we can reuse it here. We have to use getattr it to access it without
|
||||
# getting an attribute error from mypy.
|
||||
default_locale_path = getattr(self, "default_locale_path")
|
||||
# so that we can reuse it here.
|
||||
default_locale_path = self.default_locale_path # type: ignore[attr-defined] # not in stubs
|
||||
paths = glob.glob(f"{default_locale_path}/*")
|
||||
all_locales = [os.path.basename(path) for path in paths if os.path.isdir(path)]
|
||||
|
||||
|
|
|
@ -774,7 +774,7 @@ class ZulipSCIMAuthCheckMiddleware(SCIMAuthCheckMiddleware):
|
|||
# so we can assign the corresponding SCIMClient object to request.user - which
|
||||
# will allow this request to pass request.user.is_authenticated checks from now on,
|
||||
# to be served by the relevant views implemented in django-scim2.
|
||||
# Since request.user must be a UserProfile or AnonymousUser, setattr is a type-unsafe
|
||||
# Since request.user must be a UserProfile or AnonymousUser, this is a type-unsafe
|
||||
# workaround to make this monkey-patching work.
|
||||
setattr(request, "user", scim_client)
|
||||
request.user = scim_client # type: ignore[assignment] # wrong type
|
||||
return None
|
||||
|
|
|
@ -3245,22 +3245,20 @@ class AbstractUserMessage(models.Model):
|
|||
|
||||
@staticmethod
|
||||
def where_unread() -> str:
|
||||
return AbstractUserMessage.where_flag_is_absent(getattr(AbstractUserMessage.flags, "read"))
|
||||
return AbstractUserMessage.where_flag_is_absent(AbstractUserMessage.flags.read)
|
||||
|
||||
@staticmethod
|
||||
def where_read() -> str:
|
||||
return AbstractUserMessage.where_flag_is_present(getattr(AbstractUserMessage.flags, "read"))
|
||||
return AbstractUserMessage.where_flag_is_present(AbstractUserMessage.flags.read)
|
||||
|
||||
@staticmethod
|
||||
def where_starred() -> str:
|
||||
return AbstractUserMessage.where_flag_is_present(
|
||||
getattr(AbstractUserMessage.flags, "starred")
|
||||
)
|
||||
return AbstractUserMessage.where_flag_is_present(AbstractUserMessage.flags.starred)
|
||||
|
||||
@staticmethod
|
||||
def where_active_push_notification() -> str:
|
||||
return AbstractUserMessage.where_flag_is_present(
|
||||
getattr(AbstractUserMessage.flags, "active_mobile_push_notification")
|
||||
AbstractUserMessage.flags.active_mobile_push_notification
|
||||
)
|
||||
|
||||
def flags_list(self) -> List[str]:
|
||||
|
|
|
@ -542,7 +542,7 @@ class PreviewTestCase(ZulipTestCase):
|
|||
self.assertEqual(msg.rendered_content, with_preview)
|
||||
|
||||
realm = msg.get_realm()
|
||||
setattr(realm, "inline_url_embed_preview", False)
|
||||
realm.inline_url_embed_preview = False
|
||||
realm.save()
|
||||
|
||||
msg = self._send_message_with_test_org_url(
|
||||
|
|
|
@ -240,7 +240,7 @@ class AdminNotifyHandlerTest(ZulipTestCase):
|
|||
self.assertEqual(report["stack_trace"], "No stack trace available")
|
||||
|
||||
# Test arbitrary exceptions from request.user
|
||||
delattr(record.request, "user")
|
||||
del record.request.user
|
||||
with patch("zerver.logging_handlers.traceback.print_exc"):
|
||||
report = self.run_handler(record)
|
||||
self.assertIn("host", report)
|
||||
|
|
|
@ -623,7 +623,7 @@ class MarkdownTest(ZulipTestCase):
|
|||
self.assertEqual(converted.rendered_content, with_preview)
|
||||
|
||||
realm = msg.get_realm()
|
||||
setattr(realm, "inline_image_preview", False)
|
||||
realm.inline_image_preview = False
|
||||
realm.save()
|
||||
|
||||
sender_user_profile = self.example_user("othello")
|
||||
|
|
|
@ -422,8 +422,8 @@ do not match the types declared in the implementation of {function.__name__}.\n"
|
|||
# Iterate through the decorators to find the original
|
||||
# function, wrapped by has_request_variables, so we can parse
|
||||
# its arguments.
|
||||
while hasattr(function, "__wrapped__"):
|
||||
function = getattr(function, "__wrapped__")
|
||||
while (wrapped := getattr(function, "__wrapped__", None)) is not None:
|
||||
function = wrapped
|
||||
|
||||
# Now, we do inference mapping each REQ parameter's
|
||||
# declaration details to the Python/mypy types for the
|
||||
|
|
|
@ -12,7 +12,8 @@ from django.contrib.auth.views import PasswordResetConfirmView
|
|||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.mail.message import EmailMultiAlternatives
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseBase
|
||||
from django.template.response import TemplateResponse
|
||||
from django.test import Client, override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils import translation
|
||||
|
@ -198,7 +199,7 @@ class DeactivationNoticeTestCase(ZulipTestCase):
|
|||
realm.save(update_fields=["deactivated"])
|
||||
|
||||
result = self.client_get("/login/", follow=True)
|
||||
self.assertEqual(getattr(result, "redirect_chain")[-1], ("/accounts/deactivated/", 302))
|
||||
self.assertEqual(result.redirect_chain[-1], ("/accounts/deactivated/", 302))
|
||||
self.assertIn("Zulip Dev, has been deactivated.", result.content.decode())
|
||||
self.assertNotIn("It has moved to", result.content.decode())
|
||||
|
||||
|
@ -1080,10 +1081,12 @@ class LoginTest(ZulipTestCase):
|
|||
description = "https://www.google.com/images/srpr/logo4w.png"
|
||||
realm.description = description
|
||||
realm.save(update_fields=["description"])
|
||||
response = self.client_get("/login/")
|
||||
response: HttpResponseBase = self.client_get("/login/")
|
||||
expected_response = """<p><a href="https://www.google.com/images/srpr/logo4w.png">\
|
||||
https://www.google.com/images/srpr/logo4w.png</a></p>"""
|
||||
self.assertEqual(getattr(response, "context_data")["realm_description"], expected_response)
|
||||
assert isinstance(response, TemplateResponse)
|
||||
assert response.context_data is not None
|
||||
self.assertEqual(response.context_data["realm_description"], expected_response)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,6 @@ class Command(BaseCommand):
|
|||
def handle(self, *args: Any, **options: Any) -> None:
|
||||
assert settings.DEVELOPMENT
|
||||
UserMessage.objects.all().update(flags=F("flags").bitand(~UserMessage.flags.read))
|
||||
_cache = getattr(cache, "_cache")
|
||||
_cache = cache._cache # type: ignore[attr-defined] # not in stubs
|
||||
assert isinstance(_cache, bmemcached.Client)
|
||||
_cache.flush_all()
|
||||
|
|
Loading…
Reference in New Issue