Commit 002ae350 authored by Denis Bilenko's avatar Denis Bilenko

initial commit

parents
syntax: glob
*~
*.pyc
*.orig
dist
gevent.egg-info
build
htmlreports
results.*.db
gevent/core.so
recursive-include greentest *.py *.crt *.key
recursive-include examples *.py
include MANIFEST.in
= eventlet =
Eventlet is a networking library written in Python. It achieves high
scalability by using non-blocking io while at the same time retaining
high programmer usability by using coroutines to make the non-blocking
io operations appear blocking at the source code level.
The wiki at http://wiki.secondlife.com/wiki/Eventlet is likely to be a
more current source of information than this README. Questions,
patches, and general discussion go to the eventlet mailing list:
https://lists.secondlife.com/cgi-bin/mailman/listinfo/eventletdev
== requirements ===
Eventlet runs on Python version 2.3 or greater, with the following dependenceis:
* http://cheeseshop.python.org/pypi/greenlet
* (if running python versions < 2.4) collections.py from the 2.4 distribution or later
== limitations ==
* Not enough test coverage -- the goal is 100%, but we are not there yet.
* Eventlet does not currently run on stackless using tasklets, though
it is a goal to do so in the future.
== getting started ==
% python
>>> from eventlet import api
>>> help(api)
Also, look at the examples in the examples directory.
== eventlet history ==
eventlet began life as Donovan Preston was talking to Bob Ippolito
about coroutine-based non-blocking networking frameworks in
Python. Most non-blocking frameworks require you to run the "main
loop" in order to perform all network operations, but Donovan wondered
if a library written using a trampolining style could get away with
transparently running the main loop any time i/o was required,
stopping the main loop once no more i/o was scheduled. Bob spent a few
days during PyCon 2005 writing a proof-of-concept. He named it
eventlet, after the coroutine implementation it used,
[[greenlet]]. Donovan began using eventlet as a light-weight network
library for his spare-time project Pavel, and also began writing some
unittests.
* http://svn.red-bean.com/bob/eventlet/trunk/
* http://soundfarmer.com/Pavel/trunk/
When Donovan started at Linden Lab in May of 2006, he added eventlet
as an svn external in the indra/lib/python directory, to be a
dependency of the yet-to-be-named [[backbone]] project (at the time,
it was named restserv). However, including eventlet as an svn external
meant that any time the externally hosted project had hosting issues,
Linden developers were not able to perform svn updates. Thus, the
eventlet source was imported into the linden source tree at the same
location, and became a fork.
Bob Ippolito has ceased working on eventlet and has stated his desire
for Linden to take its fork forward to the open source world as "the"
eventlet.
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Spawn multiple workers and collect their results"""
import gevent
from gevent import proc
from gevent import socket
def geturl(url):
c = socket.GreenSocket()
c.connect((url, 80))
print '%s connected' % url
gevent.sleep(0.05)
c.sendall('GET /\r\n\r\n')
print '%s sent request' % url
return c.recv(1024)
urls = ['www.google.com', 'www.yandex.ru', 'www.python.org']
jobs = [proc.spawn(geturl, x) for x in urls]
print 'spawned %s jobs' % len(jobs)
# collect the results from workers
results = proc.waitall(jobs)
# Note, that any exception in the workers will be reraised by waitall
# unless trap_errors argument specifies otherwise
for url, result in zip(urls, results):
print '%s: %s' % (url, repr(result)[:50])
#! /usr/bin/env python
# Copyright (c) 2007, Linden Research, Inc.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Simple server that listens on port 6000 and echos back every input to
the client. To try out the server, start it up by running this file.
Connect to it with:
telnet localhost 6000
You terminate your connection by terminating telnet (typically Ctrl-]
and then 'quit')
"""
import gevent
from gevent import socket
def handle_socket(reader, writer):
print "client connected"
while True:
# pass through every non-eof line
x = reader.readline()
if not x: break
writer.write(x)
print "echoed", x
print "client disconnected"
print "server socket listening on port 6000"
server = socket.tcp_listener(('0.0.0.0', 6000))
while True:
try:
new_sock, address = server.accept()
except KeyboardInterrupt:
break
# handle every new connection with a new coroutine
gevent.spawn(handle_socket, new_sock.makefile('r'), new_sock.makefile('w'))
"""This is a simple example of running a wsgi application with gevent.
For a more fully-featured server which supports multiple processes,
multiple threads, and graceful code reloading, see:
http://pypi.python.org/pypi/Spawning/
"""
from gevent import wsgi, socket
def hello_world(env, start_response):
if env['PATH_INFO'] != '/':
start_response('404 Not Found', [('Content-Type', 'text/plain')])
return ['Not Found\r\n']
else:
start_response('200 OK', [('Content-Type', 'text/plain')])
return ["Hello World!\r\n"]
wsgi.server(socket.tcp_listener(('', 8080)), hello_world)
import sys
import os
import traceback
from gevent import core
from py.magic import greenlet
version_info = (0, 9, 0)
__version__ = '0.9.0'
__all__ = ['Greenlet',
'getcurrent',
'GreenletExit',
'MAIN',
'TimeoutError',
'spawn',
'kill',
'get_hub',
'sleep',
'wait_reader',
'wait_writer',
'timeout',
'with_timeout']
libevent_version = core.get_version()
libevent_headers_version = core.get_header_version()
if libevent_version != libevent_headers_version:
import warnings
msg = "version mismatch: system libevent version is %r but compiled with %r" % (libevent_version, libevent_headers_version)
warnings.warn(msg, UserWarning, stacklevel=2)
_threadlocal = None
Greenlet = greenlet
getcurrent = greenlet.getcurrent
GreenletExit = greenlet.GreenletExit
MAIN = greenlet.getcurrent()
def timer(*args, **kwargs):
return core.timer(*args, **kwargs)
class TimeoutError(Exception):
"""Exception raised if an asynchronous operation times out"""
def spawn(function, *args, **kwargs):
"""Create a new greenlet that will run `function(*args)'.
The current greenlet won't be unscheduled. Keyword arguments aren't
supported (limitation of greenlet), use spawn() to work around that.
"""
g = Greenlet(lambda : function(*args, **kwargs))
g.parent = get_hub().greenlet
timer(0, g.switch)
return g
def spawn_later(seconds, function, *args, **kwargs):
"""Create a new greenlet that will run `function(*args)'.
The current greenlet won't be unscheduled. Keyword arguments aren't
supported (limitation of greenlet), use spawn() to work around that.
"""
g = Greenlet(lambda : function(*args, **kwargs))
g.parent = get_hub().greenlet
timer(seconds, g.switch)
return g
def kill(g, *throw_args):
timer(0, g.throw, *throw_args)
if getcurrent() is not get_hub().greenlet:
sleep(0)
def get_hub():
global _threadlocal
try:
hub = _threadlocal.hub
except AttributeError:
# do not import anything that can be monkey-patched at top level
import threading
_threadlocal = threading.local()
hub = _threadlocal.hub = Hub()
return hub
def sleep(seconds=0):
"""Yield control to another eligible coroutine until at least *seconds* have
elapsed.
*seconds* may be specified as an integer, or a float if fractional seconds
are desired. Calling sleep with *seconds* of 0 is the canonical way of
expressing a cooperative yield. For example, if one is looping over a
large list performing an expensive calculation without calling any socket
methods, it's a good idea to call ``sleep(0)`` occasionally; otherwise
nothing else will run.
"""
hub = get_hub()
assert hub.greenlet is not greenlet.getcurrent(), 'do not call blocking functions from the mainloop'
t = timer(seconds, greenlet.getcurrent().switch)
try:
hub.switch()
finally:
t.cancel()
class Hub(object):
def __init__(self):
self.greenlet = Greenlet(self.run)
self.keyboard_interrupt_signal = None
def switch(self):
cur = getcurrent()
assert cur is not self.greenlet, 'Cannot switch to MAINLOOP from MAINLOOP'
switch_out = getattr(cur, 'switch_out', None)
if switch_out is not None:
try:
switch_out()
except:
traceback.print_exception(*sys.exc_info())
if self.greenlet.dead:
self.greenlet = Greenlet(self.run)
return self.greenlet.switch()
def run(self, *args, **kwargs):
if self.keyboard_interrupt_signal is None:
self.keyboard_interrupt_signal = signal(2, MAIN.throw, KeyboardInterrupt)
while True:
result = core.dispatch()
if result>0:
return 'Hub.run() has finished because there are no events registered'
elif result<0:
return 'Hub.run() has finished because there was an error'
return result
def signal(signalnum, handler, *args, **kwargs):
def deliver_exception_to_MAIN():
try:
handler(*args, **kwargs)
except:
MAIN.throw(*sys.exc_info())
return core.signal(signalnum, deliver_exception_to_MAIN)
def _wait_helper(ev, fd, evtype):
current, timeout_exc = ev.arg
if evtype & core.EV_TIMEOUT:
current.throw(timeout_exc)
else:
current.switch(ev)
def wait_reader(fileno, timeout=-1, timeout_exc=TimeoutError):
evt = core.read(fileno, _wait_helper, timeout, (getcurrent(), timeout_exc))
try:
returned_ev = get_hub().switch()
assert evt is returned_ev, (evt, returned_ev)
finally:
evt.cancel()
def wait_writer(fileno, timeout=-1, timeout_exc=TimeoutError):
evt = core.write(fileno, _wait_helper, timeout, (getcurrent(), timeout_exc))
try:
returned_ev = get_hub().switch()
assert evt is returned_ev, (evt, returned_ev)
finally:
evt.cancel()
class _SilentException:
pass
class timeout(object):
"""Schedule an exception to raise in the current greenlet (TimeoutError by default).
Raise an exception in the block after timeout.
with timeout(seconds[, exc]):
... code block ...
Assuming code block is yielding (i.e. gives up control to the hub),
an exception provided in `exc' argument will be raised
(TimeoutError if `exc' is omitted).
When exc is None, code block is interrupted silently.
"""
def __init__(self, seconds, exception=TimeoutError):
if exception is None:
exception = _SilentException()
self.exception = exception
if seconds is None:
self.timeout = None
else:
self.timeout = timer(seconds, getcurrent().throw, exception)
def cancel(self):
if self.timeout is not None:
self.timeout.cancel()
def __repr__(self):
if self.timeout is not None:
return repr(self.timeout)
else:
return '<fake timeout>'
def __enter__(self):
return self
def __exit__(self, typ, value, tb):
self.cancel()
if typ is _SilentException and value is self.exception:
return True
def with_timeout(seconds, func, *args, **kwds):
"""Wrap a call to some (yielding) function with a timeout; if the called
function fails to return before the timeout, cancel it and return a flag
value.
seconds
(int or float) seconds before timeout occurs
func
the callable to execute with a timeout; must be one of the functions
that implicitly or explicitly yields
\*args, \*\*kwds
(positional, keyword) arguments to pass to *func*
timeout_value=
value to return if timeout occurs (default raise ``TimeoutError``)
**Returns**:
Value returned by *func* if *func* returns before *seconds*, else
*timeout_value* if provided, else raise ``TimeoutError``
**Raises**:
Any exception raised by *func*, and ``TimeoutError`` if *func* times out
and no ``timeout_value`` has been provided.
**Example**::
data = with_timeout(30, httpc.get, 'http://www.google.com/', timeout_value="")
Here *data* is either the result of the ``get()`` call, or the empty string if
it took too long to return. Any exception raised by the ``get()`` call is
passed through to the caller.
"""
# Recognize a specific keyword argument, while also allowing pass-through
# of any other keyword arguments accepted by func. Use pop() so we don't
# pass timeout_value through to func().
has_timeout_value = "timeout_value" in kwds
timeout_value = kwds.pop("timeout_value", None)
error = TimeoutError()
timer = timeout(seconds, error)
try:
try:
return func(*args, **kwds)
except TimeoutError, ex:
if ex is error and has_timeout_value:
return timeout_value
raise
finally:
timer.cancel()
_original_fork = os.fork
def fork():
result = _original_fork()
core.reinit()
return result
# @author Bob Ippolito
#
# Copyright (c) 2005-2006, Bob Ippolito
# Copyright (c) 2007, Linden Research, Inc.
# Copyright (c) 2008, Donovan Preston
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import socket
import sys
from code import InteractiveConsole
import gevent
try:
sys.ps1
except AttributeError:
sys.ps1 = '>>> '
try:
sys.ps2
except AttributeError:
sys.ps2 = '... '
class SocketConsole(gevent.Greenlet):
def __init__(self, desc, hostport, locals):
self.hostport = hostport
self.locals = locals
# mangle the socket
self.desc = desc
readline = desc.readline
self.old = {}
self.fixups = {
'softspace': 0,
'isatty': lambda: True,
'flush': lambda: None,
'readline': lambda *a: readline(*a).replace('\r\n', '\n'),
}
for key, value in self.fixups.iteritems():
if hasattr(desc, key):
self.old[key] = getattr(desc, key)
setattr(desc, key, value)
gevent.Greenlet.__init__(self)
def run(self):
try:
console = InteractiveConsole(self.locals)
console.interact()
finally:
self.switch_out()
self.finalize()
def switch(self, *args, **kw):
self.saved = sys.stdin, sys.stderr, sys.stdout
sys.stdin = sys.stdout = sys.stderr = self.desc
gevent.Greenlet.switch(self, *args, **kw)
def switch_out(self):
sys.stdin, sys.stderr, sys.stdout = self.saved
def finalize(self):
# restore the state of the socket
for key in self.fixups:
try:
value = self.old[key]
except KeyError:
delattr(self.desc, key)
else:
setattr(self.desc, key, value)
self.fixups.clear()
self.old.clear()
self.desc = None
print "backdoor closed to %s:%s" % self.hostport
def backdoor_server(server, locals=None):
print "backdoor listening on %s:%s" % server.getsockname()
try:
try:
while True:
(conn, (host, port)) = server.accept()
print "backdoor connected to %s:%s" % (host, port)
fl = conn.makeGreenFile("rw")
fl.newlines = '\n'
greenlet = SocketConsole(fl, (host, port), locals)
gevent.timer(0, greenlet.switch)
except socket.error, e:
# Broken pipe means it was shutdown
if e[0] != 32:
raise
finally:
server.close()
def backdoor((conn, addr), locals=None):
""" Use this with tcp_server like so:
tcp_server(tcp_listener(('127.0.0.1', 9000)), backdoor.backdoor, {})
"""
host, port = addr
print "backdoor to %s:%s" % (host, port)
fl = conn.makeGreenFile("rw")
fl.newlines = '\n'
greenlet = SocketConsole(fl, (host, port), locals)
gevent.timer(0, greenlet.switch)
if __name__ == '__main__':
from gevent.socket import tcp_server, tcp_listener
tcp_server(tcp_listener(('127.0.0.1', 9000)), backdoor, {})
This diff is collapsed.
#
# event.pyx
#
# libevent Python bindings
#
# Copyright (c) 2004 Dug Song <dugsong@monkey.org>
# Copyright (c) 2003 Martin Murray <murrayma@citi.umich.edu>
#
"""event library
This module provides a mechanism to execute a function when a
specific event on a file handle, file descriptor, or signal occurs,
or after a given time has passed.
"""
__author__ = ( 'Dug Song <dugsong@monkey.org>',
'Martin Murray <mmurray@monkey.org>' )
__copyright__ = ( 'Copyright (c) 2004 Dug Song',
'Copyright (c) 2003 Martin Murray' )
__license__ = 'BSD'
__url__ = 'http://monkey.org/~dugsong/pyevent/'
__version__ = '0.4+'
import sys
import traceback
DEF EVENT_INTERNAL_AVAILABLE=False
cdef extern from "libevent-internal.h":
pass
cdef extern from "sys/types.h":
ctypedef unsigned char u_char
cdef extern from "stdio.h":
void perror(char *s)
cdef extern from "Python.h":
void Py_INCREF(object o)
void Py_DECREF(object o)
object PyString_FromStringAndSize(char *v, int len)
object PyString_FromString(char *v)
int PyObject_AsCharBuffer(object obj, char **buffer, int *buffer_len)
ctypedef void (*event_handler)(int fd, short evtype, void *arg)
cdef extern from "event.h":
struct timeval:
unsigned int tv_sec
unsigned int tv_usec
struct event_t "event":
int ev_fd
int ev_flags
void *ev_arg
void* event_init()
int event_reinit(void *base)
char* event_get_version()
char* event_get_method()
void event_set(event_t *ev, int fd, short event, event_handler handler, void *arg)
void evtimer_set(event_t *ev, event_handler handler, void *arg)
int event_add(event_t *ev, timeval *tv)
int event_del(event_t *ev)
int event_dispatch() nogil
int event_loop(int loop) nogil
int event_pending(event_t *ev, short, timeval *tv)
int EVLOOP_ONCE
int EVLOOP_NONBLOCK
char* _EVENT_VERSION
IF EVENT_INTERNAL_AVAILABLE:
cdef extern from "libevent-internal.h":
struct event_base:
int event_count # counts number of total events
int event_count_active # counts number of active events
def _event_count():
cdef event_base* c = current_base
return c.event_count
def _event_count_active():
cdef event_base* c = current_base
return c.event_count_active
cdef extern from "libevent.h":
IF EVENT_INTERNAL_AVAILABLE:
event_base* current_base
ELSE:
void* current_base
EV_TIMEOUT = 0x01
EV_READ = 0x02
EV_WRITE = 0x04
EV_SIGNAL = 0x08
EV_PERSIST = 0x10
cdef void __event_handler(int fd, short evtype, void *arg) with gil:
cdef event ev = <event>arg
try:
ev._callback(ev, fd, evtype)
except:
traceback.print_exc()
try:
sys.stderr.write('Failed to execute callback for %r\n' % (ev, ))
except:
pass
finally:
if not event_pending(&ev.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL):
Py_DECREF(ev)
cdef class event:
"""event(callback, arg=None, evtype=0, handle=None) -> event object
Create a new event object with a user callback.
Arguments:
callback -- user callback with (ev, handle, evtype, arg) prototype
arg -- optional callback arguments
evtype -- bitmask of EV_READ or EV_WRITE, or EV_SIGNAL
handle -- for EV_READ or EV_WRITE, a file handle, descriptor, or socket
for EV_SIGNAL, a signal number
"""
cdef event_t ev
cdef object _callback, _arg
def __init__(self, short evtype, int handle, callback, arg=None):
self._callback = callback
self._arg = arg
cdef void* c_self = <void*>self
if evtype == 0 and not handle:
evtimer_set(&self.ev, __event_handler, c_self)
else:
event_set(&self.ev, handle, evtype, __event_handler, c_self)
property callback:
def __get__(self):
return self._callback
def __set__(self, new):
self._callback = new
property arg:
def __get__(self):
return self._arg
def __set__(self, new):
self._arg = new
property pending:
def __get__(self):
return event_pending(&self.ev, EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE, NULL)
def add(self, timeout=-1):
"""Add event to be executed after an optional timeout.
Arguments:
timeout -- seconds after which the event will be executed
"""
cdef timeval tv
cdef double c_timeout
if not event_pending(&self.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL):
Py_INCREF(self)
if timeout >= 0.0:
c_timeout = <double>timeout
tv.tv_sec = <long>c_timeout
tv.tv_usec = <unsigned int>((c_timeout - <double>tv.tv_sec) * 1000000.0)
event_add(&self.ev, &tv)
else:
event_add(&self.ev, NULL)
def cancel(self):
"""Remove event from the event queue."""
if event_pending(&self.ev, EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE, NULL):
event_del(&self.ev)
Py_DECREF(self)
def __dealloc__(self):
self.cancel()
def __repr__(self):
if self.pending:
pending = ' pending'
else:
pending = ''
return '<%s flags=0x%x, handle=%s, callback=%s, arg=%s%s>' % \
(type(self).__name__, self.ev.ev_flags, self.ev.ev_fd, self._callback, self._arg, pending)
cdef class read(event):
def __init__(self, int handle, callback, timeout=-1, arg=None):
event.__init__(self, EV_READ, handle, callback, arg)
self.add(timeout)
cdef class write(event):
def __init__(self, int handle, callback, timeout=-1, arg=None):
event.__init__(self, EV_WRITE, handle, callback, arg)
self.add(timeout)
cdef void __simple_handler(int fd, short evtype, void *arg) with gil:
cdef event ev = <event>arg
try:
args, kwargs = ev._arg
ev._callback(*args, **kwargs)
except:
traceback.print_exc()
try:
sys.stderr.write('Failed to execute callback for %r\n' % (ev, ))
except:
pass
finally:
if not event_pending(&ev.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL):
Py_DECREF(ev)
cdef class timer(event):
def __init__(self, float seconds, callback, *args, **kwargs):
self._callback = callback
self._arg = (args, kwargs)
evtimer_set(&self.ev, __simple_handler, <void*>self)
self.add(seconds)
cdef class signal(event):
def __init__(self, int signalnum, callback, *args, **kwargs):
self._callback = callback
self._arg = (args, kwargs)
event_set(&self.ev, signalnum, EV_SIGNAL|EV_PERSIST, __simple_handler, <void*>self)
self.add(-1)
def init():
"""Initialize event queue."""
event_init()
def reinit():
return event_reinit(current_base)
def dispatch():
"""Dispatch all events on the event queue.
Returns -1 on error, 0 on success, and 1 if no events are registered.
"""
cdef int ret
with nogil:
ret = event_dispatch()
if ret < 0:
perror("event_dispatch failed")
return ret
def loop(nonblock=False):
"""Dispatch all pending events on queue in a single pass.
Returns -1 on error, 0 on success, and 1 if no events are registered."""
cdef int flags, ret
flags = EVLOOP_ONCE
if nonblock:
flags = EVLOOP_ONCE|EVLOOP_NONBLOCK
with nogil:
ret = event_loop(flags)
if ret < 0:
perror("event_loop failed")
return ret
def get_version():
return event_get_version()
def get_header_version():
return _EVENT_VERSION
def get_method():
return event_get_method()
# XXX - make sure event queue is always initialized.
init()
This diff is collapsed.
struct event_base {
const void *evsel;
void *evbase;
int event_count; /* counts number of total events */
int event_count_active; /* counts number of active events */
int event_gotterm; /* Set to terminate loop */
int event_break; /* Set to terminate loop immediately */
/* active event management */
struct event_list **activequeues;
int nactivequeues;
};
extern void *current_base;
def patch_os():
from gevent import fork
import os
os.fork = fork
def patch_time():
from gevent import sleep
_time = __import__('time')
_time.sleep = sleep
def patch_thread():
from gevent import thread as green_thread
thread = __import__('thread')
thread.get_ident = green_thread.get_ident
thread.start_new_thread = green_thread.start_new_thread
thread.LockType = green_thread.LockType
thread.allocate_lock = green_thread.allocate_lock
thread.exit = green_thread.exit
if hasattr(green_thread, 'stack_size'):
thread.stack_size = green_thread.stack_size
def patch_socket():
from gevent.socket import GreenSocket, fromfd, wrap_ssl, socketpair
_socket = __import__('socket')
_socket.socket = GreenSocket
_socket.fromfd = fromfd
_socket.ssl = wrap_ssl
_socket.socketpair = socketpair
# also gethostbyname, getaddrinfo
def patch_select():
from gevent.select import select
_select = __import__('select')
globals()['_select_select'] = _select.select
_select.select = select
def patch_all(socket=True, time=True, select=True, thread=True, os=True):
# order is important
if os:
patch_os()
if time:
patch_time()
if thread:
patch_thread()
if socket:
patch_socket()
if select:
patch_select()
# XXX patch unittest to count switches and detect event_count and run the standard tests 2 hour
# make makefile() return GreenFile. since it uses socket's buffer, while _fileobject creates a new one 2 hour
# probably make GreenSocket be also a file and makefile() just increases refcount and returns self
if __name__=='__main__':
import sys
modules = [x.replace('patch_', '') for x in globals().keys() if x.startswith('patch_') and x!='patch_all']
script_help = """gevent.monkey - monkey patch the standard modules to use gevent.
USAGE: python -m gevent.monkey [MONKEY OPTIONS] script [SCRIPT OPTIONS]
If no OPTIONS present, monkey patches the all modules it can patch.
You can exclude a module with --no-module, e.g. --no-thread. You can
specify a module to patch with --module, e.g. --socket. In this case
only those mentioned on the command line will be patched.
MONKEY OPTIONS: --verbose %s""" % ', '.join('--[no-]%s' % m for m in modules)
args = {}
argv = sys.argv[1:]
verbose = False
while argv and argv[0].startswith('--'):
option = argv[0][2:]
if option == 'verbose':
verbose = True
elif option.startswith('no-') and option.replace('no-', '') in modules:
args[option[3:]] = False
elif option not in modules:
args[option] = True
else:
sys.exit(script_help + '\n\n' + 'Cannot patch %r' % option)
del argv[0]
if verbose:
sys.stderr.write('gevent.monkey.patch_all(%s)\n' % ', '.join('%s=%s' % item for item in args.items()))
patch_all(**args)
if argv:
sys.argv = argv
execfile(sys.argv[0])
else:
print script_help
This diff is collapsed.
from __future__ import with_statement
from Queue import Full, Empty
import gevent
from gevent import coros
class Queue(object):
"""Create a queue object with a given maximum size.
If maxsize is <= 0, the queue size is infinite.
"""
def __init__(self, maxsize=0):
if maxsize <= 0:
self.q = coros.Queue()
else:
self.q = coros.Channel(maxsize)
def qsize(self):
"""Return the size of the queue."""
return len(self.q)
def empty(self):
"""Return True if the queue is empty, False otherwise."""
return not bool(self.q)
def full(self):
"""Return True if the queue is full, False otherwise."""
return self.q.full()
def put(self, item, block=True, timeout=None):
"""Put an item into the queue.
If optional args 'block' is true and 'timeout' is None (the default),
block if necessary until a free slot is available. If 'timeout' is
a positive number, it blocks at most 'timeout' seconds and raises
the Full exception if no free slot was available within that time.
Otherwise ('block' is false), put an item on the queue if a free slot
is immediately available, else raise the Full exception ('timeout'
is ignored in that case).
"""
if block:
if timeout is None:
self.q.send(item)
else:
if timeout < 0:
raise ValueError("'timeout' must be a positive number")
with timeout(timeout, Full):
return self.q.wait()
else:
if self.q.full():
raise Full
else:
self.q.send(item)
def put_nowait(self, item):
"""Put an item into the queue without blocking.
Only enqueue the item if a free slot is immediately available.
Otherwise raise the Full exception.
"""
self.q.put(False)
def get(self, block=True, timeout=None):
"""Remove and return an item from the queue.
If optional args 'block' is true and 'timeout' is None (the default),
block if necessary until an item is available. If 'timeout' is
a positive number, it blocks at most 'timeout' seconds and raises
the Empty exception if no item was available within that time.
Otherwise ('block' is false), return an item if one is immediately
available, else raise the Empty exception ('timeout' is ignored
in that case).
"""
if block:
if timeout is None:
return self.q.wait()
elif timeout < 0:
raise ValueError("'timeout' must be a positive number")
else:
with gevent.timeout(timeout, Empty):
return self.q.wait()
else:
if not self.q:
raise Empty
else:
return self.q.wait()
def get_nowait(self):
"""Remove and return an item from the queue without blocking.
Only get an item if one is immediately available. Otherwise
raise the Empty exception.
"""
return self.get(False)
import gevent
from gevent import core
def get_fileno(obj):
try:
f = obj.fileno
except AttributeError:
if not isinstance(obj, int):
raise TypeError("Must be int of have file() method: %r" % (obj, ))
return obj
else:
return f()
def select(read_list, write_list, error_list, t=None):
hub = gevent.get_hub()
t = None
current = gevent.getcurrent()
assert hub.greenlet is not current, 'do not call blocking functions from the mainloop'
allevents = []
def callback(ev, fd, evtype):
if evtype & core.EV_READ:
current.switch(([ev.arg], [], []))
elif evtype & core.EV_WRITE:
current.switch(([], [ev.arg], []))
else:
current.switch(([], [], []))
for r in read_list:
allevents.append(core.read(get_fileno(r), callback, arg=r))
for w in write_list:
allevents.append(core.write(get_fileno(r), callback, arg=w))
if t is not None:
t = gevent.timeout(t)
try:
return hub.switch()
except gevent.TimeoutError:
return [], [], []
finally:
for evt in allevents:
evt.cancel()
if t is not None:
t.cancel()
This diff is collapsed.
"""implements standard module 'thread' with greenlets"""
__thread = __import__('thread')
from gevent import spawn, getcurrent, GreenletExit
from gevent.coros import Semaphore as LockType
error = __thread.error
def get_ident(gr=None):
if gr is None:
return id(getcurrent())
else:
return id(gr)
def start_new_thread(function, args=(), kwargs={}):
g = spawn(function, *args, **kwargs)
return get_ident(g)
def allocate_lock():
return LockType(1)
def exit():
raise GreenletExit
if hasattr(__thread, 'stack_size'):
_original_stack_size = __thread.stack_size
def stack_size(size=None):
if size is None:
return _original_stack_size()
if size > _original_stack_size():
return _original_stack_size(size)
else:
pass
# not going to decrease stack_size, because otherwise other greenlets in this thread will suffer
# XXX interrupt_main
This diff is collapsed.
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# package is named greentest, not test, so it won't be confused with test in stdlib
import sys
import os
import errno
import unittest
import gevent
disabled_marker = '-*-*-*-*-*- disabled -*-*-*-*-*-'
def exit_disabled():
sys.exit(disabled_marker)
def exit_unless_25():
if sys.version_info[:2]<(2, 5):
exit_disabled()
class TestCase(unittest.TestCase):
__timeout__ = 1
__switch_check__ = True
def disable_switch_check(self):
self._switch_count = None
def setUp(self):
from gevent import core
gevent.sleep(0) # switch at least once to setup signal handlers
if hasattr(core, '_event_count'):
self._event_count = (core._event_count(), core._event_count_active())
self._switch_count = gevent.get_hub().switch_count
self._timer = gevent.timeout(self.__timeout__, RuntimeError('test is taking too long'))
def tearDown(self):
if hasattr(self, '_timer'):
self._timer.cancel()
if self.__switch_check__ and self._switch_count is not None and gevent.get_hub().switch_count <= self._switch_count:
sys.stderr.write('WARNING: %s.%s did not switch\n' % (type(self).__name__, self._testMethodName))
from gevent import core
if hasattr(core, '_event_count'):
event_count = (core._event_count(), core._event_count_active())
if event_count > self._event_count:
args = (type(self).__name__, self._testMethodName, self._event_count, event_count)
sys.stderr.write('WARNING: %s.%s event count was %s, now %s\n' % args)
gevent.sleep(0.1)
else:
sys.stderr.write('WARNING: %s.setUp does not call base class setUp\n' % (type(self).__name__, ))
def find_command(command):
for dir in os.getenv('PATH', '/usr/bin:/usr/sbin').split(os.pathsep):
p = os.path.join(dir, command)
if os.access(p, os.X_OK):
return p
raise IOError(errno.ENOENT, 'Command not found: %r' % command)
main = unittest.main
_original_Hub = gevent.Hub
class CountingHub(_original_Hub):
switch_count = 0
def switch(self):
self.switch_count += 1
return _original_Hub.switch(self)
gevent.Hub = CountingHub
# @author Donovan Preston
#
# Copyright (c) 2006-2007, Linden Research, Inc.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import os
import os.path
from greentest import TestCase, main
import gevent
from gevent import socket
class TestApi(TestCase):
mode = 'static'
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
def test_tcp_listener(self):
self.disable_switch_check()
sock = socket.tcp_listener(('0.0.0.0', 0))
assert sock.getsockname()[0] == '0.0.0.0'
sock.close()
def test_connect_tcp(self):
def accept_once(listenfd):
try:
conn, addr = listenfd.accept()
fd = conn.makeGreenFile()
conn.close()
fd.write('hello\n')
fd.close()
finally:
listenfd.close()
server = socket.tcp_listener(('0.0.0.0', 0))
g = gevent.spawn(accept_once, server)
try:
client = socket.connect_tcp(('127.0.0.1', server.getsockname()[1]))
fd = client.makeGreenFile()
client.close()
assert fd.readline() == 'hello\n'
assert fd.read() == ''
fd.close()
finally:
gevent.kill(g)
def test_connect_ssl(self):
def accept_once(listenfd):
try:
conn, addr = listenfd.accept()
fl = conn.makeGreenFile('w')
fl.write('hello\r\n')
fl.close()
conn.close()
finally:
listenfd.close()
server = socket.ssl_listener(('0.0.0.0', 0),
self.certificate_file,
self.private_key_file)
gevent.spawn(accept_once, server)
client = socket.wrap_ssl(
socket.connect_tcp(('127.0.0.1', server.getsockname()[1])))
client = client.makeGreenFile()
assert client.readline() == 'hello\r\n'
assert client.read() == ''
client.close()
def test_server(self):
connected = []
server = socket.tcp_listener(('0.0.0.0', 0))
bound_port = server.getsockname()[1]
current = gevent.getcurrent()
def accept_twice((conn, addr)):
connected.append(True)
conn.close()
if len(connected) == 2:
#server.close()
# it's no longer possible with gevent to kill accept() loop by closing the listening socket
# (the regular sockets also don't have this feature)
# however, it's also not necessary, as it's as easy to kill it directly:
gevent.kill(current, socket.error(32, 'broken pipe'))
g1 = gevent.spawn(socket.connect_tcp, ('127.0.0.1', bound_port))
g2 = gevent.spawn(socket.connect_tcp, ('127.0.0.1', bound_port))
try:
socket.tcp_server(server, accept_twice)
finally:
gevent.sleep(0)
assert len(connected) == 2
def test_001_trampoline_timeout(self):
server = socket.tcp_listener(('0.0.0.0', 0))
bound_port = server.getsockname()[1]
try:
desc = socket.GreenSocket()
desc.connect(('127.0.0.1', bound_port))
gevent.wait_reader(desc.fileno(), timeout=0.1)
except gevent.TimeoutError:
pass # test passed
else:
assert False, "Didn't timeout"
def test_timeout_cancel(self):
server = socket.tcp_listener(('0.0.0.0', 0))
bound_port = server.getsockname()[1]
def client_connected((conn, addr)):
conn.close()
server_greenlet = gevent.getcurrent()
def go():
desc = socket.GreenSocket()
desc.connect(('127.0.0.1', bound_port))
try:
gevent.wait_reader(desc.fileno(), timeout=0.1)
except gevent.TimeoutError:
assert False, "Timed out"
gevent.kill(server_greenlet, socket.error(32, 'broken error'))
desc.close()
g = gevent.spawn(go)
try:
socket.tcp_server(server, client_connected)
except:
gevent.kill(g)
raise
finally:
gevent.sleep(0)
def test_timeout_and_final_write(self):
# This test verifies that a write on a socket that we've
# stopped listening for doesn't result in an incorrect switch
rpipe, wpipe = os.pipe()
rfile = os.fdopen(rpipe,"r",0)
wrap_rfile = socket.GreenPipe(rfile)
wfile = os.fdopen(wpipe,"w",0)
wrap_wfile = socket.GreenPipe(wfile)
def sender(evt):
gevent.sleep(0.02)
wrap_wfile.write('hi')
evt.send('sent via event')
from gevent import coros
evt = coros.event()
gevent.spawn(sender, evt)
try:
# try and get some data off of this pipe
# but bail before any is sent
gevent.timeout(0.01)
_c = wrap_rfile.read(1)
self.fail()
except gevent.TimeoutError:
pass
result = evt.wait()
self.assertEquals(result, 'sent via event')
if __name__ == '__main__':
main()
# @author Donovan Preston, Ryan Williams
#
# Copyright (c) 2000-2007, Linden Research, Inc.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from greentest import TestCase, main
import gevent
from gevent import coros
class TestEvent(TestCase):
mode = 'static'
def setUp(self):
# raise an exception if we're waiting forever
self._cancel_timeout = gevent.timeout(1, RuntimeError('test takes too long'))
def tearDown(self):
self._cancel_timeout.cancel()
def test_waiting_for_event(self):
evt = coros.event()
value = 'some stuff'
def send_to_event():
evt.send(value)
gevent.spawn(send_to_event)
self.assertEqual(evt.wait(), value)
def test_multiple_waiters(self):
evt = coros.event()
value = 'some stuff'
results = []
def wait_on_event(i_am_done):
evt.wait()
results.append(True)
i_am_done.send()
waiters = []
count = 5
for i in range(count):
waiters.append(coros.event())
gevent.spawn(wait_on_event, waiters[-1])
evt.send()
for w in waiters:
w.wait()
self.assertEqual(len(results), count)
def test_reset(self):
evt = coros.event()
# calling reset before send should throw
self.assertRaises(AssertionError, evt.reset)
value = 'some stuff'
def send_to_event():
evt.send(value)
gevent.spawn(send_to_event)
self.assertEqual(evt.wait(), value)
# now try it again, and we should get the same exact value,
# and we shouldn't be allowed to resend without resetting
value2 = 'second stuff'
self.assertRaises(AssertionError, evt.send, value2)
self.assertEqual(evt.wait(), value)
# reset and everything should be happy
evt.reset()
def send_to_event2():
evt.send(value2)
gevent.spawn(send_to_event2)
self.assertEqual(evt.wait(), value2)
def test_double_exception(self):
evt = coros.event()
# send an exception through the event
evt.send(exc=RuntimeError('from test_double_exception'))
self.assertRaises(RuntimeError, evt.wait)
evt.reset()
# shouldn't see the RuntimeError again
gevent.timeout(0.001, gevent.TimeoutError('from test_double_exception'))
self.assertRaises(gevent.TimeoutError, evt.wait)
if __name__ == '__main__':
main()
#!/usr/bin/python
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import sys
import os
import sqlite3
import glob
REPO_URL = 'http://bitbucket.org/denis/gevent'
hubs_order = ['poll', 'selects', 'libevent', 'libev', 'twistedr/selectreactor', 'twistedr/pollreactor', 'twistedr/epollreactor']
def make_table(database):
c = sqlite3.connect(database)
res = c.execute(('select command_record.id, testname, hub, runs, errors, fails, '
'timeouts, exitcode, stdout from parsed_command_record join '
'command_record on parsed_command_record.id=command_record.id ')).fetchall()
table = {} # testname -> hub -> test_result (runs, errors, fails, timeouts)
tests = set()
for id, testname, hub, runs, errors, fails, timeouts, exitcode, stdout in res:
tests.add(testname)
test_result = TestResult(runs, errors, fails, timeouts, exitcode, id, stdout)
table.setdefault(testname, {})[hub] = test_result
return table, sorted(tests)
def calc_hub_stats(table):
hub_stats = {} # hub -> cumulative test_result
for testname in table:
for hub in table[testname]:
test_result = table[testname][hub]
hub_stats.setdefault(hub, TestResult(0,0,0,0)).__iadd__(test_result)
hubs = hub_stats.items()
hub_names = sorted(hub_stats.keys())
def get_order(hub):
try:
return hubs_order.index(hub)
except ValueError:
return 100 + hub_names.index(hub)
hubs.sort(key=lambda (hub, stats): get_order(hub))
return hub_stats, [x[0] for x in hubs]
class TestResult:
def __init__(self, runs, errors, fails, timeouts, exitcode=None, id=None, output=None):
self.runs = max(runs, 0)
self.errors = max(errors, 0)
self.fails = max(fails, 0)
self.timeouts = max(timeouts, 0)
self.exitcode = exitcode
self.id = id
self.output = output
@property
def passed(self):
return max(0, self.runs - self.errors - self.fails)
@property
def failed(self):
return self.errors + self.fails
@property
def total(self):
return self.runs + self.timeouts
@property
def percentage(self):
return float(self.passed) / self.total
def __iadd__(self, other):
self.runs += other.runs
self.errors += other.errors
self.fails += other.fails
self.timeouts += other.timeouts
if self.exitcode != other.exitcode:
self.exitcode = None
self.id = None
self.output = None
def color(self):
if self.id is None:
return 'white'
if self.timeouts or self.exitcode in [7, 9, 10]:
return 'red'
elif self.errors or self.fails or self.exitcode:
return 'yellow'
else:
return '"#72ff75"'
def warnings(self):
r = []
if not self.failed and not self.timeouts:
if self.exitcode in [7, 9, 10]:
r += ['TIMEOUT']
if self.exitcode:
r += ['exitcode=%s' % self.exitcode]
if self.output is not None:
output = self.output.lower()
warning = output.count('warning')
if warning:
r += ['%s warnings' % warning]
tracebacks = output.count('traceback')
if tracebacks:
r += ['%s tracebacks' % tracebacks]
return r
def text(self):
errors = []
if self.fails:
errors += ['%s failed' % self.fails]
if self.errors:
errors += ['%s raised' % self.errors]
if self.timeouts:
errors += ['%s timeout' % self.timeouts]
errors += self.warnings()
if self.id is None:
errors += ['<hr>%s total' % self.total]
return '\n'.join(["%s passed" % self.passed] + errors).replace(' ', '&nbsp;')
# shorter passed/failed/raised/timeout
def text_short(self):
r = '%s/%s/%s' % (self.passed, self.failed, self.timeouts)
if self.warnings():
r += '\n' + '\n'.join(self.warnings()).replace(' ', '&nbsp;')
return r
def format(self):
text = self.text().replace('\n', '<br>\n')
if self.id is None:
valign = 'bottom'
else:
text = '<a class="x" href="%s.txt">%s</a>' % (self.id, text)
valign = 'center'
return '<td align=center valign=%s bgcolor=%s>%s</td>' % (valign, self.color(), text)
def format_testname(changeset, test):
return '<a href="%s/src/%s/greentest/%s">%s</a>' % (REPO_URL, changeset, test, test)
def format_table(table, hubs, tests, hub_stats, changeset):
r = '<table border=1>\n<tr>\n<td/>\n'
for hub in hubs:
r += '<td align=center>%s</td>\n' % hub
r += '</tr>\n'
r += '<tr><td>Total</td>'
for hub in hubs:
test_result = hub_stats.get(hub)
if test_result is None:
r += '<td align=center bgcolor=gray>no data</td>'
else:
r += test_result.format() + '\n'
r += '</tr>'
r += '<tr><td colspan=%s/></tr>' % (len(hubs)+1)
for test in tests:
r += '<tr><td>%s</td>' % format_testname(changeset, test)
for hub in hubs:
test_result = table[test].get(hub)
if test_result is None:
r += '<td align=center bgcolor=gray>no data</td>'
else:
r += test_result.format() + '\n'
r += '</tr>'
r += '</table>'
return r
def format_header(rev, changeset, pyversion):
result = '<table width=99%%><tr><td>'
url = '%s/changeset/%s' % (REPO_URL, changeset)
result += '<a href="%s">Eventlite changeset %s: %s</a>' % (url, rev, changeset)
result += '</td><tr><tr><td>Python version: %s</td><tr></table><p>' % pyversion
return result
def format_html(table, rev, changeset, pyversion):
r = '<html><head><style type="text/css">a.x {color: black; text-decoration: none;} a.x:hover {text-decoration: underline;} </style></head><body>'
r += format_header(rev, changeset, pyversion)
r += table
r += '</body></html>'
return r
def generate_raw_results(path, database):
c = sqlite3.connect(database)
res = c.execute('select id, stdout from command_record').fetchall()
for id, out in res:
file(os.path.join(path, '%s.txt' % id), 'w').write(out.encode('utf-8'))
sys.stderr.write('.')
sys.stderr.write('\n')
def main(db):
full_changeset = '.'.join(db.split('.')[1:-1])
rev, changeset, pyversion = full_changeset.split('_')
table, tests = make_table(db)
hub_stats, hubs = calc_hub_stats(table)
report = format_html(format_table(table, hubs, tests, hub_stats, changeset), rev, changeset, pyversion)
path = '../htmlreports/%s' % full_changeset
try:
os.makedirs(path)
except OSError, ex:
if 'File exists' not in str(ex):
raise
file(path + '/index.html', 'w').write(report)
generate_raw_results(path, db)
if __name__=='__main__':
if not sys.argv[1:]:
latest_db = sorted(glob.glob('results.*.db'), key=lambda f: os.stat(f).st_mtime)[-1]
print latest_db
sys.argv.append(latest_db)
for db in sys.argv[1:]:
main(db)
# Copyright (c) 2006-2007, Linden Research, Inc.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from greentest import TestCase, main
import gevent
from gevent import socket
class TestGreenIo(TestCase):
def test_close_with_makefile(self):
def accept_close_early(listener):
# verify that the makefile and the socket are truly independent
# by closing the socket prior to using the made file
try:
conn, addr = listener.accept()
fd = conn.makeGreenFile()
conn.close()
fd.write('hello\n')
fd.close()
self.assertRaises(socket.error, fd.write, 'a')
self.assertRaises(socket.error, conn.send, 'b')
finally:
listener.close()
def accept_close_late(listener):
# verify that the makefile and the socket are truly independent
# by closing the made file and then sending a character
try:
conn, addr = listener.accept()
fd = conn.makeGreenFile()
fd.write('hello')
fd.close()
conn.send('\n')
conn.close()
self.assertRaises(socket.error, fd.write, 'a')
self.assertRaises(socket.error, conn.send, 'b')
finally:
listener.close()
def did_it_work(server):
client = socket.connect_tcp(('127.0.0.1', server.getsockname()[1]))
fd = client.makeGreenFile()
client.close()
assert fd.readline() == 'hello\n'
assert fd.read() == ''
fd.close()
server = socket.tcp_listener(('0.0.0.0', 0))
killer = gevent.spawn(accept_close_early, server)
did_it_work(server)
gevent.kill(killer)
server = socket.tcp_listener(('0.0.0.0', 0))
killer = gevent.spawn(accept_close_late, server)
did_it_work(server)
gevent.kill(killer)
def test_del_closes_socket(self):
timer = gevent.timeout(0.5)
def accept_once(listener):
# delete/overwrite the original conn
# object, only keeping the file object around
# closing the file object should close everything
try:
conn, addr = listener.accept()
conn = conn.makeGreenFile()
conn.write('hello\n')
conn.close()
self.assertRaises(socket.error, conn.write, 'a')
finally:
listener.close()
server = socket.tcp_listener(('0.0.0.0', 0))
killer = gevent.spawn(accept_once, server)
client = socket.connect_tcp(('127.0.0.1', server.getsockname()[1]))
fd = client.makeGreenFile()
client.close()
assert fd.read() == 'hello\n'
assert fd.read() == ''
timer.cancel()
if __name__ == '__main__':
main()
#!/usr/bin/python
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import sys
import os
import traceback
import sqlite3
import re
import glob
def parse_stdout(s):
argv = re.search('^===ARGV=(.*?)$', s, re.M).group(1)
argv = argv.split()
testname = argv[-1]
del argv[-1]
hub = None
reactor = None
while argv:
if argv[0]=='--hub':
hub = argv[1]
del argv[0]
del argv[0]
elif argv[0]=='--reactor':
reactor = argv[1]
del argv[0]
del argv[0]
else:
del argv[0]
if reactor is not None:
hub += '/%s' % reactor
return testname, hub
greentest_delim = '----------------------------------------------------------------------'
def parse_greentest_output(s):
s = s[s.rindex(greentest_delim)+len(greentest_delim):]
num = int(re.search('^Ran (\d+) test.*?$', s, re.M).group(1))
ok = re.search('^OK$', s, re.M)
error, fail, timeout = 0, 0, 0
failed_match = re.search(r'^FAILED \((?:failures=(?P<f>\d+))?,? ?(?:errors=(?P<e>\d+))?\)$', s, re.M)
ok_match = re.search('^OK$', s, re.M)
if failed_match:
assert not ok_match, (ok_match, s)
fail = failed_match.group('f')
error = failed_match.group('e')
fail = int(fail or '0')
error = int(error or '0')
else:
assert ok_match, `s`
timeout_match = re.search('^===disabled because of timeout: (\d+)$', s, re.M)
if timeout_match:
timeout = int(timeout_match.group(1))
return num, error, fail, timeout
def main(db):
c = sqlite3.connect(db)
c.execute('''create table if not exists parsed_command_record
(id integer not null unique,
testname text,
hub text,
runs integer,
errors integer,
fails integer,
timeouts integer,
error_names text,
fail_names text,
timeout_names text)''')
c.commit()
parse_error = 0
SQL = ('select command_record.id, command, stdout, exitcode from command_record '
'where not exists (select * from parsed_command_record where '
'parsed_command_record.id=command_record.id)')
for row in c.execute(SQL).fetchall():
id, command, stdout, exitcode = row
try:
testname, hub = parse_stdout(stdout)
if greentest_delim in stdout:
runs, errors, fails, timeouts = parse_greentest_output(stdout)
else:
if exitcode == 0:
runs, errors, fails, timeouts = 1,0,0,0
if exitcode == 7:
runs, errors, fails, timeouts = 0,0,0,1
elif exitcode:
runs, errors, fails, timeouts = 1,1,0,0
except Exception:
parse_error += 1
sys.stderr.write('Failed to parse id=%s\n' % id)
print repr(stdout)
traceback.print_exc()
else:
print id, hub, testname, runs, errors, fails, timeouts
c.execute('insert into parsed_command_record '
'(id, testname, hub, runs, errors, fails, timeouts) '
'values (?, ?, ?, ?, ?, ?, ?)',
(id, testname, hub, runs, errors, fails, timeouts))
c.commit()
if __name__=='__main__':
if not sys.argv[1:]:
latest_db = sorted(glob.glob('results.*.db'), key=lambda f: os.stat(f).st_mtime)[-1]
print latest_db
sys.argv.append(latest_db)
for db in sys.argv[1:]:
main(db)
execfile('generate_report.py')
#!/usr/bin/python
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Run the program and record stdout/stderr/exitcode into the database results.rev_changeset.db
Usage: %prog program [args]
"""
import sys
import os
import codecs
try:
import sqlite3
except ImportError:
import pysqlite2.dbapi2 as sqlite3
import warnings
from greentest import disabled_marker
warnings.simplefilter('ignore')
PYTHON_VERSION = '%s.%s.%s' % sys.version_info[:3]
COMMAND_CHANGESET = r"hg log -r tip 2> /dev/null | grep changeset"
def record(changeset, argv, stdout, returncode):
c = sqlite3.connect('results.%s_%s.db' % (changeset, PYTHON_VERSION))
c.execute('''create table if not exists command_record
(id integer primary key autoincrement,
command text,
stdout text,
exitcode integer)''')
c.execute('insert into command_record (command, stdout, exitcode)'
'values (?, ?, ?)', (`argv`, stdout, returncode))
c.commit()
def main():
argv = sys.argv[1:]
if argv[0]=='-d':
debug = True
del argv[0]
else:
debug = False
try:
changeset = os.popen(COMMAND_CHANGESET).readlines()[0].replace('changeset:', '').strip().replace(':', '_')
except Exception:
changeset = 'revision_unknown'
output_name = os.tmpnam()
arg = ' '.join(argv) + ' &> %s' % output_name
print arg
returncode = os.system(arg)>>8
print arg, 'finished with code', returncode
stdout = codecs.open(output_name, mode='r', encoding='utf-8', errors='replace').read().replace('\x00', '?')
if not debug:
if returncode==1:
pass
elif returncode==8 and disabled_marker in stdout:
pass
else:
record(changeset, argv, stdout, returncode)
os.unlink(output_name)
sys.exit(returncode)
if __name__=='__main__':
main()
#!/usr/bin/python
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Run all the tests"""
import sys
import os
import random
from glob import glob
from optparse import OptionParser
from time import time
COMMAND = sys.executable + ' ./record_results.py ' + sys.executable + ' ./with_timeout.py %(test)s'
PARSE_PERIOD = 10
def w(s):
sys.stderr.write("%s\n" % (s, ))
def enum_tests():
tests = []
tests += glob('test_*.py')
tests += glob('*_test.py')
tests = set(tests) - set(['test_support.py'])
return tests
def cmd(program):
w(program)
res = os.system(program)>>8
w(res)
if res==1:
sys.exit(1)
return res
def main():
parser = OptionParser()
parser.add_option('--skip', action='store_true', default=False,
help="Run all the tests except those provided on command line")
parser.add_option('--dry-run')
options, tests = parser.parse_args()
if options.skip:
tests = enum_tests() - set(tests)
elif not tests:
tests = enum_tests()
tests = list(tests)
random.shuffle(tests)
print 'tests: %s' % ','.join(tests)
if options.dry_run:
return
last_time = time()
for test in tests:
w(test)
cmd(COMMAND % locals())
if time()-last_time>PARSE_PERIOD:
os.system('./parse_results.py')
last_time = time()
os.system('./parse_results.py')
if __name__=='__main__':
main()
# Copyright (c) 2008 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import greentest
import gevent
DELAY = 0.1
class Test(greentest.TestCase):
def test_killing_dormant(self):
state = []
def test():
try:
state.append('start')
gevent.sleep(DELAY)
except:
state.append('except')
# catching GreenletExit
pass
# when switching to hub, hub makes itself the parent of this greenlet,
# thus after the function's done, the control will go to the parent
# QQQ why the first sleep is not enough?
gevent.sleep(0)
state.append('finished')
g = gevent.spawn(test)
gevent.sleep(DELAY/2)
assert state == ['start'], state
gevent.kill(g)
# will not get there, unless switching is explicitly scheduled by kill
assert state == ['start', 'except'], state
gevent.sleep(DELAY)
assert state == ['start', 'except', 'finished'], state
def test_nested_with_timeout(self):
def func():
return gevent.with_timeout(0.2, gevent.sleep, 2, timeout_value=1)
self.assertRaises(gevent.TimeoutError, gevent.with_timeout, 0.1, func)
class TestTimers(greentest.TestCase):
def setUp(self):
greentest.TestCase.setUp(self)
self.lst = [1]
def test_timer_fired(self):
def func():
gevent.timer(0.1, self.lst.pop)
gevent.sleep(0.2)
gevent.spawn(func)
assert self.lst == [1], self.lst
gevent.sleep(0.3)
assert self.lst == [], self.lst
def test_spawn_is_not_cancelled(self):
def func():
gevent.spawn(self.lst.pop)
# exiting immediatelly, but self.lst.pop must be called
gevent.spawn(func)
gevent.sleep(0.1)
assert self.lst == [], self.lst
if __name__=='__main__':
greentest.main()
# Copyright (c) 2008 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import with_statement
import sys
import greentest
import weakref
import time
from gevent import sleep, timeout, TimeoutError, _SilentException
DELAY = 0.04
class Error(Exception):
pass
class Test(greentest.TestCase):
def test_api(self):
# Nothing happens if with-block finishes before the timeout expires
with timeout(DELAY*2):
sleep(DELAY)
sleep(DELAY*2) # check if timer was actually cancelled
# An exception will be raised if it's not
try:
with timeout(DELAY):
sleep(DELAY*2)
except TimeoutError:
pass
else:
raise AssertionError('must raise TimeoutError')
# You can customize the exception raised:
try:
with timeout(DELAY, IOError("Operation takes way too long")):
sleep(DELAY*2)
except IOError, ex:
assert str(ex)=="Operation takes way too long", repr(ex)
# Providing classes instead of values should be possible too:
try:
with timeout(DELAY, ValueError):
sleep(DELAY*2)
except ValueError:
pass
try:
1/0
except:
try:
with timeout(DELAY, sys.exc_info()[0]):
sleep(DELAY*2)
raise AssertionError('should not get there')
raise AssertionError('should not get there')
except ZeroDivisionError:
pass
else:
raise AssertionError('should not get there')
# It's possible to cancel the timer inside the block:
with timeout(DELAY) as timer:
timer.cancel()
sleep(DELAY*2)
# To silent the exception, pass None as second parameter. The with-block
# will be interrupted with _SilentException, but it won't be propagated
# outside.
XDELAY=0.1
start = time.time()
with timeout(XDELAY, None):
sleep(XDELAY*2)
delta = (time.time()-start)
assert delta<XDELAY*2, delta
# passing None as seconds disables the timer
with timeout(None):
sleep(DELAY)
sleep(DELAY)
def test_ref(self):
err = Error()
err_ref = weakref.ref(err)
with timeout(DELAY*2, err):
sleep(DELAY)
del err
assert not err_ref(), repr(err_ref())
def test_nested_timeout(self):
with timeout(DELAY, None):
with timeout(DELAY*2, None):
sleep(DELAY*3)
raise AssertionError('should not get there')
with timeout(DELAY, _SilentException()):
with timeout(DELAY*2, _SilentException()):
sleep(DELAY*3)
raise AssertionError('should not get there')
# this case fails and there's no intent to fix it.
# just don't do it like that
#with timeout(DELAY, _SilentException):
# with timeout(DELAY*2, _SilentException):
# sleep(DELAY*3)
# assert False, 'should not get there'
if __name__=='__main__':
greentest.main()
This diff is collapsed.
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import greentest
from gevent import spawn, coros
from greentest import TestCase
class TestSemaphore(TestCase):
def test_bounded(self):
sem = coros.BoundedSemaphore(2, limit=3)
self.assertEqual(sem.acquire(), True)
self.assertEqual(sem.acquire(), True)
spawn(sem.release)
self.assertEqual(sem.acquire(), True)
self.assertEqual(-3, sem.balance)
sem.release()
sem.release()
sem.release()
spawn(sem.acquire)
sem.release()
self.assertEqual(3, sem.balance)
def test_bounded_with_zero_limit(self):
sem = coros.BoundedSemaphore(0, 0)
spawn(sem.acquire)
sem.release()
if __name__=='__main__':
greentest.main()
import os
import re
import doctest
import unittest
import gevent
base = os.path.dirname(gevent.__file__)
modules = set()
for path, dirs, files in os.walk(base):
package = 'gevent' + path.replace(base, '').replace('/', '.')
modules.add((package, os.path.join(path, '__init__.py')))
for f in files:
module = None
if f.endswith('.py'):
module = f[:-3]
if module:
modules.add((package + '.' + module, os.path.join(path, f)))
suite = unittest.TestSuite()
tests_count = 0
modules_count = 0
for m, path in modules:
if re.search('^\s*>>> ', open(path).read(), re.M):
s = doctest.DocTestSuite(m)
print '%s (from %s): %s tests' % (m, path, len(s._tests))
suite.addTest(s)
modules_count += 1
tests_count += len(s._tests)
print 'Total: %s tests in %s modules' % (tests_count, modules_count)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
# Copyright (c) 2008-2009 AG Projects
# Author: Denis Bilenko
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import greentest
from gevent.coros import event
from gevent import spawn, sleep, timeout, with_timeout
from greentest import TestCase
DELAY= 0.01
class TestEvent(TestCase):
def test_send_exc(self):
log = []
e = event()
def waiter():
try:
result = e.wait()
log.append(('received', result))
except Exception, ex:
log.append(('catched', ex))
spawn(waiter)
sleep(0) # let waiter to block on e.wait()
obj = Exception()
e.send(exc=obj)
sleep(0)
assert log == [('catched', obj)], log
def test_send(self):
event1 = event()
event2 = event()
spawn(event1.send, 'hello event1')
timeout(0, ValueError('interrupted'))
try:
result = event1.wait()
except ValueError:
X = object()
result = with_timeout(DELAY, event2.wait, timeout_value=X)
assert result is X, 'Nobody sent anything to event2 yet it received %r' % (result, )
if __name__=='__main__':
greentest.main()
This diff is collapsed.
This diff is collapsed.
from gevent import monkey
monkey.patch_all(thread=True)
import time
assert 'built-in' not in repr(time.sleep), repr(time.sleep)
import thread
import threading
assert 'built-in' not in repr(thread.start_new_thread), repr(thread.start_new_thread)
assert 'built-in' not in repr(threading._start_new_thread), repr(threading._start_new_thread)
assert 'built-in' not in repr(threading._sleep), repr(threading._sleep)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment