Skip to content

Conversation

@amn
Copy link

@amn amn commented Nov 9, 2025

This adds assertion checks during initialisation of HTTPServerRequest object, to ensure the corresponding attributes of the object being created, won't end up being None. This allows the type checker to assume the value of the attribute is str and never None, which I argue aids typed Tornado applications. To be clear, it is still permitted to provide None or omit specification for both uri and method parameters to the constructor if the start_line parameter specifies [good] values instead.

This is also motivated by the idea that per HTTP, requests always feature a method and a URI, and so the HTTPServerRequest modelling wasn't optimal allowing None for either. As for typed Tornado applications using e.g. self.request.uri as part of request handling -- i.e. in code with self being a RequestHandler -- these can now safely assume e.g. uri or method are str and not str | None / Optional[str] which would require ad-hoc assertions ala assert self.request.uri is not None (or assert self.request.uri) in application code. That would IMO be a case of "surprising the user" -- as most everyone would expect an HTTP request to have its URI and method be "mandatory" attributes -- not allowing None for value.

Again, because semantics of start_line are preserved, the initialisation of the object may omit parameters uri and/or method if start_line specifies valid values for these instead. In any case, it is the attributes of the object being constructed, that end up being effectively validated with assert -- which make the type checker (tested with MyPy 1.18.2 here) assume str instead of str | None.

It's also important that this doesn't break existing Tornado applications, since the type of both attributes is effectively narrowed down, meaning that applications that would otherwise assume str | None can continue to do so safely -- "may be None" is compatible with "won't ever be None", obviously.

This adds assertion checks during initialisation of `HTTPServerRequest` object, to ensure the corresponding attributes of the object being created, won't end up being `None`. To be clear, it is still permitted to provide `None` or omit specification for both `uri` and `method` parameters to the constructor if the `start_line` parameter specifies [good] values instead.

This is motivated by the idea that per HTTP, requests _always_ feature a method and a URI, and so the model implemented with `HTTPServerRequest` is amended accordingly. Beyond the seemingly idealistic motivation, this helps with _typed_ Tornado applications using e.g. `self.request.uri` as part of request handling -- i.e. in code with `self` being a `RequestHandler` -- to safely assume e.g. `uri` or `method` are `str` and not `str | None` / `Optional[str]` which would require ad-hoc assertions ala `assert self.request.uri is not None` (or `assert self.request.uri`) in _application code_, which IMO is a case of "surprising the user" -- as everyone would expect a HTTP request to have an URI and method be clearly defined as e.g. strings -- certainly excluding the `None` value.

Again, because semantics of `start_line` are preserved, the initialisation of the object _may_ omit parameters `uri` and/or `method` if `start_line` specifies valid values for these instead. In any case, it is the _attributes_ of the object being constructed, that end up being effectively validated with `assert` -- which make the type checker (tested with MyPy 1.18.2 here) assume `str` instead of `str | None`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant