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

django-stubs: Fix HttpResponse missing attribute error. #22185

Merged
merged 1 commit into from
Jun 7, 2022

Conversation

PIG208
Copy link
Member

@PIG208 PIG208 commented Jun 3, 2022

This is a part of #18777.

As Django monkey patch attributes on the HttpResponse the test client returns. This does not really make the patched attributes available on the response object of the test client, but instead avoids accessing these attributes by taking a detour.

It refactors away response.json() with response.assert_json_success and a new helper response.assert_json_error_data manually and with regexes.

A flag use_zulip_api_format is added for response.assert_json_error_data to properly test test_scim.py.

Self-review checklist

  • Self-reviewed the changes for clarity and maintainability
    (variable names, code reuse, readability, etc.).

Communicate decisions, questions, and potential concerns.

  • Explains differences from previous plans (e.g., issue description).
  • Highlights technical choices and bugs encountered.
  • Calls out remaining decisions and concerns.
  • Automated tests verify logic where appropriate.

Individual commits are ready for review (see commit discipline).

  • Each commit is a coherent idea.
  • Commit message(s) explain reasoning and motivation for changes.

Completed manual review and testing of the following:

  • Visual appearance of the changes.
  • Responsiveness and internationalization.
  • Strings and tooltips.
  • End-to-end functionality of buttons, interactions and flows.
  • Corner cases, error conditions, and easily imagined bugs.

@PIG208 PIG208 force-pushed the HttpResponse-missing-attributes branch 2 times, most recently from 98f0b6f to 53f97e0 Compare June 3, 2022 16:19
@PIG208 PIG208 mentioned this pull request Jun 3, 2022
52 tasks
@andersk
Copy link
Member

andersk commented Jun 3, 2022

The use_zulip_error_format flag is not worth its complexity. The five tests that set it to False would be simpler and more readable without it.

-        response_dict = self.assert_json_error_data(result, use_zulip_error_format=False)
+        self.assertEqual(result.status_code, 400)
         self.assertEqual(
-            response_dict,
+            orjson.loads(result.content),
             {
                 "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
                 "detail": "Must specify name.formatted, name.givenName or name.familyName when creating a new user",
                 "status": 400,
             },
         )

@@ -695,8 +696,10 @@ def test_upgrade_by_card(self, *mocks: Mock) -> None:
response = self.upgrade()
[payment_intent] = PaymentIntent.objects.all()
assert payment_intent.stripe_payment_intent_id is not None

success = self.assert_json_success(response)
Copy link
Sponsor Member

Choose a reason for hiding this comment

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

I think result_dict or response_dict would probably be a better conventional variable name for these objects than success.

Copy link
Member

@andersk andersk Jun 3, 2022

Choose a reason for hiding this comment

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

I’m fine with success or response_dict I guess, but result_dict is strictly worse. (Requests have responses; computations have results. We have a lot of result variables of type HttpResponse that should be named response.)

My justification for success is the same as the one in the OpenAPI schema, where JsonResponse is the type of all API responses and JsonSuccess is the more specific subtype of all successful API responses.

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

response_dict WFM. I don't like success because the object it a dictionary containing the data returned in the response -- sans headers and the like. success_dict would be fine too, but I think it's cleaner to have the name directly associated with response.

Also agreed that it would be a nice refactor to s/result/response/ in the tests.

Copy link
Member Author

Choose a reason for hiding this comment

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

The PR is updated to go with response_dict.

@PIG208 PIG208 force-pushed the HttpResponse-missing-attributes branch from 53f97e0 to 177ce9a Compare June 4, 2022 16:11
@andersk
Copy link
Member

andersk commented Jun 4, 2022

I noticed that django-stubs actually knows about response.json(). We’re just not declaring our ZulipTestCase.client_get et al. wrappers with the type that knows about it, _MonkeyPatchedWSGIResponse. (It’s not present on all HttpResponse objects, only the ones returned by the test client.)

@PIG208
Copy link
Member Author

PIG208 commented Jun 5, 2022

I noticed that django-stubs actually knows about response.json(). We’re just not declaring our ZulipTestCase.client_get et al. wrappers with the type that knows about it, _MonkeyPatchedWSGIResponse. (It’s not present on all HttpResponse objects, only the ones returned by the test client.)

Yes. We might need to change the return type of the wrapped test client to _MonkeyPatchedWSGIResponse so that it's properly typed. This requires us to import it with django-stubs installed. This causes type errors wherever we have HttpResponse in our test code, and it will be a larger migration than this one.

@andersk
Copy link
Member

andersk commented Jun 5, 2022

You can actually write this today, without django-stubs installed (in which case mypy will treat it as Any, like it treats HttpResponse now).

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from django.test.client import _MonkeyPatchedWSGIResponse

def client_get(…) -> "_MonkeyPatchedWSGIResponse"

Even after we do install django-stubs, we’ll still need that TYPE_CHECKING conditional, since _MonkeyPatchedWSGIResponse doesn’t exist in the real django at runtime.

@timabbott
Copy link
Sponsor Member

Makes sense. Though I think it's probably a cleanup to the tests to not have tons of them doing the .json() access directly, so we probably still want to do a version of this PR? Or are you proposing we don't want to do that?

Copy link
Member

@andersk andersk left a comment

Choose a reason for hiding this comment

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

This is still basically a fine cleanup. If we have an assert_json_success we might as well use its return value.

The commit has two changes, though: use the assert_json_success return value, and add assert_json_error_data. The commit message only mentions the latter. (Unintentional squash perhaps?) It should be split into two commits. Or perhaps assert_json_error_data should be dropped—it has only two callers.

zerver/lib/test_classes.py Outdated Show resolved Hide resolved
@PIG208 PIG208 force-pushed the HttpResponse-missing-attributes branch 2 times, most recently from 71e0ef3 to e28ea5f Compare June 6, 2022 23:37
Signed-off-by: Zixuan James Li <p359101898@gmail.com>
@PIG208 PIG208 force-pushed the HttpResponse-missing-attributes branch from e28ea5f to 2e8c2b7 Compare June 6, 2022 23:47
@timabbott timabbott merged commit a142fbf into zulip:main Jun 7, 2022
@timabbott
Copy link
Sponsor Member

This is great, merged, thanks @PIG208!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants