This commit is contained in:
Bernardo Heynemann 2012-03-09 14:02:27 -03:00
parent b45364ce92
commit 5c90b4e77e
5 changed files with 67 additions and 149 deletions

View file

@ -1,5 +1,5 @@
pyvows: db pyvows: db
@env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. pyvows --cover --cover_package=django_pyvows --cover_threshold=95 vows/ @env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. pyvows --cover --cover_package=django_pyvows --cover_threshold=95 vows/settings_vows.py
ci_test: ci_test:
@env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. python vows/sandbox/manage.py syncdb && pyvows --no_color --cover --cover_package=django_pyvows --cover_threshold=100 -r django_pyvows.coverage.xml -x vows/ @env PYTHONPATH=$$PYTHONPATH:vows/sandbox/:. python vows/sandbox/manage.py syncdb && pyvows --no_color --cover --cover_package=django_pyvows --cover_threshold=100 -r django_pyvows.coverage.xml -x vows/

View file

@ -10,7 +10,6 @@
import os import os
import re import re
from threading import local, current_thread
from pyvows import Vows from pyvows import Vows
from django.http import HttpRequest from django.http import HttpRequest
@ -37,13 +36,6 @@ class DjangoContext(Vows.Context):
self.ignore('get_settings', 'template', 'request', 'model', 'url', 'find_in_parent', self.ignore('get_settings', 'template', 'request', 'model', 'url', 'find_in_parent',
'start_environment', 'port', 'host', 'get_url', 'get', 'post') 'start_environment', 'port', 'host', 'get_url', 'get', 'post')
@property
def settings(self):
thread = current_thread()
if not hasattr(thread, 'settings'):
thread.settings = local()
return thread.settings
def setup(self): def setup(self):
DjangoContext.start_environment(self.get_settings()) DjangoContext.start_environment(self.get_settings())
@ -83,15 +75,16 @@ class DjangoContext(Vows.Context):
return path return path
class DjangoHTTPContext(DjangoContext): class DjangoHTTPContext(DjangoContext):
def start_server(self, host=None, port=None): def start_server(self, host=None, port=None, settings={}):
if not port: port = DEFAULT_PORT if not port: port = DEFAULT_PORT
if not host: host = DEFAULT_HOST if not host: host = DEFAULT_HOST
self.address = (host, port) self.address = (host, port)
self.server = DjangoServer(host, port) self.server = DjangoServer(host, port)
self.server.start(self.settings) self.server.start(settings)
def __init__(self, parent): def __init__(self, parent):
super(DjangoHTTPContext, self).__init__(parent) super(DjangoHTTPContext, self).__init__(parent)

View file

@ -8,130 +8,52 @@
# http://www.opensource.org/licenses/mit-license # http://www.opensource.org/licenses/mit-license
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com # Copyright (c) 2011 Rafael Caricio rafael@caricio.com
from threading import Thread, current_thread, local
from time import sleep
import sys from cherrypy import wsgiserver
import urllib2
from threading import Thread, local, current_thread
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from django.core.handlers.wsgi import WSGIHandler from django.core.handlers.wsgi import WSGIHandler
class WSGIRequestHandler(BaseHTTPRequestHandler): def make_response_thread(thread, settings):
"""A request handler that implements WSGI dispatching.""" if not hasattr(thread, 'settings'):
thread.settings = settings
@property def run_app(host, port):
def server_version(self): server = wsgiserver.CherryPyWSGIServer(
return 'pyVowsServer' (host, port),
WSGIHandler(),
server_name='tornado-pyvows',
numthreads = 1
)
def make_environ(self): my_thread = current_thread()
if '?' in self.path: my_thread.server = server
path_info, query = self.path.split('?', 1)
else:
path_info = self.path
query = ''
environ = { try:
'wsgi.version': (1, 0), server.start()
'wsgi.url_scheme': 'http', except KeyboardInterrupt:
'wsgi.input': self.rfile, server.stop()
'wsgi.errors': sys.stderr,
'wsgi.multithread': False,
'wsgi.multiprocess': False,
'wsgi.run_once': False,
'SERVER_SOFTWARE': self.server_version,
'REQUEST_METHOD': self.command,
'SCRIPT_NAME': '',
'PATH_INFO': urllib2.unquote(path_info),
'QUERY_STRING': query,
'CONTENT_TYPE': self.headers.get('Content-Type', ''),
'CONTENT_LENGTH': self.headers.get('Content-Length', ''),
'REMOTE_ADDR': self.client_address[0],
'REMOTE_PORT': self.client_address[1],
'SERVER_NAME': self.server.server_address[0],
'SERVER_PORT': str(self.server.server_address[1]),
'SERVER_PROTOCOL': self.request_version
}
for key, value in self.headers.items(): class DjangoServer(object):
key = 'HTTP_' + key.upper().replace('-', '_')
if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
environ[key] = value
return environ
def run_wsgi(self):
app = self.server.app
environ = self.make_environ()
headers_set = []
headers_sent = []
def write(data):
assert headers_set, 'write() before start_response'
if not headers_sent:
status, response_headers = headers_sent[:] = headers_set
code, msg = status.split(None, 1)
self.send_response(int(code), msg)
header_keys = set()
for key, value in response_headers:
self.send_header(key, value)
key = key.lower()
header_keys.add(key)
if 'content-length' not in header_keys:
self.close_connection = True
self.send_header('Connection', 'close')
if 'server' not in header_keys:
self.send_header('Server', self.version_string())
if 'date' not in header_keys:
self.send_header('Date', self.date_time_string())
self.end_headers()
assert type(data) is str, 'applications must write bytes'
self.wfile.write(data)
self.wfile.flush()
def start_response(status, response_headers, exc_info=None):
headers_set[:] = [status, response_headers]
return write
application_iter = app(environ, start_response)
try:
for data in application_iter:
write(data)
write('')
finally:
if hasattr(application_iter, 'close'):
application_iter.close()
application_iter = None
def handle_one_request(self):
self.raw_requestline = self.rfile.readline()
if self.parse_request():
return self.run_wsgi()
def log_request(self, *args, **kwargs):
pass
class DjangoServer(HTTPServer, object):
def __init__(self, host, port): def __init__(self, host, port):
HTTPServer.__init__(self, (host, int(port)), WSGIRequestHandler) self.host = host
self.app = WSGIHandler() self.port = port
def start(self, settings): def start(self, settings):
self.server_activate() self.thr = Thread(target=run_app, args=(self.host, self.port))
self.thr = Thread(target=self.make_response_thread, args=(getattr(settings, '__dict__', settings),))
self.thr.daemon = True self.thr.daemon = True
self.thr.start() self.thr.start()
def make_response_thread(self, settings): while not len(self.thr.server.requests._threads):
thread = current_thread() sleep(0.1)
if not hasattr(thread, 'settings'):
thread.settings = local() for _thread in self.thr.server.requests._threads:
for key, value in settings.items(): _thread.settings = hasattr(_thread, 'settings') and _thread.settings or local()
setattr(thread.settings, key, value) for k, v in settings.iteritems():
while True: setattr(_thread.settings, k, v)
self.handle_request()

View file

@ -44,6 +44,7 @@ django-pyvows are pyvows extensions to django web framework.
install_requires=[ install_requires=[
"pyvows", "pyvows",
"django", "django",
"cherrypy",
"httplib2" "httplib2"
], ],

View file

@ -23,51 +23,53 @@ class SettingsVows(DjangoContext):
def topic(self): def topic(self):
settings_tracker.install() settings_tracker.install()
class WhenImportFromDjangoConf(DjangoContext): #class WhenImportFromDjangoConf(DjangoContext):
def topic(self): #def topic(self):
from django.conf import settings #from django.conf import settings
return settings #return settings
def should_be_the_vows_settings(self, topic): #def should_be_the_vows_settings(self, topic):
expect(topic).to_be_instance_of(VowsSettings) #expect(topic).to_be_instance_of(VowsSettings)
class WhenIImportOnlyConfAndThenUseSettings(DjangoContext): #class WhenIImportOnlyConfAndThenUseSettings(DjangoContext):
def topic(self): #def topic(self):
from django import conf #from django import conf
return conf.settings #return conf.settings
def should_be_the_vows_settings(self, topic): #def should_be_the_vows_settings(self, topic):
expect(topic).to_be_instance_of(VowsSettings) #expect(topic).to_be_instance_of(VowsSettings)
class WhenIImportTheCompletePathAndThenUseSettings(DjangoContext): #class WhenIImportTheCompletePathAndThenUseSettings(DjangoContext):
def topic(self): #def topic(self):
import django.conf #import django.conf
return django.conf.settings #return django.conf.settings
def should_be_the_vows_settings(self, topic): #def should_be_the_vows_settings(self, topic):
expect(topic).to_be_instance_of(VowsSettings) #expect(topic).to_be_instance_of(VowsSettings)
class CannotSayHelloWithoutName(DjangoHTTPContext): #class CannotSayHelloWithoutName(DjangoHTTPContext):
def topic(self): #def topic(self):
self.settings.SAY_HELLO_WITHOUT_NAME = False #self.settings.SAY_HELLO_WITHOUT_NAME = False
self.start_server(port=9000) #self.start_server(port=9000)
return self.get('/say/') #return self.get('/say/')
def should_be_ok(self, (topic, content)): #def should_be_ok(self, (topic, content)):
expect(topic.status).to_equal(200) #expect(topic.status).to_equal(200)
def should_ask_for_my_name(self, (topic, content)): #def should_ask_for_my_name(self, (topic, content)):
expect(content).to_equal("What's your name?") #expect(content).to_equal("What's your name?")
class SayHelloWithoutName(DjangoHTTPContext): class SayHelloWithoutName(DjangoHTTPContext):
def topic(self): def topic(self):
self.settings.SAY_HELLO_WITHOUT_NAME = True #self.settings.SAY_HELLO_WITHOUT_NAME = True
self.start_server(port=9001) self.start_server(port=9001, settings={
'SAY_HELLO_WITHOUT_NAME': True
})
return self.get('/say/') return self.get('/say/')
def should_be_ok(self, (topic, content)): def should_be_ok(self, (topic, content)):