mirror of
https://github.com/kennethreitz/responder.git
synced 2026-06-05 23:00:17 +00:00
parameterized routes working
This commit is contained in:
@@ -5,6 +5,7 @@ name = "pypi"
|
||||
|
||||
[packages]
|
||||
responder = {editable = true, path = "."}
|
||||
uvicorn = "*"
|
||||
|
||||
[dev-packages]
|
||||
pytest = "*"
|
||||
|
||||
Generated
+57
-4
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "5843d79d019341544a1c9456b537125203079f127721132c8111421095660524"
|
||||
"sha256": "04a8f69fdffabcc25d69228af2c581260027423940c5ff741c42ba752ad2e35d"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -37,6 +37,13 @@
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||
],
|
||||
"version": "==7.0"
|
||||
},
|
||||
"graphene": {
|
||||
"hashes": [
|
||||
"sha256:b8ec446d17fa68721636eaad3d6adc1a378cb6323e219814c8f98c9928fc9642",
|
||||
@@ -63,6 +70,13 @@
|
||||
],
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"h11": {
|
||||
"hashes": [
|
||||
"sha256:acca6a44cb52a32ab442b1779adf0875c443c689e9e028f8d831a3769f9c5208",
|
||||
"sha256:f2b1ca39bfed357d1f19ac732913d5f9faa54a5062eca7d2ec3a916cfb7ae4c7"
|
||||
],
|
||||
"version": "==0.8.1"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
|
||||
@@ -83,6 +97,12 @@
|
||||
],
|
||||
"version": "==1.0"
|
||||
},
|
||||
"parse": {
|
||||
"hashes": [
|
||||
"sha256:9dd6048ea212cd032a342f9f6aa2b7bc222f7407c7e37bdc2777fecd36897437"
|
||||
],
|
||||
"version": "==1.9.0"
|
||||
},
|
||||
"promise": {
|
||||
"hashes": [
|
||||
"sha256:2ebbfc10b7abf6354403ed785fe4f04b9dfd421eb1a474ac8d187022228332af",
|
||||
@@ -138,6 +158,13 @@
|
||||
],
|
||||
"version": "==1.23"
|
||||
},
|
||||
"uvicorn": {
|
||||
"hashes": [
|
||||
"sha256:8de03999a936d8704f07cc3b1d3a3edb6922a068b64d84b4f5e49604c8b70a11"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.12"
|
||||
},
|
||||
"waitress": {
|
||||
"hashes": [
|
||||
"sha256:40b0f297a7f3af61fbfbdc67e59090c70dc150a1601c39ecc9f5f1d283fb931b",
|
||||
@@ -145,6 +172,32 @@
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"websockets": {
|
||||
"hashes": [
|
||||
"sha256:0e2f7d6567838369af074f0ef4d0b802d19fa1fee135d864acc656ceefa33136",
|
||||
"sha256:2a16dac282b2fdae75178d0ed3d5b9bc3258dabfae50196cbb30578d84b6f6a6",
|
||||
"sha256:5a1fa6072405648cb5b3688e9ed3b94be683ce4a4e5723e6f5d34859dee495c1",
|
||||
"sha256:5c1f55a1274df9d6a37553fef8cff2958515438c58920897675c9bc70f5a0538",
|
||||
"sha256:669d1e46f165e0ad152ed8197f7edead22854a6c90419f544e0f234cc9dac6c4",
|
||||
"sha256:695e34c4dbea18d09ab2c258994a8bf6a09564e762655408241f6a14592d2908",
|
||||
"sha256:6b2e03d69afa8d20253455e67b64de1a82ff8612db105113cccec35d3f8429f0",
|
||||
"sha256:79ca7cdda7ad4e3663ea3c43bfa8637fc5d5604c7737f19a8964781abbd1148d",
|
||||
"sha256:7fd2dd9a856f72e6ed06f82facfce01d119b88457cd4b47b7ae501e8e11eba9c",
|
||||
"sha256:82c0354ac39379d836719a77ee360ef865377aa6fdead87909d50248d0f05f4d",
|
||||
"sha256:8f3b956d11c5b301206382726210dc1d3bee1a9ccf7aadf895aaf31f71c3716c",
|
||||
"sha256:91ec98640220ae05b34b79ee88abf27f97ef7c61cf525eec57ea8fcea9f7dddb",
|
||||
"sha256:952be9540d83dba815569d5cb5f31708801e0bbfc3a8c5aef1890b57ed7e58bf",
|
||||
"sha256:99ac266af38ba1b1fe13975aea01ac0e14bb5f3a3200d2c69f05385768b8568e",
|
||||
"sha256:9fa122e7adb24232247f8a89f2d9070bf64b7869daf93ac5e19546b409e47e96",
|
||||
"sha256:a0873eadc4b8ca93e2e848d490809e0123eea154aa44ecd0109c4d0171869584",
|
||||
"sha256:cb998bd4d93af46b8b49ecf5a72c0a98e5cc6d57fdca6527ba78ad89d6606484",
|
||||
"sha256:e02e57346f6a68523e3c43bbdf35dde5c440318d1f827208ae455f6a2ace446d",
|
||||
"sha256:e79a5a896bcee7fff24a788d72e5c69f13e61369d055f28113e71945a7eb1559",
|
||||
"sha256:ee55eb6bcf23ecc975e6b47c127c201b913598f38b6a300075f84eeef2d3baff",
|
||||
"sha256:f1414e6cbcea8d22843e7eafdfdfae3dd1aba41d1945f6ca66e4806c07c4f454"
|
||||
],
|
||||
"version": "==6.0"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
|
||||
@@ -290,11 +343,11 @@
|
||||
},
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
"sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda",
|
||||
"sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"
|
||||
"sha256:a3d89af5db9e9806a779a50296b5fdb466e281147c2c235e8225ecc6dbf7bbf3",
|
||||
"sha256:c9b54bebe91a6a803e0772c8561d53f2926bfeb17cd141fbabcb08424086595c"
|
||||
],
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==0.3.9"
|
||||
"version": "==0.4.0"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
|
||||
@@ -49,7 +49,7 @@ print(
|
||||
# headers={"Accept": "application/x-yaml"},
|
||||
# data="hello",
|
||||
)
|
||||
.headers
|
||||
.text
|
||||
)
|
||||
|
||||
# print(
|
||||
|
||||
+16
-14
@@ -14,8 +14,9 @@ from graphql_server import encode_execution_results, json_encode, default_format
|
||||
|
||||
from . import models
|
||||
from .status_codes import HTTP_404
|
||||
from .routes import Route
|
||||
|
||||
|
||||
# TODO: consider moving status codes here
|
||||
class API:
|
||||
def __init__(self, static_dir="static", templates_dir="templates"):
|
||||
self.static_dir = Path(os.path.abspath(static_dir))
|
||||
@@ -81,8 +82,8 @@ class API:
|
||||
return self.wsgi_app(environ, start_response)
|
||||
|
||||
def path_matches_route(self, url):
|
||||
for (route, view) in self.routes.items():
|
||||
if url == route:
|
||||
for (route, route_object) in self.routes.items():
|
||||
if route_object.does_match(url):
|
||||
return route
|
||||
|
||||
def _dispatch_request(self, req):
|
||||
@@ -91,13 +92,14 @@ class API:
|
||||
|
||||
if route:
|
||||
try:
|
||||
self.routes[route](req, resp)
|
||||
params = self.routes[route].incoming_matches(req.path)
|
||||
self.routes[route].endpoint(req, resp, **params)
|
||||
# The request is using class-based views.
|
||||
except TypeError:
|
||||
try:
|
||||
view = self.routes[route]()
|
||||
view = self.routes[route].endpoint(**params)
|
||||
except TypeError:
|
||||
view = self.routes[route]
|
||||
view = self.routes[route].endpoint
|
||||
try:
|
||||
# GraphQL Schema.
|
||||
assert hasattr(view, "execute")
|
||||
@@ -119,7 +121,7 @@ class API:
|
||||
pass
|
||||
|
||||
# Then on_get.
|
||||
method = req.method.lower()
|
||||
method = req.method
|
||||
|
||||
try:
|
||||
getattr(view, f"on_{method}")(req, resp)
|
||||
@@ -135,7 +137,7 @@ class API:
|
||||
assert route not in self.routes
|
||||
|
||||
# TODO: Support grpahiql.
|
||||
self.routes[route] = view
|
||||
self.routes[route] = Route(route, view)
|
||||
|
||||
def default_response(self, req, resp):
|
||||
resp.status_code = HTTP_404
|
||||
@@ -193,14 +195,13 @@ class API:
|
||||
return self._session
|
||||
|
||||
def url_for(self, view, absolute_url=False, **params):
|
||||
for (route, _view) in self.routes.items():
|
||||
if view == _view:
|
||||
# TODO: Lots of cleanup here.
|
||||
return route
|
||||
for (route, route_object) in self.routes.items():
|
||||
if route_object.endpoint == _view:
|
||||
return route_object.url(**params)
|
||||
raise ValueError
|
||||
|
||||
def url(self):
|
||||
# Current URL, somehow.
|
||||
# TODO: Current URL, somehow.
|
||||
pass
|
||||
|
||||
def template(self, name, auto_escape=True, **values):
|
||||
@@ -254,5 +255,6 @@ class API:
|
||||
port = 0
|
||||
|
||||
bind_to = f"{address}:{port}"
|
||||
import uvicorn
|
||||
|
||||
waitress.serve(app=self, listen=bind_to, **kwargs)
|
||||
uvicorn.serve(app=self, listen=bind_to, **kwargs)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
from parse import parse, search
|
||||
|
||||
|
||||
class Route:
|
||||
def __init__(self, route, endpoint):
|
||||
self.route = route
|
||||
self.endpoint = endpoint
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Route {self.route!r}={self.endpoint!r}>"
|
||||
|
||||
def __eq__(self, other):
|
||||
if hasattr(other, "route"):
|
||||
# Being compared to other routes.
|
||||
return self.route == other.route
|
||||
else:
|
||||
# Strings.
|
||||
return self.does_match(other)
|
||||
|
||||
@property
|
||||
def has_parameters(self):
|
||||
return all([("{" in self.route), ("}" in self.route)])
|
||||
|
||||
def does_match(self, s):
|
||||
if s == self.route:
|
||||
return True
|
||||
|
||||
named = self.incoming_matches(s)
|
||||
return bool(len(named))
|
||||
|
||||
def incoming_matches(self, s):
|
||||
results = parse(self.route, s)
|
||||
return results.named if results else {}
|
||||
|
||||
def url(self, **params):
|
||||
return self.route.format(**params)
|
||||
|
||||
# def is_graphql, is_wsgi
|
||||
|
||||
|
||||
r = Route(route="/2/{name}", endpoint=print)
|
||||
print(r.does_match("/2/hello"))
|
||||
@@ -31,6 +31,7 @@ required = [
|
||||
"graphql-server-core>=1.1",
|
||||
"whitenoise",
|
||||
"jinja2",
|
||||
"parse",
|
||||
]
|
||||
|
||||
|
||||
|
||||
+8
-7
@@ -33,10 +33,6 @@ def schema():
|
||||
return graphene.Schema(query=Query)
|
||||
|
||||
|
||||
def test_api_fixture(api):
|
||||
assert api
|
||||
|
||||
|
||||
def test_api_basic_route(api):
|
||||
@api.route("/")
|
||||
def home(req, resp):
|
||||
@@ -153,6 +149,11 @@ def test_graphql_schema_query_querying(api, schema):
|
||||
assert r.json() == {"data": {"hello": None}}
|
||||
|
||||
|
||||
# GRAPHQL
|
||||
def test_assert():
|
||||
assert True
|
||||
def test_argumented_routing(api):
|
||||
@api.route("/{name}")
|
||||
def hello(req, resp, *, name):
|
||||
print("yay")
|
||||
resp.text = f"Hello, {name}."
|
||||
|
||||
r = api.session().get("http://app/sean")
|
||||
assert r.text == "Hello, sean."
|
||||
|
||||
Reference in New Issue
Block a user