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
021581bb
Commit
021581bb
authored
Aug 30, 2011
by
Jacek Furmankiewicz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
multi resource support + BDD tests + docs
parent
a08b5e25
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
166 additions
and
36 deletions
+166
-36
README.md
README.md
+80
-4
url_routing.feature
corepost/test/feature/url_routing.feature
+17
-0
multi_resource.py
corepost/test/multi_resource.py
+46
-0
steps.py
corepost/test/steps.py
+14
-14
submodule_test.py
corepost/test/submodule_test.py
+0
-13
web.py
corepost/web.py
+8
-3
setup.py
setup.py
+1
-2
No files found.
README.md
View file @
021581bb
...
@@ -4,11 +4,13 @@ Twisted REST micro-framework
...
@@ -4,11 +4,13 @@ Twisted REST micro-framework
Based on
*Flask*
API, with integrated multiprocessing support for full usage of all CPUs.
Based on
*Flask*
API, with integrated multiprocessing support for full usage of all CPUs.
Provides a more Flask/Sinatra-style API on top of the core
*twisted.web*
APIs.
Provides a more Flask/Sinatra-style API on top of the core
*twisted.web*
APIs.
Geared towards creating REST-oriented server platforms
(e.g. as a source of data for a Javascript MVC app)
.
Geared towards creating REST-oriented server platforms.
Tested
exclusively on PyPy
for maximum performance.
Tested
on PyPy (recommended) and Python 2.7
for maximum performance.
Example
Single REST module example
-------
--------------------------
The simplest possible REST application:
from corepost.web import CorePost
from corepost.web import CorePost
from corepost.enums import Http
from corepost.enums import Http
...
@@ -28,8 +30,74 @@ Example
...
@@ -28,8 +30,74 @@ Example
return "%s - %s" % (numericid,stringid)
return "%s - %s" % (numericid,stringid)
if __name__ == '__main__':
if __name__ == '__main__':
# shortcut method to run a CorePost Resource as a single site
app.run()
app.run()
Multiple module REST application
--------------------------------
The key CorePost object is just an extension of the regular twisted.web Resource object
and as such can easily be used to assemble a multi-module REST applications with
different CorePost objects serving from different context paths:
from corepost.web import CorePost
from corepost.enums import Http
from twisted.web.resource import Resource
from twisted.internet import reactor
from twisted.web.server import Site
# Home module
home = CorePost()
@home.route("/")
def home_root(request,**kwargs):
return "HOME %s" % kwargs
# First module
module1 = CorePost('module1')
@module1.route("/",Http.GET)
def module1_get(request,**kwargs):
return request.path
@module1.route("/sub",Http.GET)
def module1e_sub(request,**kwargs):
return request.path
# Second module
module2 = CorePost('module2')
@module2.route("/",Http.GET)
def module2_get(request,**kwargs):
return request.path
@module2.route("/sub",Http.GET)
def module2_sub(request,**kwargs):
return request.path
if __name__ == '__main__':
app = Resource()
app.putChild(home.path, home)
app.putChild(module1.path,module1)
app.putChild(module2.path,module2)
factory = Site(app)
reactor.listenTCP(8080, factory)
reactor.run()
The example above creates 3 modules ("/","module1","/module2") and exposes the following URLs:
http://127.0.0.1:8080
http://127.0.0.1:8080/
http://127.0.0.1:8080/module1
http://127.0.0.1:8080/module1/
http://127.0.0.1:8080/module1/sub
http://127.0.0.1:8080/module2
http://127.0.0.1:8080/module2/
http://127.0.0.1:8080/module2/sub
@defer.inlineCallbacks support
@defer.inlineCallbacks support
------------------------------
------------------------------
...
@@ -47,6 +115,14 @@ Performance
...
@@ -47,6 +115,14 @@ Performance
On par with raw
*twisted.web*
performance. Minimal overhead for URL routing and function argument extraction.
On par with raw
*twisted.web*
performance. Minimal overhead for URL routing and function argument extraction.
BDD unit tests
--------------
All unit tests for CorePost are in BDD feature format, using Freshen.
Can be run using:
nosetests --with-freshen -v
Plans
Plans
-----
-----
...
...
corepost/test/feature/url_routing.feature
View file @
021581bb
...
@@ -52,3 +52,20 @@ Feature: URL routing
...
@@ -52,3 +52,20 @@ Feature: URL routing
Then
I expect HTTP code 200
Then
I expect HTTP code 200
And I expect content contains '{'test'
:
'value', 'test2'
:
'value2'}'
And I expect content contains '{'test'
:
'value', 'test2'
:
'value2'}'
@multi
Scenario Outline
:
Multiple resources with submodules
Given 'multi_resource' is running
When as user 'None
:
None'
I
GET '<url>'
Then
I expect HTTP code 200
Examples
:
|
url
|
|
http://127.0.0.1:8081
|
|
http://127.0.0.1:8081/
|
|
http://127.0.0.1:8081/module1
|
|
http://127.0.0.1:8081/module1/
|
|
http://127.0.0.1:8081/module1/sub
|
|
http://127.0.0.1:8081/module2
|
|
http://127.0.0.1:8081/module2/
|
|
http://127.0.0.1:8081/module2/sub
|
\ No newline at end of file
corepost/test/multi_resource.py
0 → 100644
View file @
021581bb
'''
A CorePost module1 that can be merged into the main CorePost Resource
'''
from
corepost.web
import
CorePost
from
corepost.enums
import
Http
from
twisted.web.resource
import
Resource
from
twisted.internet
import
reactor
from
twisted.web.server
import
Site
home
=
CorePost
()
@
home
.
route
(
"/"
)
def
home_root
(
request
,
**
kwargs
):
return
"HOME
%
s"
%
kwargs
module1
=
CorePost
(
'module1'
)
@
module1
.
route
(
"/"
,
Http
.
GET
)
def
module1_get
(
request
,
**
kwargs
):
return
request
.
path
@
module1
.
route
(
"/sub"
,
Http
.
GET
)
def
module1e_sub
(
request
,
**
kwargs
):
return
request
.
path
module2
=
CorePost
(
'module2'
)
@
module2
.
route
(
"/"
,
Http
.
GET
)
def
module2_get
(
request
,
**
kwargs
):
return
request
.
path
@
module2
.
route
(
"/sub"
,
Http
.
GET
)
def
module2_sub
(
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
)
factory
=
Site
(
app
)
reactor
.
listenTCP
(
8081
,
factory
)
#@UndefinedVariable
reactor
.
run
()
#@UndefinedVariable
corepost/test/steps.py
View file @
021581bb
...
@@ -5,11 +5,12 @@ Common Freshen BDD steps
...
@@ -5,11 +5,12 @@ Common Freshen BDD steps
'''
'''
from
multiprocessing
import
Process
from
multiprocessing
import
Process
import
httplib2
,
json
,
re
,
time
import
httplib2
,
json
,
re
,
time
from
freshen
import
Before
,
After
,
Given
,
When
,
Then
,
scc
,
assert_equals
,
assert_true
#@UnresolvedImport
from
freshen
import
Before
,
After
,
Given
,
When
,
Then
,
scc
,
glc
,
assert_equals
,
assert_true
#@UnresolvedImport
from
urllib
import
urlencode
from
urllib
import
urlencode
from
corepost.test.home_resource
import
run_app_home
from
corepost.test.home_resource
import
run_app_home
from
corepost.test.multi_resource
import
run_app_multi
apps
=
{
'home_resource'
:
run_app_home
}
apps
=
{
'home_resource'
:
run_app_home
,
'multi_resource'
:
run_app_multi
}
def
as_dict
(
parameters
):
def
as_dict
(
parameters
):
dict_val
=
{}
dict_val
=
{}
...
@@ -25,26 +26,25 @@ def as_dict(parameters):
...
@@ -25,26 +26,25 @@ def as_dict(parameters):
@
Before
@
Before
def
setup
(
slc
):
def
setup
(
slc
):
scc
.
processes
=
[]
scc
.
http_headers
=
{}
scc
.
http_headers
=
{}
@
After
def
cleanup
(
slc
):
# shut down processes
for
process
in
scc
.
processes
:
process
.
terminate
()
##################################
##################################
# GIVEN
# GIVEN
##################################
##################################
@
Given
(
r"^'(.+)' is running\s*$"
)
@
Given
(
r"^'(.+)' is running\s*$"
)
def
given_process_is_running
(
processname
):
def
given_process_is_running
(
processname
):
if
glc
.
processes
==
None
:
glc
.
processes
=
{}
if
processname
not
in
glc
.
processes
:
# start a process only once, keep it running
# to make test runs faster
process
=
Process
(
target
=
apps
[
processname
])
process
=
Process
(
target
=
apps
[
processname
])
process
.
daemon
=
True
process
.
daemon
=
True
process
.
start
()
process
.
start
()
scc
.
processes
.
append
(
process
)
time
.
sleep
(
0.25
)
# let it start up
time
.
sleep
(
0.25
)
# let it start up
glc
.
processes
[
processname
]
=
process
##################################
##################################
# WHEN
# WHEN
...
...
corepost/test/submodule_test.py
deleted
100644 → 0
View file @
a08b5e25
'''
A CorePost submodule that can be merged into the main CorePost Resource
'''
from
corepost.web
import
CorePost
from
corepost.enums
import
Http
submodule
=
CorePost
()
submodule
.
isLeaf
=
True
@
submodule
.
route
(
"/test"
,
Http
.
GET
)
def
submodule_get
(
request
,
**
kwargs
):
return
request
.
path
\ No newline at end of file
corepost/web.py
View file @
021581bb
...
@@ -96,7 +96,7 @@ class CorePost(Resource):
...
@@ -96,7 +96,7 @@ class CorePost(Resource):
'''
'''
isLeaf
=
True
isLeaf
=
True
def
__init__
(
self
):
def
__init__
(
self
,
path
=
''
):
'''
'''
Constructor
Constructor
'''
'''
...
@@ -104,6 +104,11 @@ class CorePost(Resource):
...
@@ -104,6 +104,11 @@ class CorePost(Resource):
self
.
__urls
=
defaultdict
(
dict
)
self
.
__urls
=
defaultdict
(
dict
)
self
.
__cachedUrls
=
defaultdict
(
dict
)
self
.
__cachedUrls
=
defaultdict
(
dict
)
self
.
__methods
=
{}
self
.
__methods
=
{}
self
.
__path
=
path
@
property
def
path
(
self
):
return
self
.
__path
def
__registerFunction
(
self
,
f
,
url
,
methods
,
accepts
,
produces
,
cache
):
def
__registerFunction
(
self
,
f
,
url
,
methods
,
accepts
,
produces
,
cache
):
if
f
not
in
self
.
__methods
.
values
():
if
f
not
in
self
.
__methods
.
values
():
...
@@ -116,7 +121,7 @@ class CorePost(Resource):
...
@@ -116,7 +121,7 @@ class CorePost(Resource):
self
.
__methods
[
url
]
=
f
self
.
__methods
[
url
]
=
f
def
route
(
self
,
url
,
methods
=
[]
,
accepts
=
MediaType
.
WILDCARD
,
produces
=
None
,
cache
=
True
):
def
route
(
self
,
url
,
methods
=
(
Http
.
GET
,)
,
accepts
=
MediaType
.
WILDCARD
,
produces
=
None
,
cache
=
True
):
"""Main decorator for registering REST functions """
"""Main decorator for registering REST functions """
def
wrap
(
f
):
def
wrap
(
f
):
self
.
__registerFunction
(
f
,
url
,
methods
,
accepts
,
produces
,
cache
)
self
.
__registerFunction
(
f
,
url
,
methods
,
accepts
,
produces
,
cache
)
...
...
setup.py
View file @
021581bb
...
@@ -16,7 +16,7 @@ def read(fname):
...
@@ -16,7 +16,7 @@ def read(fname):
setup
(
setup
(
name
=
"CorePost"
,
name
=
"CorePost"
,
version
=
"0.0.
2
"
,
version
=
"0.0.
3
"
,
author
=
"Jacek Furmankiewicz"
,
author
=
"Jacek Furmankiewicz"
,
author_email
=
"jacek99@gmail.com"
,
author_email
=
"jacek99@gmail.com"
,
description
=
(
"A Twisted Web REST micro-framework"
),
description
=
(
"A Twisted Web REST micro-framework"
),
...
@@ -37,7 +37,6 @@ setup(
...
@@ -37,7 +37,6 @@ setup(
],
],
install_requires
=
[
install_requires
=
[
'twisted>=11.0.0'
,
'twisted>=11.0.0'
,
'twisted.internet.processes>=1.0b1'
,
'httplib2>=0.7.1'
,
'httplib2>=0.7.1'
,
'freshen>=0.2'
,
'freshen>=0.2'
,
],
],
...
...
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