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

Documentation for the "request" object #706

Closed
simonw opened this issue Mar 22, 2020 · 6 comments
Closed

Documentation for the "request" object #706

simonw opened this issue Mar 22, 2020 · 6 comments

Comments

@simonw
Copy link
Owner

simonw commented Mar 22, 2020

Since that object is passed to the extra_template_vars hooks AND the classes registered by register_facet_classes it should be part of the documented interface on https://datasette.readthedocs.io/en/stable/internals.html

I could also start passing it to the register_output_renderer callback.

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

This is the full current implementation of the request object:

class Request:
def __init__(self, scope, receive):
self.scope = scope
self.receive = receive
@property
def method(self):
return self.scope["method"]
@property
def url(self):
return urlunparse(
(self.scheme, self.host, self.path, None, self.query_string, None)
)
@property
def scheme(self):
return self.scope.get("scheme") or "http"
@property
def headers(self):
return dict(
[
(k.decode("latin-1").lower(), v.decode("latin-1"))
for k, v in self.scope.get("headers") or []
]
)
@property
def host(self):
return self.headers.get("host") or "localhost"
@property
def path(self):
if self.scope.get("raw_path") is not None:
return self.scope["raw_path"].decode("latin-1")
else:
path = self.scope["path"]
if isinstance(path, str):
return path
else:
return path.decode("utf-8")
@property
def query_string(self):
return (self.scope.get("query_string") or b"").decode("latin-1")
@property
def args(self):
return RequestParameters(parse_qs(qs=self.query_string))
@property
def raw_args(self):
return {key: value[0] for key, value in self.args.items()}
async def post_vars(self):
body = []
body = b""
more_body = True
while more_body:
message = await self.receive()
assert message["type"] == "http.request", message
body += message.get("body", b"")
more_body = message.get("more_body", False)
return dict(parse_qsl(body.decode("utf-8")))
@classmethod
def fake(cls, path_with_query_string, method="GET", scheme="http"):
"Useful for constructing Request objects for tests"
path, _, query_string = path_with_query_string.partition("?")
scope = {
"http_version": "1.1",
"method": method,
"path": path,
"raw_path": path.encode("latin-1"),
"query_string": query_string.encode("latin-1"),
"scheme": scheme,
"type": "http",
}
return cls(scope, None)

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

New documentation can be seen here: https://github.com/simonw/datasette/blob/6d7cb02f00010d3cb4b4bac0460d41277652b80e/docs/internals.rst#request-object

It's inspired me to reconsider the name of the .raw_args property, which isn't particularly clear.

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

It looks like I inherited .raw_args from Sanic - I use it in a few places: https://github.com/search?q=user%3Asimonw+raw_args&type=Code

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

What would a better name be?

  • .simple_args
  • .kv_args
  • .pair_args
  • .dict_args
  • .args_dict

I dislike the last two the least.

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

I'm going to leave .raw_args in for the moment but deliberately not document it. I'll hope to phase it out entirely at a later date.

@simonw
Copy link
Owner Author

simonw commented May 28, 2020

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

No branches or pull requests

1 participant