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
446c73bf
Commit
446c73bf
authored
Sep 05, 2011
by
Jacek Furmankiewicz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
0.0.6: reworked API to be class/method oriented and avoid global objects
parent
fa5d53b9
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
131 additions
and
125 deletions
+131
-125
arguments.py
corepost/test/arguments.py
+18
-17
home_resource.py
corepost/test/home_resource.py
+38
-34
misc.py
corepost/test/misc.py
+0
-24
multi_resource.py
corepost/test/multi_resource.py
+25
-25
web.py
corepost/web.py
+48
-24
setup.py
setup.py
+2
-1
No files found.
corepost/test/arguments.py
View file @
446c73bf
...
...
@@ -3,30 +3,31 @@ Argument extraction tests
@author: jacekf
'''
from
corepost.web
import
CorePost
,
validate
from
corepost.web
import
CorePost
,
validate
,
route
from
corepost.enums
import
Http
from
formencode
import
Schema
,
validators
app
=
CorePost
()
class
TestSchema
(
Schema
):
allow_extra_fields
=
True
childId
=
validators
.
Regex
(
regex
=
"^jacekf|test$"
)
@
app
.
route
(
"/int/<int:intarg>/float/<float:floatarg>/string/<stringarg>"
,
Http
.
GET
)
def
test
(
request
,
intarg
,
floatarg
,
stringarg
,
**
kwargs
):
class
ArgumentApp
(
CorePost
):
@
route
(
"/int/<int:intarg>/float/<float:floatarg>/string/<stringarg>"
,
Http
.
GET
)
def
test
(
self
,
request
,
intarg
,
floatarg
,
stringarg
,
**
kwargs
):
args
=
(
intarg
,
floatarg
,
stringarg
)
return
"
%
s"
%
map
(
lambda
x
:
(
type
(
x
),
x
),
args
)
@
app
.
route
(
"/validate/<int:rootId>/schema"
,
Http
.
POST
)
@
validate
(
schema
=
TestSchema
)
def
postValidateSchema
(
request
,
rootId
,
childId
,
**
kwargs
):
@
route
(
"/validate/<int:rootId>/schema"
,
Http
.
POST
)
@
validate
(
schema
=
TestSchema
()
)
def
postValidateSchema
(
self
,
request
,
rootId
,
childId
,
**
kwargs
):
return
"
%
s -
%
s -
%
s"
%
(
rootId
,
childId
,
kwargs
)
@
app
.
route
(
"/validate/<int:rootId>/custom"
,
Http
.
POST
)
@
validate
(
childId
=
validators
.
Regex
(
regex
=
"^jacekf|test$"
))
def
postValidateCustom
(
request
,
rootId
,
childId
,
**
kwargs
):
@
route
(
"/validate/<int:rootId>/custom"
,
Http
.
POST
)
@
validate
(
childId
=
validators
.
Regex
(
regex
=
"^jacekf|test$"
))
def
postValidateCustom
(
self
,
request
,
rootId
,
childId
,
**
kwargs
):
return
"
%
s -
%
s -
%
s"
%
(
rootId
,
childId
,
kwargs
)
def
run_app_arguments
():
app
=
ArgumentApp
()
app
.
run
(
8082
)
\ No newline at end of file
corepost/test/home_resource.py
View file @
446c73bf
...
...
@@ -3,42 +3,46 @@ Server tests
@author: jacekf
'''
from
corepost.web
import
CorePost
from
corepost.web
import
CorePost
,
route
from
corepost.enums
import
Http
from
twisted.internet
import
defer
app
=
CorePost
()
class
HomeApp
(
CorePost
):
@
app
.
route
(
"/"
,
Http
.
GET
)
@
defer
.
inlineCallbacks
def
root
(
request
,
**
kwargs
):
@
route
(
"/"
,
Http
.
GET
)
@
defer
.
inlineCallbacks
def
root
(
self
,
request
,
**
kwargs
):
yield
1
request
.
write
(
"
%
s"
%
kwargs
)
request
.
finish
()
@
app
.
route
(
"/test"
,
Http
.
GET
)
def
test
(
request
,
**
kwargs
):
@
route
(
"/test"
,
Http
.
GET
)
def
test
(
self
,
request
,
**
kwargs
):
return
"
%
s"
%
kwargs
@
app
.
route
(
"/test/<int:numericid>/resource/<stringid>"
,
Http
.
GET
)
def
test_get_resources
(
request
,
numericid
,
stringid
,
**
kwargs
):
@
route
(
"/test/<int:numericid>/resource/<stringid>"
,
Http
.
GET
)
def
test_get_resources
(
self
,
request
,
numericid
,
stringid
,
**
kwargs
):
return
"
%
s -
%
s"
%
(
numericid
,
stringid
)
@
app
.
route
(
"/post"
,(
Http
.
POST
,
Http
.
PUT
))
def
test_post
(
request
,
**
kwargs
):
@
route
(
"/post"
,(
Http
.
POST
,
Http
.
PUT
))
def
test_post
(
self
,
request
,
**
kwargs
):
return
"
%
s"
%
kwargs
@
app
.
route
(
"/put"
,(
Http
.
POST
,
Http
.
PUT
))
def
test_put
(
request
,
**
kwargs
):
@
route
(
"/put"
,(
Http
.
POST
,
Http
.
PUT
))
def
test_put
(
self
,
request
,
**
kwargs
):
return
"
%
s"
%
kwargs
@
app
.
route
(
"/postput"
,(
Http
.
POST
,
Http
.
PUT
))
def
test_postput
(
request
,
**
kwargs
):
@
route
(
"/postput"
,(
Http
.
POST
,
Http
.
PUT
))
def
test_postput
(
self
,
request
,
**
kwargs
):
return
"
%
s"
%
kwargs
@
app
.
route
(
"/delete"
,
Http
.
DELETE
)
def
test_delete
(
request
,
**
kwargs
):
@
route
(
"/delete"
,
Http
.
DELETE
)
def
test_delete
(
self
,
request
,
**
kwargs
):
return
"
%
s"
%
kwargs
def
run_app_home
():
app
=
HomeApp
()
app
.
run
()
if
__name__
==
"__main__"
:
run_app_home
()
\ No newline at end of file
corepost/test/misc.py
deleted
100644 → 0
View file @
fa5d53b9
'''
Created on 2011-09-02
Misc tests
@author: jacekf
'''
def
dec
(
f
):
print
"DEC"
def
wrap
():
print
"WRAP"
v
=
f
()
return
v
return
wrap
@
dec
def
test
():
print
"TEST3232"
if
__name__
==
"__main__"
:
test
()
test
()
test
()
\ No newline at end of file
corepost/test/multi_resource.py
View file @
446c73bf
...
...
@@ -2,43 +2,43 @@
A CorePost module1 that can be merged into the main CorePost Resource
'''
from
corepost.web
import
CorePost
from
corepost.web
import
CorePost
,
route
from
corepost.enums
import
Http
from
twisted.web.resource
import
Resource
from
twisted.internet
import
reactor
from
twisted.web.server
import
Site
home
=
CorePost
()
class
HomeApp
(
CorePost
):
@
home
.
route
(
"/"
)
def
home_root
(
request
,
**
kwargs
):
@
route
(
"/"
)
def
home_root
(
self
,
request
,
**
kwargs
):
return
"HOME
%
s"
%
kwargs
module1
=
CorePost
(
'module1'
)
class
Module1
(
CorePost
):
@
module1
.
route
(
"/"
,
Http
.
GET
)
def
module1_get
(
request
,
**
kwargs
):
@
route
(
"/"
,
Http
.
GET
)
def
module1_get
(
self
,
request
,
**
kwargs
):
return
request
.
path
@
module1
.
route
(
"/sub"
,
Http
.
GET
)
def
module1e_sub
(
request
,
**
kwargs
):
@
route
(
"/sub"
,
Http
.
GET
)
def
module1e_sub
(
self
,
request
,
**
kwargs
):
return
request
.
path
module2
=
CorePost
(
'module2'
)
class
Module2
(
CorePost
):
@
module2
.
route
(
"/"
,
Http
.
GET
)
def
module2_get
(
request
,
**
kwargs
):
@
route
(
"/"
,
Http
.
GET
)
def
module2_get
(
self
,
request
,
**
kwargs
):
return
request
.
path
@
module2
.
route
(
"/sub"
,
Http
.
GET
)
def
module2_sub
(
request
,
**
kwargs
):
@
route
(
"/sub"
,
Http
.
GET
)
def
module2_sub
(
self
,
request
,
**
kwargs
):
return
request
.
path
def
run_app_multi
():
app
=
Resource
()
app
.
putChild
(
home
.
path
,
home
)
app
.
putChild
(
module1
.
path
,
module1
)
app
.
putChild
(
module2
.
path
,
module2
)
app
.
putChild
(
''
,
HomeApp
()
)
app
.
putChild
(
'module1'
,
Module1
()
)
app
.
putChild
(
'module2'
,
Module2
()
)
factory
=
Site
(
app
)
reactor
.
listenTCP
(
8081
,
factory
)
#@UndefinedVariable
...
...
corepost/web.py
View file @
446c73bf
...
...
@@ -3,16 +3,18 @@ Main server classes
@author: jacekf
'''
import
re
,
copy
,
exceptions
from
twisted.internet
import
reactor
,
defer
from
twisted.web.resource
import
Resource
from
twisted.web.server
import
Site
,
NOT_DONE_YET
from
twisted.web.http
import
parse_qs
from
collections
import
defaultdict
from
enums
import
MediaType
from
corepost.enums
import
Http
from
corepost.utils
import
getMandatoryArgumentNames
from
enums
import
MediaType
from
formencode
import
FancyValidator
,
Invalid
from
twisted.internet
import
reactor
,
defer
from
twisted.web.http
import
parse_qs
from
twisted.web.resource
import
Resource
from
twisted.web.server
import
Site
,
NOT_DONE_YET
import
re
import
copy
import
exceptions
class
RequestRouter
:
''' Common class for containing info related to routing a request to a function '''
...
...
@@ -21,17 +23,16 @@ class RequestRouter:
__urlRegexReplace
=
{
""
:
r"(?P<arg>.+)"
,
"int"
:
r"(?P<arg>\d+)"
,
"float"
:
r"(?P<arg>\d+.?\d*)"
}
__typeConverters
=
{
"int"
:
int
,
"float"
:
float
}
def
__init__
(
self
,
f
,
url
,
method
,
accepts
,
produces
,
cache
):
def
__init__
(
self
,
f
,
url
,
method
s
,
accepts
,
produces
,
cache
):
self
.
__url
=
url
self
.
__method
=
method
self
.
__method
s
=
methods
if
isinstance
(
methods
,
tuple
)
else
(
methods
,)
self
.
__accepts
=
accepts
self
.
__produces
=
produces
self
.
__cache
=
cache
self
.
__f
=
f
self
.
__argConverters
=
{}
# dict of arg names -> group index
self
.
__schema
=
None
self
.
__validators
=
{}
self
.
__mandatory
=
getMandatoryArgumentNames
(
f
)[
1
:]
self
.
__mandatory
=
getMandatoryArgumentNames
(
f
)[
2
:]
#parse URL into regex used for matching
m
=
RequestRouter
.
__urlMatcher
.
findall
(
url
)
...
...
@@ -57,9 +58,12 @@ class RequestRouter:
return
self
.
__cache
@
property
def
schema
(
self
):
''''Returns the formencode Schema, if this URL uses custom validation schema'''
return
self
.
__schema
def
methods
(
self
):
return
self
.
__methods
@
property
def
url
(
self
):
return
self
.
__url
def
addValidator
(
self
,
fieldName
,
validator
):
'''Adds additional field-specific formencode validators'''
...
...
@@ -83,12 +87,12 @@ class RequestRouter:
else
:
return
None
def
call
(
self
,
request
,
**
kwargs
):
def
call
(
self
,
instance
,
request
,
**
kwargs
):
'''Forwards call to underlying method'''
for
arg
in
self
.
__mandatory
:
if
arg
not
in
kwargs
:
raise
TypeError
(
"Missing mandatory argument '
%
s'"
%
arg
)
return
self
.
__f
(
request
,
**
kwargs
)
return
self
.
__f
(
instance
,
request
,
**
kwargs
)
class
CachedUrl
():
'''
...
...
@@ -113,7 +117,7 @@ class CorePost(Resource):
'''
isLeaf
=
True
def
__init__
(
self
,
path
=
''
,
schema
=
None
):
def
__init__
(
self
,
schema
=
None
):
'''
Constructor
'''
...
...
@@ -122,13 +126,22 @@ class CorePost(Resource):
self
.
__cachedUrls
=
defaultdict
(
dict
)
self
.
__methods
=
{}
self
.
__routers
=
{}
self
.
__path
=
path
self
.
__schema
=
schema
self
.
__registerRouters
()
@
property
def
path
(
self
):
return
self
.
__path
def
__registerRouters
(
self
):
from
types
import
FunctionType
for
_
,
func
in
self
.
__class__
.
__dict__
.
iteritems
():
if
type
(
func
)
==
FunctionType
and
hasattr
(
func
,
'corepostRequestRouter'
):
rq
=
func
.
corepostRequestRouter
for
method
in
rq
.
methods
:
self
.
__urls
[
method
][
rq
.
url
]
=
rq
self
.
__routers
[
func
]
=
rq
# needed so that we can lookup the router for a specific function
def
__registerFunction
(
self
,
f
,
url
,
methods
,
accepts
,
produces
,
cache
):
if
f
not
in
self
.
__methods
.
values
():
if
not
isinstance
(
methods
,(
list
,
tuple
)):
...
...
@@ -142,11 +155,8 @@ class CorePost(Resource):
self
.
__methods
[
url
]
=
f
def
route
(
self
,
url
,
methods
=
(
Http
.
GET
,),
accepts
=
MediaType
.
WILDCARD
,
produces
=
None
,
cache
=
True
):
"""Main decorator for registering REST functions """
def
wrap
(
f
,
*
args
,
**
kwargs
):
self
.
__registerFunction
(
f
,
url
,
methods
,
accepts
,
produces
,
cache
)
return
f
return
wrap
'''Obsolete'''
raise
RuntimeError
(
"Do not @app.route() any more, as of 0.0.6 API has been re-designed around class methods, see docs and examples"
)
def
render_GET
(
self
,
request
):
""" Handles all GET requests """
...
...
@@ -202,7 +212,7 @@ class CorePost(Resource):
#handle Deferreds natively
try
:
val
=
urlrouter
.
call
(
request
,
**
allargs
)
val
=
urlrouter
.
call
(
self
,
request
,
**
allargs
)
if
isinstance
(
val
,
defer
.
Deferred
):
# we assume the method will call request.finish()
...
...
@@ -244,6 +254,20 @@ class CorePost(Resource):
#
##################################################################################################
def
route
(
url
,
methods
=
(
Http
.
GET
,),
accepts
=
MediaType
.
WILDCARD
,
produces
=
None
,
cache
=
True
):
'''
Main decorator for registering REST functions
'''
def
decorator
(
f
):
def
wrap
(
*
args
,
**
kwargs
):
return
f
router
=
RequestRouter
(
f
,
url
,
methods
,
accepts
,
produces
,
cache
)
setattr
(
wrap
,
'corepostRequestRouter'
,
router
)
return
wrap
return
decorator
def
validate
(
schema
=
None
,
**
vKwargs
):
'''
Main decorator for registering additional validators for incoming URL arguments
...
...
setup.py
View file @
446c73bf
...
...
@@ -40,6 +40,7 @@ Links
Changelog
`````````
* 0.0.6 - redesigned API around classes and methods, rather than functions and global objects (after feedback from Twisted devs)
* 0.0.5 - added FormEncode validation for arguments
* 0.0.4 - path argument extraction, mandatory argument error checking
...
...
@@ -57,7 +58,7 @@ def read(fname):
setup
(
name
=
"CorePost"
,
version
=
"0.0.
5
"
,
version
=
"0.0.
6
"
,
author
=
"Jacek Furmankiewicz"
,
author_email
=
"jacek99@gmail.com"
,
description
=
(
"A Twisted Web REST micro-framework"
),
...
...
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