Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
C
corepost
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
nexlab
corepost
Commits
29c6715b
Commit
29c6715b
authored
Sep 20, 2011
by
Jacek Furmankiewicz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
routing by incoming content type works
parent
89c4bf7c
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
139 additions
and
73 deletions
+139
-73
arguments.feature
corepost/test/feature/arguments.feature
+2
-2
content_types.feature
corepost/test/feature/content_types.feature
+23
-7
home_resource.py
corepost/test/home_resource.py
+20
-1
steps.py
corepost/test/steps.py
+6
-2
utils.py
corepost/utils.py
+4
-1
web.py
corepost/web.py
+84
-60
No files found.
corepost/test/feature/arguments.feature
View file @
29c6715b
...
@@ -5,7 +5,7 @@ Feature: Arguments
...
@@ -5,7 +5,7 @@ Feature: Arguments
CorePost should be able to correctly extract arguments
CorePost should be able to correctly extract arguments
from paths, query arguments and form arguments
from paths, query arguments and form arguments
@
path_arguments
@
arguments_ok
Scenario Outline
:
Path argument extraction
Scenario Outline
:
Path argument extraction
Given 'arguments' is running
Given 'arguments' is running
When as user 'None
:
None' I GET 'http
:
//127.0.0.1
:
8082<url>'
When as user 'None
:
None' I GET 'http
:
//127.0.0.1
:
8082<url>'
...
@@ -18,7 +18,7 @@ Feature: Arguments
...
@@ -18,7 +18,7 @@ Feature: Arguments
|
/int/1/float/1/string/TEST
|
200
|
[(<type
'int'>,
1),
(<type
'float'>,
1.0),
(<type
'str'>,
'TEST')]
|
|
/int/1/float/1/string/TEST
|
200
|
[(<type
'int'>,
1),
(<type
'float'>,
1.0),
(<type
'str'>,
'TEST')]
|
|
/int/1/float/1/string/23
|
200
|
[(<type
'int'>,
1),
(<type
'float'>,
1.0),
(<type
'str'>,
'23')]
|
|
/int/1/float/1/string/23
|
200
|
[(<type
'int'>,
1),
(<type
'float'>,
1.0),
(<type
'str'>,
'23')]
|
@
path_arguments
@
arguments_error
Scenario Outline
:
Path argument extraction - error handling
Scenario Outline
:
Path argument extraction - error handling
Given 'arguments' is running
Given 'arguments' is running
When as user 'None
:
None' I GET 'http
:
//127.0.0.1
:
8082<url>'
When as user 'None
:
None' I GET 'http
:
//127.0.0.1
:
8082<url>'
...
...
corepost/test/feature/content_types.feature
View file @
29c6715b
...
@@ -6,9 +6,11 @@ Feature: Content types
...
@@ -6,9 +6,11 @@ Feature: Content types
correctly parse/generate
correctly parse/generate
JSON/XML/YAML based on content types
JSON/XML/YAML based on content types
Background
:
Given 'home_resource' is running
@json
@json
Scenario Outline
:
Parse incoming JSON data
Scenario Outline
:
Parse incoming JSON data
Given 'home_resource' is running
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/json'
with
JSON
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/json'
with
JSON
"""
"""
{"test":"test2"}
{"test":"test2"}
...
@@ -26,7 +28,6 @@ Feature: Content types
...
@@ -26,7 +28,6 @@ Feature: Content types
@json
@json
Scenario Outline
:
Handle invalid incoming JSON data
Scenario Outline
:
Handle invalid incoming JSON data
Given 'home_resource' is running
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/json'
with
JSON
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/json'
with
JSON
"""
"""
wrong_json
wrong_json
...
@@ -41,7 +42,6 @@ Feature: Content types
...
@@ -41,7 +42,6 @@ Feature: Content types
@xml
@xml
Scenario Outline
:
Parse incoming XML data
Scenario Outline
:
Parse incoming XML data
Given 'home_resource' is running
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/xml'
with
XML
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/xml'
with
XML
"""
"""
<root><test>TEST</test><test2>Yo</test2></root>
<root><test>TEST</test><test2>Yo</test2></root>
...
@@ -57,7 +57,6 @@ Feature: Content types
...
@@ -57,7 +57,6 @@ Feature: Content types
@xml
@xml
Scenario Outline
:
Handle invalid XML data
Scenario Outline
:
Handle invalid XML data
Given 'home_resource' is running
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/xml'
with
XML
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/xml'
with
XML
"""
"""
wrong xml
wrong xml
...
@@ -73,7 +72,6 @@ Feature: Content types
...
@@ -73,7 +72,6 @@ Feature: Content types
@yaml
@yaml
Scenario Outline
:
Parse incoming YAML data
Scenario Outline
:
Parse incoming YAML data
Given 'home_resource' is running
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/yaml'
with
YAML
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/yaml'
with
YAML
"""
"""
invoice: 34843
invoice: 34843
...
@@ -144,7 +142,6 @@ total: 4443.52
...
@@ -144,7 +142,6 @@ total: 4443.52
@yaml
@yaml
Scenario Outline
:
Handle invalid YAML data
Scenario Outline
:
Handle invalid YAML data
Given 'home_resource' is running
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/yaml'
with
YAML
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/yaml'
with
YAML
"""
"""
- test
- test
...
@@ -156,4 +153,23 @@ total: 4443.52
...
@@ -156,4 +153,23 @@ total: 4443.52
Examples
:
Examples
:
|
method
|
|
method
|
|
POST
|
|
POST
|
|
PUT
|
|
PUT
|
\ No newline at end of file
@json
@yaml
@xml
@route_content_type
Scenario Outline
:
Route by incoming content type
When
I prepare HTTP header 'content-type' = '<content>'
When as user 'None
:
None' I <method> 'http
:
//127.0.0.1
:
8080/post/by/content'
with
<type>
body
'<body>'
Then
I expect HTTP code
<code>
And
I expect content contains '<content>'
Examples
:
|
method
|
type
|
body
|
content
|
code
|
|
POST
|
JSON
|
{"test":2}
|
application/json
|
201
|
|
POST
|
XML
|
<test>1</test>
|
application/xml
|
201
|
|
POST
|
XML
|
<test>1</test>
|
text/xml
|
201
|
|
POST
|
YAML
|
test:
2
|
text/yaml
|
201
|
|
PUT
|
JSON
|
{"test":2}
|
application/json
|
200
|
|
PUT
|
XML
|
<test>1</test>
|
text/xml
|
200
|
|
PUT
|
XML
|
<test>1</test>
|
application/xml
|
200
|
|
PUT
|
YAML
|
test:
2
|
text/yaml
|
200
|
\ No newline at end of file
corepost/test/home_resource.py
View file @
29c6715b
...
@@ -4,7 +4,7 @@ Server tests
...
@@ -4,7 +4,7 @@ Server tests
'''
'''
from
corepost.web
import
CorePost
,
route
from
corepost.web
import
CorePost
,
route
from
corepost.enums
import
Http
from
corepost.enums
import
Http
,
MediaType
,
HttpHeader
from
twisted.internet
import
defer
from
twisted.internet
import
defer
from
xml.etree
import
ElementTree
from
xml.etree
import
ElementTree
import
json
,
yaml
import
json
,
yaml
...
@@ -54,6 +54,25 @@ class HomeApp(CorePost):
...
@@ -54,6 +54,25 @@ class HomeApp(CorePost):
def
test_yaml
(
self
,
request
,
**
kwargs
):
def
test_yaml
(
self
,
request
,
**
kwargs
):
return
"
%
s"
%
yaml
.
dump
(
request
.
yaml
,
indent
=
4
,
width
=
130
,
default_flow_style
=
False
)
return
"
%
s"
%
yaml
.
dump
(
request
.
yaml
,
indent
=
4
,
width
=
130
,
default_flow_style
=
False
)
##################################################################
# same URLs, routed by incoming content type
###################################################################
@
route
(
"/post/by/content"
,(
Http
.
POST
,
Http
.
PUT
),
MediaType
.
APPLICATION_JSON
)
def
test_content_app_json
(
self
,
request
,
**
kwargs
):
return
request
.
received_headers
[
HttpHeader
.
CONTENT_TYPE
]
@
route
(
"/post/by/content"
,(
Http
.
POST
,
Http
.
PUT
),(
MediaType
.
TEXT_XML
,
MediaType
.
APPLICATION_XML
))
def
test_content_xml
(
self
,
request
,
**
kwargs
):
return
request
.
received_headers
[
HttpHeader
.
CONTENT_TYPE
]
@
route
(
"/post/by/content"
,(
Http
.
POST
,
Http
.
PUT
),
MediaType
.
TEXT_YAML
)
def
test_content_yaml
(
self
,
request
,
**
kwargs
):
return
request
.
received_headers
[
HttpHeader
.
CONTENT_TYPE
]
@
route
(
"/post/by/content"
,(
Http
.
POST
,
Http
.
PUT
))
def
test_content_catch_all
(
self
,
request
,
**
kwargs
):
return
MediaType
.
WILDCARD
def
run_app_home
():
def
run_app_home
():
app
=
HomeApp
()
app
=
HomeApp
()
...
...
corepost/test/steps.py
View file @
29c6715b
...
@@ -68,8 +68,12 @@ def when_as_user_i_send_post_put_to_url(user,password,method,url,params):
...
@@ -68,8 +68,12 @@ def when_as_user_i_send_post_put_to_url(user,password,method,url,params):
scc
.
http_headers
[
'Content-type'
]
=
'application/x-www-form-urlencoded'
scc
.
http_headers
[
'Content-type'
]
=
'application/x-www-form-urlencoded'
scc
.
response
,
scc
.
content
=
h
.
request
(
url
,
method
,
urlencode
(
as_dict
(
params
)),
headers
=
scc
.
http_headers
)
scc
.
response
,
scc
.
content
=
h
.
request
(
url
,
method
,
urlencode
(
as_dict
(
params
)),
headers
=
scc
.
http_headers
)
@
When
(
r"^as user '(.+):(.+)' I (POST|PUT) '(.+)' with (XML|JSON|YAML) body '(.+)'\s*$"
)
def
when_as_user_i_send_post_put_xml_json_to_url
(
user
,
password
,
method
,
url
,
request_type
,
body
):
when_as_user_i_send_post_put_xml_json_to_url_multiline
(
body
,
user
,
password
,
method
,
url
,
request_type
)
@
When
(
r"^as user '(.+):(.+)' I (POST|PUT) '(.+)' with (XML|JSON|YAML)\s*$"
)
@
When
(
r"^as user '(.+):(.+)' I (POST|PUT) '(.+)' with (XML|JSON|YAML)\s*$"
)
def
when_as_user_i_send_post_put_xml_json_to_url
(
payload
,
user
,
password
,
method
,
url
,
request_type
):
def
when_as_user_i_send_post_put_xml_json_to_url
_multiline
(
body
,
user
,
password
,
method
,
url
,
request_type
):
h
=
httplib2
.
Http
()
h
=
httplib2
.
Http
()
h
.
follow_redirects
=
False
h
.
follow_redirects
=
False
h
.
add_credentials
(
user
,
password
)
h
.
add_credentials
(
user
,
password
)
...
@@ -79,7 +83,7 @@ def when_as_user_i_send_post_put_xml_json_to_url(payload,user,password,method,ur
...
@@ -79,7 +83,7 @@ def when_as_user_i_send_post_put_xml_json_to_url(payload,user,password,method,ur
scc
.
http_headers
[
'Content-type'
]
=
'text/xml'
scc
.
http_headers
[
'Content-type'
]
=
'text/xml'
elif
request_type
==
"YAML"
:
elif
request_type
==
"YAML"
:
scc
.
http_headers
[
'Content-type'
]
=
'text/yaml'
scc
.
http_headers
[
'Content-type'
]
=
'text/yaml'
scc
.
response
,
scc
.
content
=
h
.
request
(
url
,
method
,
payload
,
headers
=
scc
.
http_headers
)
scc
.
response
,
scc
.
content
=
h
.
request
(
url
,
method
,
body
,
headers
=
scc
.
http_headers
)
@
When
(
"I prepare HTTP header '(.*)' = '(.*)'"
)
@
When
(
"I prepare HTTP header '(.*)' = '(.*)'"
)
def
when_i_define_http_header_with_value
(
header
,
value
):
def
when_i_define_http_header_with_value
(
header
,
value
):
...
...
corepost/utils.py
View file @
29c6715b
...
@@ -10,4 +10,7 @@ def getMandatoryArgumentNames(f):
...
@@ -10,4 +10,7 @@ def getMandatoryArgumentNames(f):
return
args
return
args
else
:
else
:
return
args
[
0
:
len
(
args
)
-
len
(
defaults
)]
return
args
[
0
:
len
(
args
)
-
len
(
defaults
)]
\ No newline at end of file
def
getRouterKey
(
method
,
url
):
'''Returns the common key used to represent a function that a request can be routed to'''
return
"
%
s
%
s"
%
(
method
,
url
)
\ No newline at end of file
corepost/web.py
View file @
29c6715b
...
@@ -27,7 +27,7 @@ class RequestRouter:
...
@@ -27,7 +27,7 @@ class RequestRouter:
def
__init__
(
self
,
f
,
url
,
methods
,
accepts
,
produces
,
cache
):
def
__init__
(
self
,
f
,
url
,
methods
,
accepts
,
produces
,
cache
):
self
.
__url
=
url
self
.
__url
=
url
self
.
__methods
=
methods
if
isinstance
(
methods
,
tuple
)
else
(
methods
,)
self
.
__methods
=
methods
if
isinstance
(
methods
,
tuple
)
else
(
methods
,)
self
.
__accepts
=
accepts
self
.
__accepts
=
accepts
if
isinstance
(
accepts
,
tuple
)
else
(
accepts
,)
self
.
__produces
=
produces
self
.
__produces
=
produces
self
.
__cache
=
cache
self
.
__cache
=
cache
self
.
__f
=
f
self
.
__f
=
f
...
@@ -66,6 +66,10 @@ class RequestRouter:
...
@@ -66,6 +66,10 @@ class RequestRouter:
def
url
(
self
):
def
url
(
self
):
return
self
.
__url
return
self
.
__url
@
property
def
accepts
(
self
):
return
self
.
__accepts
def
addValidator
(
self
,
fieldName
,
validator
):
def
addValidator
(
self
,
fieldName
,
validator
):
'''Adds additional field-specific formencode validators'''
'''Adds additional field-specific formencode validators'''
self
.
__validators
[
fieldName
]
=
validator
self
.
__validators
[
fieldName
]
=
validator
...
@@ -123,8 +127,8 @@ class CorePost(Resource):
...
@@ -123,8 +127,8 @@ class CorePost(Resource):
Constructor
Constructor
'''
'''
Resource
.
__init__
(
self
)
Resource
.
__init__
(
self
)
self
.
__urls
=
defaultdict
(
dict
)
self
.
__urls
=
{
Http
.
GET
:
defaultdict
(
dict
),
Http
.
POST
:
defaultdict
(
dict
),
Http
.
PUT
:
defaultdict
(
dict
),
Http
.
DELETE
:
defaultdict
(
dict
)}
self
.
__cachedUrls
=
defaultdict
(
dict
)
self
.
__cachedUrls
=
{
Http
.
GET
:
defaultdict
(
dict
),
Http
.
POST
:
defaultdict
(
dict
),
Http
.
PUT
:
defaultdict
(
dict
),
Http
.
DELETE
:
defaultdict
(
dict
)}
self
.
__routers
=
{}
self
.
__routers
=
{}
self
.
__schema
=
schema
self
.
__schema
=
schema
self
.
__registerRouters
()
self
.
__registerRouters
()
...
@@ -139,8 +143,9 @@ class CorePost(Resource):
...
@@ -139,8 +143,9 @@ class CorePost(Resource):
if
type
(
func
)
==
FunctionType
and
hasattr
(
func
,
'corepostRequestRouter'
):
if
type
(
func
)
==
FunctionType
and
hasattr
(
func
,
'corepostRequestRouter'
):
rq
=
func
.
corepostRequestRouter
rq
=
func
.
corepostRequestRouter
for
method
in
rq
.
methods
:
for
method
in
rq
.
methods
:
self
.
__urls
[
method
][
rq
.
url
]
=
rq
for
accepts
in
rq
.
accepts
:
self
.
__routers
[
func
]
=
rq
# needed so that we can lookup the router for a specific function
self
.
__urls
[
method
][
rq
.
url
][
accepts
]
=
rq
self
.
__routers
[
func
]
=
rq
# needed so that we can lookup the router for a specific function
def
route
(
self
,
url
,
methods
=
(
Http
.
GET
,),
accepts
=
MediaType
.
WILDCARD
,
produces
=
None
,
cache
=
True
):
def
route
(
self
,
url
,
methods
=
(
Http
.
GET
,),
accepts
=
MediaType
.
WILDCARD
,
produces
=
None
,
cache
=
True
):
'''Obsolete'''
'''Obsolete'''
...
@@ -165,64 +170,83 @@ class CorePost(Resource):
...
@@ -165,64 +170,83 @@ class CorePost(Resource):
def
__renderUrl
(
self
,
request
):
def
__renderUrl
(
self
,
request
):
"""Finds the appropriate router and dispatches the request to the registered function"""
"""Finds the appropriate router and dispatches the request to the registered function"""
# see if already cached
# see if already cached
path
=
'/'
+
'/'
.
join
(
request
.
postpath
)
try
:
path
=
'/'
+
'/'
.
join
(
request
.
postpath
)
urlrouter
,
pathargs
=
None
,
None
contentType
=
MediaType
.
WILDCARD
if
HttpHeader
.
CONTENT_TYPE
not
in
request
.
received_headers
else
request
.
received_headers
[
HttpHeader
.
CONTENT_TYPE
]
if
path
in
self
.
__cachedUrls
[
request
.
method
]:
cachedUrl
=
self
.
__cachedUrls
[
request
.
method
][
path
]
urlrouter
,
pathargs
=
cachedUrl
.
router
,
cachedUrl
.
args
else
:
# first time this URL is called
for
router
in
self
.
__urls
[
request
.
method
]
.
values
():
args
=
router
.
getArguments
(
path
)
if
args
!=
None
:
if
router
.
cache
:
self
.
__cachedUrls
[
request
.
method
][
path
]
=
CachedUrl
(
router
,
args
)
urlrouter
,
pathargs
=
router
,
args
#actual call
urlrouter
,
pathargs
=
None
,
None
if
urlrouter
!=
None
and
pathargs
!=
None
:
# fetch URL arguments <-> function from cache if hit at least once before
allargs
=
copy
.
deepcopy
(
pathargs
)
if
contentType
in
self
.
__cachedUrls
[
request
.
method
][
path
]:
# handler for weird Twisted logic where PUT does not get form params
cachedUrl
=
self
.
__cachedUrls
[
request
.
method
][
path
][
contentType
]
# see: http://twistedmatrix.com/pipermail/twisted-web/2007-March/003338.html
urlrouter
,
pathargs
=
cachedUrl
.
router
,
cachedUrl
.
args
requestargs
=
request
.
args
else
:
if
request
.
method
==
Http
.
PUT
and
HttpHeader
.
CONTENT_TYPE
in
request
.
received_headers
.
keys
()
\
# first time this URL is called
and
request
.
received_headers
[
HttpHeader
.
CONTENT_TYPE
]
==
MediaType
.
APPLICATION_FORM_URLENCODED
:
router
=
None
requestargs
=
parse_qs
(
request
.
content
.
read
(),
1
)
#merge form args
for
contentTypeFunctions
in
self
.
__urls
[
request
.
method
]
.
values
():
for
arg
in
requestargs
.
keys
():
# maintain first instance of an argument always
if
contentType
in
contentTypeFunctions
:
if
arg
not
in
allargs
:
# there is an exact function for this incoming content type
allargs
[
arg
]
=
requestargs
[
arg
][
0
]
router
=
contentTypeFunctions
[
contentType
]
elif
MediaType
.
WILDCARD
in
contentTypeFunctions
:
try
:
# fall back to any wildcard method
# if POST/PUT, check if we need to automatically parse JSON
router
=
contentTypeFunctions
[
MediaType
.
WILDCARD
]
self
.
__parseRequestData
(
request
)
if
router
!=
None
:
val
=
urlrouter
.
call
(
self
,
request
,
**
allargs
)
# see if the path arguments match up against any function @route definition
args
=
router
.
getArguments
(
path
)
#handle Deferreds natively
if
args
!=
None
:
if
isinstance
(
val
,
defer
.
Deferred
):
if
router
.
cache
:
# we assume the method will call request.finish()
self
.
__cachedUrls
[
request
.
method
][
path
][
contentType
]
=
CachedUrl
(
router
,
args
)
return
NOT_DONE_YET
urlrouter
,
pathargs
=
router
,
args
else
:
break
#special logic for POST to return 201 (created)
if
request
.
method
==
Http
.
POST
:
#actual call
if
hasattr
(
request
,
'code'
):
if
urlrouter
!=
None
and
pathargs
!=
None
:
if
request
.
code
==
200
:
allargs
=
copy
.
deepcopy
(
pathargs
)
# handler for weird Twisted logic where PUT does not get form params
# see: http://twistedmatrix.com/pipermail/twisted-web/2007-March/003338.html
requestargs
=
request
.
args
if
request
.
method
==
Http
.
PUT
and
HttpHeader
.
CONTENT_TYPE
in
request
.
received_headers
.
keys
()
\
and
request
.
received_headers
[
HttpHeader
.
CONTENT_TYPE
]
==
MediaType
.
APPLICATION_FORM_URLENCODED
:
requestargs
=
parse_qs
(
request
.
content
.
read
(),
1
)
#merge form args
for
arg
in
requestargs
.
keys
():
# maintain first instance of an argument always
if
arg
not
in
allargs
:
allargs
[
arg
]
=
requestargs
[
arg
][
0
]
try
:
# if POST/PUT, check if we need to automatically parse JSON
self
.
__parseRequestData
(
request
)
val
=
urlrouter
.
call
(
self
,
request
,
**
allargs
)
#handle Deferreds natively
if
isinstance
(
val
,
defer
.
Deferred
):
# we assume the method will call request.finish()
return
NOT_DONE_YET
else
:
#special logic for POST to return 201 (created)
if
request
.
method
==
Http
.
POST
:
if
hasattr
(
request
,
'code'
):
if
request
.
code
==
200
:
request
.
setResponseCode
(
201
)
else
:
request
.
setResponseCode
(
201
)
request
.
setResponseCode
(
201
)
else
:
request
.
setResponseCode
(
201
)
return
val
except
exceptions
.
TypeError
as
ex
:
return
val
return
self
.
__renderError
(
request
,
400
,
"
%
s"
%
ex
)
except
exceptions
.
TypeError
as
ex
:
except
Exception
as
ex
:
return
self
.
__renderError
(
request
,
400
,
"
%
s"
%
ex
)
return
self
.
__renderError
(
request
,
500
,
"Unexpected server error:
%
s
\n
%
s"
%
(
type
(
ex
),
ex
))
except
Exception
as
ex
:
return
self
.
__renderError
(
request
,
500
,
"Unexpected server error:
%
s
\n
%
s"
%
(
type
(
ex
),
ex
))
else
:
return
self
.
__renderError
(
request
,
404
,
"URL '
%
s' not found
\n
"
%
request
.
path
)
else
:
return
self
.
__renderError
(
request
,
404
,
"URL '
%
s' not found
\n
"
%
request
.
path
)
except
Exception
as
ex
:
return
self
.
__renderError
(
request
,
500
,
"Internal server error:
%
s"
%
ex
)
def
__renderError
(
self
,
request
,
code
,
message
):
def
__renderError
(
self
,
request
,
code
,
message
):
"""Common method for rendering errors"""
"""Common method for rendering errors"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment