Skip to content

Commit

Permalink
Expose scope parameter in request object (#2432)
Browse files Browse the repository at this point in the history
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
  • Loading branch information
azimovMichael and ahopkins authored Apr 26, 2022
1 parent 78b6723 commit 5d683c6
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 1 deletion.
4 changes: 4 additions & 0 deletions sanic/models/protocol_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from typing import Any, AnyStr, TypeVar, Union

from sanic.models.asgi import ASGIScope


if sys.version_info < (3, 8):
from asyncio import BaseTransport
Expand All @@ -17,6 +19,8 @@
from typing import Protocol

class TransportProtocol(Protocol):
scope: ASGIScope

def get_protocol(self):
...

Expand Down
16 changes: 16 additions & 0 deletions sanic/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from sanic_routing.route import Route # type: ignore

from sanic.models.asgi import ASGIScope
from sanic.models.http_types import Credentials


Expand Down Expand Up @@ -831,6 +832,21 @@ def url_for(self, view_name: str, **kwargs) -> str:
view_name, _external=True, _scheme=scheme, _server=netloc, **kwargs
)

@property
def scope(self) -> ASGIScope:
"""
:return: The ASGI scope of the request.
If the app isn't an ASGI app, then raises an exception.
:rtype: Optional[ASGIScope]
"""
if not self.app.asgi:
raise NotImplementedError(
"App isn't running in ASGI mode. "
"Scope is only available for ASGI apps."
)

return self.transport.scope


class File(NamedTuple):
"""
Expand Down
26 changes: 26 additions & 0 deletions tests/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,29 @@ def test_bad_url_parse():
Mock(),
Mock(),
)


def test_request_scope_raises_exception_when_no_asgi():
app = Sanic("no_asgi")

@app.get("/")
async def get(request):
return request.scope

request, response = app.test_client.get("/")
assert response.status == 500
with pytest.raises(NotImplementedError):
_ = request.scope


@pytest.mark.asyncio
async def test_request_scope_is_not_none_when_running_in_asgi(app):
@app.get("/")
async def get(request):
return response.empty()

request, _ = await app.asgi_client.get("/")

assert request.scope is not None
assert request.scope["method"].lower() == "get"
assert request.scope["path"].lower() == "/"
2 changes: 1 addition & 1 deletion tests/test_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,6 @@ async def handler(request):
assert request.form.get("test") == "" # For request.parsed_form



def test_post_form_urlencoded_drop_blanks(app):
@app.route("/", methods=["POST"])
async def handler(request):
Expand All @@ -1066,6 +1065,7 @@ async def handler(request):

assert "test" not in request.form.keys()


@pytest.mark.asyncio
async def test_post_form_urlencoded_drop_blanks_asgi(app):
@app.route("/", methods=["POST"])
Expand Down

0 comments on commit 5d683c6

Please sign in to comment.