Merge
This commit is contained in:
@@ -1,24 +1,21 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file __init__.py
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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.
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
version_info = (0, 8, 11)
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
version_info = (0, 8, 10)
|
|
||||||
__version__ = '%s.%s.%s' % version_info
|
__version__ = '%s.%s.%s' % version_info
|
||||||
|
@@ -1,27 +1,24 @@
|
|||||||
"""\
|
# @author Bob Ippolito
|
||||||
@file api.py
|
#
|
||||||
@author Bob Ippolito
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import socket
|
import socket
|
||||||
|
@@ -1,29 +1,26 @@
|
|||||||
"""\
|
# @author Bob Ippolito
|
||||||
@file backdoor.py
|
#
|
||||||
@author Bob Ippolito
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# Copyright (c) 2008, Donovan Preston
|
||||||
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
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
@@ -12,4 +12,5 @@ class channel(coros.queue):
|
|||||||
def balance(self):
|
def balance(self):
|
||||||
return self.sem.balance
|
return self.sem.balance
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
warnings.warn("channel is deprecated; use coros.queue(0) which behaves the same", DeprecationWarning, stacklevel=2)
|
||||||
|
@@ -1,26 +1,23 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file coros.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import time
|
import time
|
||||||
@@ -196,13 +193,11 @@ class event(object):
|
|||||||
>>> api.sleep(0)
|
>>> api.sleep(0)
|
||||||
received stuff
|
received stuff
|
||||||
"""
|
"""
|
||||||
# why is waiter not used?
|
|
||||||
if waiter in self._waiters:
|
if waiter in self._waiters:
|
||||||
del self._waiters[waiter]
|
del self._waiters[waiter]
|
||||||
# XXX This does not check that waiter still waits when throw actually happens
|
# XXX This does not check that waiter still waits when throw actually happens
|
||||||
# XXX and therefore is broken (see how send() deals with this)
|
# XXX and therefore is broken (see how send() deals with this)
|
||||||
api.get_hub().schedule_call(
|
api.get_hub().schedule_call(0, waiter.throw, Cancelled())
|
||||||
0, waiter.throw, Cancelled())
|
|
||||||
|
|
||||||
def send(self, result=None, exc=None):
|
def send(self, result=None, exc=None):
|
||||||
"""Makes arrangements for the waiters to be woken with the
|
"""Makes arrangements for the waiters to be woken with the
|
||||||
@@ -458,29 +453,8 @@ def execute(func, *args, **kw):
|
|||||||
|
|
||||||
|
|
||||||
def CoroutinePool(*args, **kwargs):
|
def CoroutinePool(*args, **kwargs):
|
||||||
from eventlet.pools import CoroutinePool
|
from eventlet.pool import Pool
|
||||||
return CoroutinePool(*args, **kwargs)
|
return Pool(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class pipe(object):
|
|
||||||
""" Implementation of pipe using events. Not tested! Not used, either."""
|
|
||||||
def __init__(self):
|
|
||||||
self._event = event()
|
|
||||||
self._buffer = ''
|
|
||||||
|
|
||||||
def send(self, txt):
|
|
||||||
self._buffer += txt
|
|
||||||
evt, self._event = self._event, event()
|
|
||||||
evt.send()
|
|
||||||
|
|
||||||
def recv(self, num=16384):
|
|
||||||
if not self._buffer:
|
|
||||||
self._event.wait()
|
|
||||||
if num >= len(self._buffer):
|
|
||||||
buf, self._buffer = self._buffer, ''
|
|
||||||
else:
|
|
||||||
buf, self._buffer = self._buffer[:num], self._buffer[num:]
|
|
||||||
return buf
|
|
||||||
|
|
||||||
|
|
||||||
class queue(object):
|
class queue(object):
|
||||||
|
@@ -1,28 +1,26 @@
|
|||||||
"""\
|
# @brief A pool of nonblocking database connections.
|
||||||
@file db_pool.py
|
#
|
||||||
@brief A pool of nonblocking database connections.
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
|
#
|
||||||
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
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
The db_pool module is useful for managing database connections. It provides three primary benefits: cooperative yielding during database operations, concurrency limiting to a database host, and connection reuse. db_pool is intended to be db-agnostic, compatible with any DB-API 2.0 database module; however it has currently only been tested and used with MySQLdb.
|
The db_pool module is useful for managing database connections. It provides three primary benefits: cooperative yielding during database operations, concurrency limiting to a database host, and connection reuse. db_pool is intended to be db-agnostic, compatible with any DB-API 2.0 database module; however it has currently only been tested and used with MySQLdb.
|
||||||
|
|
||||||
== ConnectionPool ==
|
== ConnectionPool ==
|
||||||
@@ -79,11 +77,11 @@ The constructor arguments:
|
|||||||
>>> dc = DatabaseConnector(MySQLdb,
|
>>> dc = DatabaseConnector(MySQLdb,
|
||||||
{'db.internal.example.com':
|
{'db.internal.example.com':
|
||||||
{'user':'internal', 'passwd':'s33kr1t'},
|
{'user':'internal', 'passwd':'s33kr1t'},
|
||||||
'localhost':
|
'localhost':
|
||||||
{'user':'root', 'passwd':''})
|
{'user':'root', 'passwd':''})
|
||||||
|
|
||||||
If the credentials contain a host named 'default', then the value for 'default' is used whenever trying to connect to a host that has no explicit entry in the database. This is useful if there is some pool of hosts that share arguments.
|
If the credentials contain a host named 'default', then the value for 'default' is used whenever trying to connect to a host that has no explicit entry in the database. This is useful if there is some pool of hosts that share arguments.
|
||||||
|
|
||||||
* conn_pool : The connection pool class to use. Defaults to db_pool.ConnectionPool.
|
* conn_pool : The connection pool class to use. Defaults to db_pool.ConnectionPool.
|
||||||
|
|
||||||
The rest of the arguments to the DatabaseConnector constructor are passed on to the ConnectionPool.
|
The rest of the arguments to the DatabaseConnector constructor are passed on to the ConnectionPool.
|
||||||
@@ -92,7 +90,6 @@ NOTE: The DatabaseConnector is a bit unfinished, it only suits a subset of use c
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from collections import deque
|
from collections import deque
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -106,28 +103,28 @@ class ConnectTimeout(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class BaseConnectionPool(Pool):
|
class BaseConnectionPool(Pool):
|
||||||
def __init__(self, db_module,
|
def __init__(self, db_module,
|
||||||
min_size = 0, max_size = 4,
|
min_size = 0, max_size = 4,
|
||||||
max_idle = 10, max_age = 30,
|
max_idle = 10, max_age = 30,
|
||||||
connect_timeout = 5,
|
connect_timeout = 5,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Constructs a pool with at least *min_size* connections and at most
|
Constructs a pool with at least *min_size* connections and at most
|
||||||
*max_size* connections. Uses *db_module* to construct new connections.
|
*max_size* connections. Uses *db_module* to construct new connections.
|
||||||
|
|
||||||
The *max_idle* parameter determines how long pooled connections can
|
The *max_idle* parameter determines how long pooled connections can
|
||||||
remain idle, in seconds. After *max_idle* seconds have elapsed
|
remain idle, in seconds. After *max_idle* seconds have elapsed
|
||||||
without the connection being used, the pool closes the connection.
|
without the connection being used, the pool closes the connection.
|
||||||
|
|
||||||
*max_age* is how long any particular connection is allowed to live.
|
*max_age* is how long any particular connection is allowed to live.
|
||||||
Connections that have been open for longer than *max_age* seconds are
|
Connections that have been open for longer than *max_age* seconds are
|
||||||
closed, regardless of idle time. If *max_age* is 0, all connections are
|
closed, regardless of idle time. If *max_age* is 0, all connections are
|
||||||
closed on return to the pool, reducing it to a concurrency limiter.
|
closed on return to the pool, reducing it to a concurrency limiter.
|
||||||
|
|
||||||
*connect_timeout* is the duration in seconds that the pool will wait
|
*connect_timeout* is the duration in seconds that the pool will wait
|
||||||
before timing out on connect() to the database. If triggered, the
|
before timing out on connect() to the database. If triggered, the
|
||||||
timeout will raise a ConnectTimeout from get().
|
timeout will raise a ConnectTimeout from get().
|
||||||
|
|
||||||
The remainder of the arguments are used as parameters to the
|
The remainder of the arguments are used as parameters to the
|
||||||
*db_module*'s connection constructor.
|
*db_module*'s connection constructor.
|
||||||
"""
|
"""
|
||||||
@@ -139,33 +136,33 @@ class BaseConnectionPool(Pool):
|
|||||||
self.max_age = max_age
|
self.max_age = max_age
|
||||||
self.connect_timeout = connect_timeout
|
self.connect_timeout = connect_timeout
|
||||||
self._expiration_timer = None
|
self._expiration_timer = None
|
||||||
super(BaseConnectionPool, self).__init__(min_size=min_size,
|
super(BaseConnectionPool, self).__init__(min_size=min_size,
|
||||||
max_size=max_size,
|
max_size=max_size,
|
||||||
order_as_stack=True)
|
order_as_stack=True)
|
||||||
|
|
||||||
def _schedule_expiration(self):
|
def _schedule_expiration(self):
|
||||||
""" Sets up a timer that will call _expire_old_connections when the
|
""" Sets up a timer that will call _expire_old_connections when the
|
||||||
oldest connection currently in the free pool is ready to expire. This
|
oldest connection currently in the free pool is ready to expire. This
|
||||||
is the earliest possible time that a connection could expire, thus, the
|
is the earliest possible time that a connection could expire, thus, the
|
||||||
timer will be running as infrequently as possible without missing a
|
timer will be running as infrequently as possible without missing a
|
||||||
possible expiration.
|
possible expiration.
|
||||||
|
|
||||||
If this function is called when a timer is already scheduled, it does
|
If this function is called when a timer is already scheduled, it does
|
||||||
nothing.
|
nothing.
|
||||||
|
|
||||||
If max_age or max_idle is 0, _schedule_expiration likewise does nothing.
|
If max_age or max_idle is 0, _schedule_expiration likewise does nothing.
|
||||||
"""
|
"""
|
||||||
if self.max_age is 0 or self.max_idle is 0:
|
if self.max_age is 0 or self.max_idle is 0:
|
||||||
# expiration is unnecessary because all connections will be expired
|
# expiration is unnecessary because all connections will be expired
|
||||||
# on put
|
# on put
|
||||||
return
|
return
|
||||||
|
|
||||||
if ( self._expiration_timer is not None
|
if ( self._expiration_timer is not None
|
||||||
and not getattr(self._expiration_timer, 'called', False)
|
and not getattr(self._expiration_timer, 'called', False)
|
||||||
and not getattr(self._expiration_timer, 'cancelled', False) ):
|
and not getattr(self._expiration_timer, 'cancelled', False) ):
|
||||||
# the next timer is already scheduled
|
# the next timer is already scheduled
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
self._expire_old_connections(now)
|
self._expire_old_connections(now)
|
||||||
@@ -174,23 +171,23 @@ class BaseConnectionPool(Pool):
|
|||||||
idle_delay = (self.free_items[-1][0] - now) + self.max_idle
|
idle_delay = (self.free_items[-1][0] - now) + self.max_idle
|
||||||
oldest = min([t[1] for t in self.free_items])
|
oldest = min([t[1] for t in self.free_items])
|
||||||
age_delay = (oldest - now) + self.max_age
|
age_delay = (oldest - now) + self.max_age
|
||||||
|
|
||||||
next_delay = min(idle_delay, age_delay)
|
next_delay = min(idle_delay, age_delay)
|
||||||
except IndexError, ValueError:
|
except IndexError, ValueError:
|
||||||
# no free items, unschedule ourselves
|
# no free items, unschedule ourselves
|
||||||
self._expiration_timer = None
|
self._expiration_timer = None
|
||||||
return
|
return
|
||||||
|
|
||||||
if next_delay > 0:
|
if next_delay > 0:
|
||||||
# set up a continuous self-calling loop
|
# set up a continuous self-calling loop
|
||||||
self._expiration_timer = api.call_after(next_delay,
|
self._expiration_timer = api.call_after(next_delay,
|
||||||
self._schedule_expiration)
|
self._schedule_expiration)
|
||||||
|
|
||||||
def _expire_old_connections(self, now):
|
def _expire_old_connections(self, now):
|
||||||
""" Iterates through the open connections contained in the pool, closing
|
""" Iterates through the open connections contained in the pool, closing
|
||||||
ones that have remained idle for longer than max_idle seconds, or have
|
ones that have remained idle for longer than max_idle seconds, or have
|
||||||
been in existence for longer than max_age seconds.
|
been in existence for longer than max_age seconds.
|
||||||
|
|
||||||
*now* is the current time, as returned by time.time().
|
*now* is the current time, as returned by time.time().
|
||||||
"""
|
"""
|
||||||
original_count = len(self.free_items)
|
original_count = len(self.free_items)
|
||||||
@@ -207,8 +204,8 @@ class BaseConnectionPool(Pool):
|
|||||||
if not self._is_expired(now, last_used, created_at)]
|
if not self._is_expired(now, last_used, created_at)]
|
||||||
self.free_items.clear()
|
self.free_items.clear()
|
||||||
self.free_items.extend(new_free)
|
self.free_items.extend(new_free)
|
||||||
|
|
||||||
# adjust the current size counter to account for expired
|
# adjust the current size counter to account for expired
|
||||||
# connections
|
# connections
|
||||||
self.current_size -= original_count - len(self.free_items)
|
self.current_size -= original_count - len(self.free_items)
|
||||||
|
|
||||||
@@ -220,7 +217,7 @@ class BaseConnectionPool(Pool):
|
|||||||
or now - created_at > self.max_age ):
|
or now - created_at > self.max_age ):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _unwrap_connection(self, conn):
|
def _unwrap_connection(self, conn):
|
||||||
""" If the connection was wrapped by a subclass of
|
""" If the connection was wrapped by a subclass of
|
||||||
BaseConnectionWrapper and is still functional (as determined
|
BaseConnectionWrapper and is still functional (as determined
|
||||||
@@ -253,7 +250,7 @@ class BaseConnectionPool(Pool):
|
|||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
conn = super(BaseConnectionPool, self).get()
|
conn = super(BaseConnectionPool, self).get()
|
||||||
|
|
||||||
# None is a flag value that means that put got called with
|
# None is a flag value that means that put got called with
|
||||||
# something it couldn't use
|
# something it couldn't use
|
||||||
if conn is None:
|
if conn is None:
|
||||||
@@ -273,7 +270,7 @@ class BaseConnectionPool(Pool):
|
|||||||
_last_used, created_at, conn = conn
|
_last_used, created_at, conn = conn
|
||||||
else:
|
else:
|
||||||
created_at = time.time()
|
created_at = time.time()
|
||||||
|
|
||||||
# wrap the connection so the consumer can call close() safely
|
# wrap the connection so the consumer can call close() safely
|
||||||
wrapped = PooledConnectionWrapper(conn, self)
|
wrapped = PooledConnectionWrapper(conn, self)
|
||||||
# annotating the wrapper so that when it gets put in the pool
|
# annotating the wrapper so that when it gets put in the pool
|
||||||
@@ -285,7 +282,7 @@ class BaseConnectionPool(Pool):
|
|||||||
created_at = getattr(conn, '_db_pool_created_at', 0)
|
created_at = getattr(conn, '_db_pool_created_at', 0)
|
||||||
now = time.time()
|
now = time.time()
|
||||||
conn = self._unwrap_connection(conn)
|
conn = self._unwrap_connection(conn)
|
||||||
|
|
||||||
if self._is_expired(now, now, created_at):
|
if self._is_expired(now, now, created_at):
|
||||||
self._safe_close(conn, quiet=False)
|
self._safe_close(conn, quiet=False)
|
||||||
conn = None
|
conn = None
|
||||||
@@ -317,7 +314,7 @@ class BaseConnectionPool(Pool):
|
|||||||
self._schedule_expiration()
|
self._schedule_expiration()
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
""" Close all connections that this pool still holds a reference to,
|
""" Close all connections that this pool still holds a reference to,
|
||||||
and removes all references to them.
|
and removes all references to them.
|
||||||
"""
|
"""
|
||||||
if self._expiration_timer:
|
if self._expiration_timer:
|
||||||
@@ -325,10 +322,10 @@ class BaseConnectionPool(Pool):
|
|||||||
free_items, self.free_items = self.free_items, deque()
|
free_items, self.free_items = self.free_items, deque()
|
||||||
for _last_used, _created_at, conn in free_items:
|
for _last_used, _created_at, conn in free_items:
|
||||||
self._safe_close(conn, quiet=True)
|
self._safe_close(conn, quiet=True)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
|
|
||||||
class SaranwrappedConnectionPool(BaseConnectionPool):
|
class SaranwrappedConnectionPool(BaseConnectionPool):
|
||||||
"""A pool which gives out saranwrapped database connections.
|
"""A pool which gives out saranwrapped database connections.
|
||||||
@@ -346,9 +343,9 @@ class SaranwrappedConnectionPool(BaseConnectionPool):
|
|||||||
return saranwrap.wrap(db_module).connect(*args, **kw)
|
return saranwrap.wrap(db_module).connect(*args, **kw)
|
||||||
finally:
|
finally:
|
||||||
timeout.cancel()
|
timeout.cancel()
|
||||||
|
|
||||||
connect = classmethod(connect)
|
connect = classmethod(connect)
|
||||||
|
|
||||||
|
|
||||||
class TpooledConnectionPool(BaseConnectionPool):
|
class TpooledConnectionPool(BaseConnectionPool):
|
||||||
"""A pool which gives out tpool.Proxy-based database connections.
|
"""A pool which gives out tpool.Proxy-based database connections.
|
||||||
@@ -422,16 +419,12 @@ class GenericConnectionWrapper(object):
|
|||||||
def set_sql_mode(self, sql_mode): return self._base.set_sql_mode(sql_mode)
|
def set_sql_mode(self, sql_mode): return self._base.set_sql_mode(sql_mode)
|
||||||
def show_warnings(self): return self._base.show_warnings()
|
def show_warnings(self): return self._base.show_warnings()
|
||||||
def warning_count(self): return self._base.warning_count()
|
def warning_count(self): return self._base.warning_count()
|
||||||
def literal(self, o): return self._base.literal(o)
|
|
||||||
def ping(self,*args, **kwargs): return self._base.ping(*args, **kwargs)
|
def ping(self,*args, **kwargs): return self._base.ping(*args, **kwargs)
|
||||||
def query(self,*args, **kwargs): return self._base.query(*args, **kwargs)
|
def query(self,*args, **kwargs): return self._base.query(*args, **kwargs)
|
||||||
def rollback(self,*args, **kwargs): return self._base.rollback(*args, **kwargs)
|
def rollback(self,*args, **kwargs): return self._base.rollback(*args, **kwargs)
|
||||||
def select_db(self,*args, **kwargs): return self._base.select_db(*args, **kwargs)
|
def select_db(self,*args, **kwargs): return self._base.select_db(*args, **kwargs)
|
||||||
def set_server_option(self,*args, **kwargs): return self._base.set_server_option(*args, **kwargs)
|
def set_server_option(self,*args, **kwargs): return self._base.set_server_option(*args, **kwargs)
|
||||||
def set_character_set(self, charset): return self._base.set_character_set(charset)
|
|
||||||
def set_sql_mode(self, sql_mode): return self._base.set_sql_mode(sql_mode)
|
|
||||||
def server_capabilities(self,*args, **kwargs): return self._base.server_capabilities(*args, **kwargs)
|
def server_capabilities(self,*args, **kwargs): return self._base.server_capabilities(*args, **kwargs)
|
||||||
def show_warnings(self): return self._base.show_warnings()
|
|
||||||
def shutdown(self,*args, **kwargs): return self._base.shutdown(*args, **kwargs)
|
def shutdown(self,*args, **kwargs): return self._base.shutdown(*args, **kwargs)
|
||||||
def sqlstate(self,*args, **kwargs): return self._base.sqlstate(*args, **kwargs)
|
def sqlstate(self,*args, **kwargs): return self._base.sqlstate(*args, **kwargs)
|
||||||
def stat(self,*args, **kwargs): return self._base.stat(*args, **kwargs)
|
def stat(self,*args, **kwargs): return self._base.stat(*args, **kwargs)
|
||||||
@@ -439,7 +432,6 @@ class GenericConnectionWrapper(object):
|
|||||||
def string_literal(self,*args, **kwargs): return self._base.string_literal(*args, **kwargs)
|
def string_literal(self,*args, **kwargs): return self._base.string_literal(*args, **kwargs)
|
||||||
def thread_id(self,*args, **kwargs): return self._base.thread_id(*args, **kwargs)
|
def thread_id(self,*args, **kwargs): return self._base.thread_id(*args, **kwargs)
|
||||||
def use_result(self,*args, **kwargs): return self._base.use_result(*args, **kwargs)
|
def use_result(self,*args, **kwargs): return self._base.use_result(*args, **kwargs)
|
||||||
def warning_count(self): return self._base.warning_count()
|
|
||||||
|
|
||||||
|
|
||||||
class PooledConnectionWrapper(GenericConnectionWrapper):
|
class PooledConnectionWrapper(GenericConnectionWrapper):
|
||||||
@@ -470,7 +462,7 @@ class PooledConnectionWrapper(GenericConnectionWrapper):
|
|||||||
if self and self._pool:
|
if self and self._pool:
|
||||||
self._pool.put(self)
|
self._pool.put(self)
|
||||||
self._destroy()
|
self._destroy()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
@@ -479,7 +471,7 @@ class DatabaseConnector(object):
|
|||||||
"""\
|
"""\
|
||||||
@brief This is an object which will maintain a collection of database
|
@brief This is an object which will maintain a collection of database
|
||||||
connection pools on a per-host basis."""
|
connection pools on a per-host basis."""
|
||||||
def __init__(self, module, credentials,
|
def __init__(self, module, credentials,
|
||||||
conn_pool=None, *args, **kwargs):
|
conn_pool=None, *args, **kwargs):
|
||||||
"""\
|
"""\
|
||||||
@brief constructor
|
@brief constructor
|
||||||
|
@@ -1,28 +1,26 @@
|
|||||||
"""\
|
# Copyright (c) 2005-2009, Donovan Preston
|
||||||
@file exc.py
|
#
|
||||||
@brief Takes an exception object and returns a dictionary suitable for use debugging the exception later.
|
# 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.
|
||||||
|
|
||||||
Copyright (c) 2005-2009, 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.
|
|
||||||
"""
|
"""
|
||||||
|
Takes an exception object and returns a dictionary suitable for use debugging the exception later.
|
||||||
|
"""
|
||||||
|
|
||||||
import linecache
|
import linecache
|
||||||
import re
|
import re
|
||||||
@@ -39,7 +37,7 @@ def format_exc(exc=None):
|
|||||||
frames = []
|
frames = []
|
||||||
while exc_tb is not None:
|
while exc_tb is not None:
|
||||||
f = exc_tb.tb_frame
|
f = exc_tb.tb_frame
|
||||||
|
|
||||||
frames.append((
|
frames.append((
|
||||||
f.f_code.co_name,
|
f.f_code.co_name,
|
||||||
f.f_code.co_filename,
|
f.f_code.co_filename,
|
||||||
|
@@ -1,26 +1,22 @@
|
|||||||
"""\
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
@file greenio.py
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# in the Software without restriction, including without limitation the rights
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
in the Software without restriction, including without limitation the rights
|
# furnished to do so, subject to the following conditions:
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
#
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
# The above copyright notice and this permission notice shall be included in
|
||||||
furnished to do so, subject to the following conditions:
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
The above copyright notice and this permission notice shall be included in
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
all copies or substantial portions of the Software.
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# THE SOFTWARE.
|
||||||
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 eventlet.api import trampoline, get_hub
|
from eventlet.api import trampoline, get_hub
|
||||||
from eventlet import util
|
from eventlet import util
|
||||||
@@ -293,7 +289,9 @@ class GreenSocket(object):
|
|||||||
def dup(self, *args, **kw):
|
def dup(self, *args, **kw):
|
||||||
sock = self.fd.dup(*args, **kw)
|
sock = self.fd.dup(*args, **kw)
|
||||||
set_nonblocking(sock)
|
set_nonblocking(sock)
|
||||||
return type(self)(sock)
|
newsock = type(self)(sock)
|
||||||
|
newsock.settimeout(self.timeout)
|
||||||
|
return newsock
|
||||||
|
|
||||||
def fileno(self, *args, **kw):
|
def fileno(self, *args, **kw):
|
||||||
fn = self.fileno = self.fd.fileno
|
fn = self.fileno = self.fd.fileno
|
||||||
@@ -352,7 +350,6 @@ class GreenSocket(object):
|
|||||||
return self.fd.sendto(*args)
|
return self.fd.sendto(*args)
|
||||||
|
|
||||||
def setblocking(self, flag):
|
def setblocking(self, flag):
|
||||||
self.fd.setblocking(flag)
|
|
||||||
if flag:
|
if flag:
|
||||||
self.act_non_blocking = False
|
self.act_non_blocking = False
|
||||||
self.timeout = None
|
self.timeout = None
|
||||||
|
@@ -1,7 +1,4 @@
|
|||||||
"""\
|
"""\
|
||||||
@file greenlib.py
|
|
||||||
@author Bob Ippolito
|
|
||||||
|
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
Copyright (c) 2005-2006, Bob Ippolito
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
Copyright (c) 2007, Linden Research, Inc.
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -22,11 +19,13 @@ 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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
"""
|
"""
|
||||||
|
from eventlet.api import Greenlet
|
||||||
|
|
||||||
|
class SwitchingToDeadGreenlet(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
def switch(other=None, value=None, exc=None):
|
def switch(other=None, value=None, exc=None):
|
||||||
"""
|
self = Greenlet.getcurrent()
|
||||||
Switch to another greenlet, passing value or exception
|
|
||||||
"""
|
|
||||||
self = greenlet.getcurrent()
|
|
||||||
if other is None:
|
if other is None:
|
||||||
other = self.parent
|
other = self.parent
|
||||||
if other is None:
|
if other is None:
|
||||||
@@ -37,3 +36,6 @@ def switch(other=None, value=None, exc=None):
|
|||||||
return other.throw(exc)
|
return other.throw(exc)
|
||||||
else:
|
else:
|
||||||
return other.switch(value)
|
return other.switch(value)
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
warnings.warn("greenlib is deprecated; use greenlet methods directly", DeprecationWarning, stacklevel=2)
|
||||||
|
@@ -1,30 +1,26 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file httpc.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2005-2006, Donovan Preston
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Donovan Preston
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
|
||||||
from eventlet.green import httplib
|
from eventlet.green import httplib
|
||||||
import os.path
|
import os.path
|
||||||
import os
|
import os
|
||||||
|
@@ -1,27 +1,24 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file httpd.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2005-2006, Donovan Preston
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Donovan Preston
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cgi
|
import cgi
|
||||||
import errno
|
import errno
|
||||||
@@ -29,7 +26,6 @@ import socket
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
import socket
|
|
||||||
import traceback
|
import traceback
|
||||||
import BaseHTTPServer
|
import BaseHTTPServer
|
||||||
|
|
||||||
|
@@ -1,39 +1,3 @@
|
|||||||
"""\
|
from wsgi import format_date_time
|
||||||
@file httpdate.py
|
import warnings
|
||||||
@author Donovan Preston
|
warnings.warn("httpdate module is deprecated; its contents is moved to wsgi.py", DeprecationWarning, stacklevel=2)
|
||||||
|
|
||||||
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 time
|
|
||||||
|
|
||||||
__all__ = ['format_date_time']
|
|
||||||
|
|
||||||
# Weekday and month names for HTTP date/time formatting; always English!
|
|
||||||
_weekdayname = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
|
||||||
_monthname = [None, # Dummy so we can use 1-based month numbers
|
|
||||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
||||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
|
||||||
|
|
||||||
def format_date_time(timestamp):
|
|
||||||
year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
|
|
||||||
return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
|
|
||||||
_weekdayname[wd], day, _monthname[month], year, hh, mm, ss
|
|
||||||
)
|
|
||||||
|
@@ -1,25 +1,21 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file hub.py
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# in the Software without restriction, including without limitation the rights
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
in the Software without restriction, including without limitation the rights
|
# furnished to do so, subject to the following conditions:
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
#
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
# The above copyright notice and this permission notice shall be included in
|
||||||
furnished to do so, subject to the following conditions:
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
The above copyright notice and this permission notice shall be included in
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
all copies or substantial portions of the Software.
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# THE SOFTWARE.
|
||||||
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 bisect
|
import bisect
|
||||||
import sys
|
import sys
|
||||||
|
@@ -1,38 +1,28 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file libev.py
|
# 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.
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import bisect
|
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import socket
|
|
||||||
import errno
|
|
||||||
import traceback
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from eventlet.hubs import hub
|
from eventlet.hubs import hub
|
||||||
|
|
||||||
from eventlet.support import greenlets as greenlet
|
|
||||||
|
|
||||||
# XXX for debugging only
|
# XXX for debugging only
|
||||||
#raise ImportError()
|
#raise ImportError()
|
||||||
|
|
||||||
@@ -81,7 +71,7 @@ class Hub(hub.BaseHub):
|
|||||||
|
|
||||||
def signal_received(self, signal):
|
def signal_received(self, signal):
|
||||||
# can't do more than set this flag here because the pyevent callback
|
# can't do more than set this flag here because the pyevent callback
|
||||||
# mechanism swallows exceptions raised here, so we have to raise in
|
# mechanism swallows exceptions raised here, so we have to raise in
|
||||||
# the 'main' greenlet (in wait()) to kill the program
|
# the 'main' greenlet (in wait()) to kill the program
|
||||||
self.interrupted = True
|
self.interrupted = True
|
||||||
self._evloop.unloop()
|
self._evloop.unloop()
|
||||||
@@ -107,7 +97,7 @@ class Hub(hub.BaseHub):
|
|||||||
# raise any signals that deserve raising
|
# raise any signals that deserve raising
|
||||||
if self.interrupted:
|
if self.interrupted:
|
||||||
self.interrupted = False
|
self.interrupted = False
|
||||||
raise KeyboardInterrupt()
|
raise KeyboardInterrupt()
|
||||||
|
|
||||||
def add_timer(self, timer):
|
def add_timer(self, timer):
|
||||||
# store the pyevent timer object so that we can cancel later
|
# store the pyevent timer object so that we can cancel later
|
||||||
|
@@ -1,38 +1,28 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file libevent.py
|
# 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.
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import bisect
|
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import socket
|
|
||||||
import errno
|
|
||||||
import traceback
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from eventlet.timer import Timer
|
|
||||||
from eventlet.hubs import hub
|
from eventlet.hubs import hub
|
||||||
|
|
||||||
from eventlet.support import greenlets as greenlet
|
|
||||||
|
|
||||||
# XXX for debugging only
|
# XXX for debugging only
|
||||||
#raise ImportError()
|
#raise ImportError()
|
||||||
|
@@ -1,168 +0,0 @@
|
|||||||
"""\
|
|
||||||
@file nginx.py
|
|
||||||
@author Donovan Preston
|
|
||||||
|
|
||||||
Copyright (c) 2008, 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 os.path import abspath, dirname
|
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
sys.stdout = sys.stderr
|
|
||||||
mydir = dirname(dirname(dirname(abspath(__file__))))
|
|
||||||
if mydir not in sys.path:
|
|
||||||
sys.path.append(mydir)
|
|
||||||
|
|
||||||
|
|
||||||
from eventlet import api
|
|
||||||
from eventlet import httpc
|
|
||||||
from eventlet.hubs import hub
|
|
||||||
|
|
||||||
|
|
||||||
def hello_world(env, start_response):
|
|
||||||
result = httpc.get('http://www.google.com/')
|
|
||||||
start_response('200 OK', [('Content-type', 'text/plain')])
|
|
||||||
return [result]
|
|
||||||
|
|
||||||
|
|
||||||
def wrap_application(master, env, start_response):
|
|
||||||
try:
|
|
||||||
real_application = api.named(env['eventlet_nginx_wsgi_app'])
|
|
||||||
except:
|
|
||||||
real_application = hello_world
|
|
||||||
result = real_application(env, start_response)
|
|
||||||
master.switch((result, None))
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
|
|
||||||
class StartResponse(object):
|
|
||||||
def __call__(self, *args):
|
|
||||||
self.args = args
|
|
||||||
|
|
||||||
|
|
||||||
pythonpath_already_set = False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WSGI_POLLIN = 0x01
|
|
||||||
WSGI_POLLOUT = 0x04
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
class Hub(hub.BaseHub):
|
|
||||||
def __init__(self, *args, **kw):
|
|
||||||
hub.BaseHub.__init__(self, *args, **kw)
|
|
||||||
self._connection_wrappers = {}
|
|
||||||
|
|
||||||
def add_descriptor(self, fileno, read=None, write=None, exc=None):
|
|
||||||
print "ADD DESCRIPTOR", fileno, read, write, exc
|
|
||||||
traceback.print_stack()
|
|
||||||
|
|
||||||
result = super(Hub, self).add_descriptor(fileno, read, write, exc)
|
|
||||||
flag = 0
|
|
||||||
if read:
|
|
||||||
flag |= WSGI_POLLIN
|
|
||||||
if write:
|
|
||||||
flag |= WSGI_POLLOUT
|
|
||||||
conn = self.connection_wrapper(fileno)
|
|
||||||
self._connection_wrappers[fileno] = conn
|
|
||||||
print "POLL REGISTER", flag
|
|
||||||
self.poll_register(conn, flag)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def remove_descriptor(self, fileno):
|
|
||||||
super(Hub, self).remove_descriptor(fileno)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.poll_unregister(self._connection_wrappers[fileno])
|
|
||||||
except RuntimeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def wait(self, seconds=0):
|
|
||||||
to_call = getattr(self, 'to_call', None)
|
|
||||||
print "WAIT", self, to_call
|
|
||||||
if to_call:
|
|
||||||
print "CALL TOCALL"
|
|
||||||
result = to_call[0](to_call[1])
|
|
||||||
del self.to_call
|
|
||||||
return result
|
|
||||||
self.current_application.switch(self.poll(int(seconds*1000)))
|
|
||||||
|
|
||||||
def application(self, env, start_response):
|
|
||||||
print "ENV",env
|
|
||||||
self.poll_register = env['ngx.poll_register']
|
|
||||||
self.poll_unregister = env['ngx.poll_unregister']
|
|
||||||
self.poll = env['ngx.poll']
|
|
||||||
self.connection_wrapper = env['ngx.connection_wrapper']
|
|
||||||
self.current_application = api.getcurrent()
|
|
||||||
|
|
||||||
slave = api.greenlet.greenlet(wrap_application)
|
|
||||||
response = StartResponse()
|
|
||||||
result = slave.switch(
|
|
||||||
api.getcurrent(), env, response)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
self.current_application = api.getcurrent()
|
|
||||||
print "RESULT", result, callable(result[0])
|
|
||||||
if result and callable(result[0]):
|
|
||||||
print "YIELDING!"
|
|
||||||
yield ''
|
|
||||||
print "AFTER YIELD!"
|
|
||||||
conn, flags = result[0]()
|
|
||||||
fileno = conn.fileno()
|
|
||||||
if flags & WSGI_POLLIN:
|
|
||||||
self.readers[fileno](fileno)
|
|
||||||
elif flags & WSGI_POLLOUT:
|
|
||||||
self.writers[fileno](fileno)
|
|
||||||
print "POLL STATE", conn, flags, dir(conn)
|
|
||||||
else:
|
|
||||||
start_response(*response.args)
|
|
||||||
if isinstance(result, tuple):
|
|
||||||
for x in result[0]:
|
|
||||||
yield x
|
|
||||||
else:
|
|
||||||
for x in result:
|
|
||||||
yield x
|
|
||||||
return
|
|
||||||
result = self.switch()
|
|
||||||
#if not isinstance(result, tuple):
|
|
||||||
# result = (result, None) ## TODO Fix greenlib's return values
|
|
||||||
|
|
||||||
|
|
||||||
def application(env, start_response):
|
|
||||||
hub = api.get_hub()
|
|
||||||
|
|
||||||
if not isinstance(hub, Hub):
|
|
||||||
api.use_hub(sys.modules[Hub.__module__])
|
|
||||||
hub = api.get_hub()
|
|
||||||
|
|
||||||
global pythonpath_already_set
|
|
||||||
if not pythonpath_already_set:
|
|
||||||
pythonpath = env.get('eventlet_python_path', '').split(':')
|
|
||||||
for seg in pythonpath:
|
|
||||||
if seg not in sys.path:
|
|
||||||
sys.path.append(seg)
|
|
||||||
|
|
||||||
return hub.application(env, start_response)
|
|
||||||
|
|
@@ -1,33 +1,28 @@
|
|||||||
"""\
|
# @author Bob Ippolito
|
||||||
@file poll.py
|
#
|
||||||
@author Bob Ippolito
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import select
|
import select
|
||||||
import socket
|
|
||||||
import errno
|
import errno
|
||||||
import traceback
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -60,7 +55,7 @@ class Hub(hub.BaseHub):
|
|||||||
mask |= WRITE_MASK
|
mask |= WRITE_MASK
|
||||||
return mask
|
return mask
|
||||||
|
|
||||||
|
|
||||||
def remove_descriptor(self, fileno):
|
def remove_descriptor(self, fileno):
|
||||||
super(Hub, self).remove_descriptor(fileno)
|
super(Hub, self).remove_descriptor(fileno)
|
||||||
try:
|
try:
|
||||||
|
@@ -1,26 +1,22 @@
|
|||||||
"""\
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
@file select.py
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# in the Software without restriction, including without limitation the rights
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
in the Software without restriction, including without limitation the rights
|
# furnished to do so, subject to the following conditions:
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
#
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
# The above copyright notice and this permission notice shall be included in
|
||||||
furnished to do so, subject to the following conditions:
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
The above copyright notice and this permission notice shall be included in
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
all copies or substantial portions of the Software.
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# THE SOFTWARE.
|
||||||
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 sys
|
||||||
import select
|
import select
|
||||||
@@ -29,7 +25,6 @@ import time
|
|||||||
|
|
||||||
from eventlet.hubs import hub
|
from eventlet.hubs import hub
|
||||||
|
|
||||||
from eventlet.support import greenlets as greenlet
|
|
||||||
|
|
||||||
class Hub(hub.BaseHub):
|
class Hub(hub.BaseHub):
|
||||||
def wait(self, seconds=None):
|
def wait(self, seconds=None):
|
||||||
|
@@ -1,26 +1,23 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file jsonhttp.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from eventlet import httpc
|
from eventlet import httpc
|
||||||
|
|
||||||
|
@@ -1,26 +1,23 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file logutil.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import syslog
|
import syslog
|
||||||
import logging
|
import logging
|
||||||
|
@@ -1,27 +1,24 @@
|
|||||||
"""\
|
# @author Bob Ippolito
|
||||||
@file channel.py
|
#
|
||||||
@author Bob Ippolito
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
@@ -100,3 +97,6 @@ class channel(object):
|
|||||||
|
|
||||||
def send_exception(self, exc):
|
def send_exception(self, exc):
|
||||||
return self._send_tasklet(None, exc)
|
return self._send_tasklet(None, exc)
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
warnings.warn("channel is deprecated; use coros.queue(0) which behaves the same", DeprecationWarning, stacklevel=2)
|
||||||
|
@@ -15,6 +15,10 @@ class Pool(object):
|
|||||||
else:
|
else:
|
||||||
self.results = None
|
self.results = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_size(self):
|
||||||
|
return len(self.procs)
|
||||||
|
|
||||||
def free(self):
|
def free(self):
|
||||||
return self.sem.counter
|
return self.sem.counter
|
||||||
|
|
||||||
@@ -50,7 +54,7 @@ class Pool(object):
|
|||||||
execute_async = execute
|
execute_async = execute
|
||||||
|
|
||||||
def _execute(self, evt, func, args, kw):
|
def _execute(self, evt, func, args, kw):
|
||||||
p = self.execute(func, args, kw)
|
p = self.execute(func, *args, **kw)
|
||||||
p.link(evt)
|
p.link(evt)
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
@@ -1,32 +1,27 @@
|
|||||||
"""\
|
# @author Donovan Preston, Aaron Brashears
|
||||||
@file pools.py
|
#
|
||||||
@author Donovan Preston, Aaron Brashears
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import traceback
|
|
||||||
|
|
||||||
from eventlet import api
|
from eventlet import api
|
||||||
from eventlet import channel
|
|
||||||
from eventlet import coros
|
from eventlet import coros
|
||||||
|
|
||||||
class FanFailed(RuntimeError):
|
class FanFailed(RuntimeError):
|
||||||
@@ -76,7 +71,7 @@ class Pool(object):
|
|||||||
self.max_size = max_size
|
self.max_size = max_size
|
||||||
self.order_as_stack = order_as_stack
|
self.order_as_stack = order_as_stack
|
||||||
self.current_size = 0
|
self.current_size = 0
|
||||||
self.channel = channel.channel()
|
self.channel = coros.queue(0)
|
||||||
self.free_items = collections.deque()
|
self.free_items = collections.deque()
|
||||||
for x in xrange(min_size):
|
for x in xrange(min_size):
|
||||||
self.current_size += 1
|
self.current_size += 1
|
||||||
@@ -91,7 +86,7 @@ class Pool(object):
|
|||||||
created = self.create()
|
created = self.create()
|
||||||
self.current_size += 1
|
self.current_size += 1
|
||||||
return created
|
return created
|
||||||
return self.channel.receive()
|
return self.channel.wait()
|
||||||
|
|
||||||
def put(self, item):
|
def put(self, item):
|
||||||
"""Put an item back into the pool, when done
|
"""Put an item back into the pool, when done
|
||||||
@@ -100,7 +95,7 @@ class Pool(object):
|
|||||||
self.current_size -= 1
|
self.current_size -= 1
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.channel.balance < 0:
|
if self.channel.sem.balance < 0:
|
||||||
self.channel.send(item)
|
self.channel.send(item)
|
||||||
else:
|
else:
|
||||||
if self.order_as_stack:
|
if self.order_as_stack:
|
||||||
@@ -121,8 +116,8 @@ class Pool(object):
|
|||||||
def waiting(self):
|
def waiting(self):
|
||||||
"""Return the number of routines waiting for a pool item.
|
"""Return the number of routines waiting for a pool item.
|
||||||
"""
|
"""
|
||||||
if self.channel.balance < 0:
|
if self.channel.sem.balance < 0:
|
||||||
return -self.channel.balance
|
return -self.channel.sem.balance
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
@@ -212,458 +207,6 @@ class ExceptionWrapper(object):
|
|||||||
def __init__(self, e):
|
def __init__(self, e):
|
||||||
self.e = e
|
self.e = e
|
||||||
|
|
||||||
|
|
||||||
class CoroutinePool(Pool):
|
|
||||||
""" Like a thread pool, but with coroutines.
|
|
||||||
|
|
||||||
Coroutine pools are useful for splitting up tasks or globally controlling
|
|
||||||
concurrency. You don't retrieve the coroutines directly with get() --
|
|
||||||
instead use the execute() and execute_async() methods to run code.
|
|
||||||
|
|
||||||
>>> from eventlet import coros, api
|
|
||||||
>>> p = coros.CoroutinePool(max_size=2)
|
|
||||||
>>> def foo(a):
|
|
||||||
... print "foo", a
|
|
||||||
...
|
|
||||||
>>> evt = p.execute(foo, 1)
|
|
||||||
>>> evt.wait()
|
|
||||||
foo 1
|
|
||||||
|
|
||||||
Once the pool is exhausted, calling an execute forces a yield.
|
|
||||||
|
|
||||||
>>> p.execute_async(foo, 2)
|
|
||||||
>>> p.execute_async(foo, 3)
|
|
||||||
>>> p.free()
|
|
||||||
0
|
|
||||||
>>> p.execute_async(foo, 4)
|
|
||||||
foo 2
|
|
||||||
foo 3
|
|
||||||
|
|
||||||
>>> api.sleep(0)
|
|
||||||
foo 4
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, min_size=0, max_size=4, track_events=False):
|
|
||||||
self._greenlets = set()
|
|
||||||
if track_events:
|
|
||||||
self._tracked_events = []
|
|
||||||
self._next_event = None
|
|
||||||
else:
|
|
||||||
self._tracked_events = None
|
|
||||||
self.requested = coros.metaphore()
|
|
||||||
super(CoroutinePool, self).__init__(min_size, max_size)
|
|
||||||
|
|
||||||
## This doesn't yet pass its own doctest -- but I'm not even sure it's a
|
|
||||||
## wonderful idea.
|
|
||||||
## def __del__(self):
|
|
||||||
## """Experimental: try to prevent the calling script from exiting until
|
|
||||||
## all coroutines in this pool have run to completion.
|
|
||||||
|
|
||||||
## >>> from eventlet import coros
|
|
||||||
## >>> pool = coros.CoroutinePool()
|
|
||||||
## >>> def saw(x): print "I saw %s!"
|
|
||||||
## ...
|
|
||||||
## >>> pool.launch_all(saw, "GHI")
|
|
||||||
## >>> del pool
|
|
||||||
## I saw G!
|
|
||||||
## I saw H!
|
|
||||||
## I saw I!
|
|
||||||
## """
|
|
||||||
## self.wait_all()
|
|
||||||
|
|
||||||
def _main_loop(self, sender):
|
|
||||||
""" Private, infinite loop run by a pooled coroutine. """
|
|
||||||
try:
|
|
||||||
# not really a loop anymore because we want the greenlet
|
|
||||||
# to die so all its timers get canceled
|
|
||||||
if True:
|
|
||||||
recvd = sender.wait()
|
|
||||||
# Delete the sender's result here because the very
|
|
||||||
# first event through the loop is referenced by
|
|
||||||
# spawn_startup, and therefore is not itself deleted.
|
|
||||||
# This means that we have to free up its argument
|
|
||||||
# because otherwise said argument persists in memory
|
|
||||||
# forever. This is generally only a problem in unit
|
|
||||||
# tests.
|
|
||||||
sender._result = coros.NOT_USED
|
|
||||||
|
|
||||||
(evt, func, args, kw) = recvd
|
|
||||||
self._safe_apply(evt, func, args, kw)
|
|
||||||
# Likewise, delete these variables or else they will
|
|
||||||
# be referenced by this frame until replaced by the
|
|
||||||
# next recvd, which may or may not be a long time from
|
|
||||||
# now.
|
|
||||||
del evt, func, args, kw, recvd
|
|
||||||
finally:
|
|
||||||
self.put(self.create())
|
|
||||||
|
|
||||||
def _safe_apply(self, evt, func, args, kw):
|
|
||||||
""" Private method that runs the function, catches exceptions, and
|
|
||||||
passes back the return value in the event."""
|
|
||||||
try:
|
|
||||||
result = func(*args, **kw)
|
|
||||||
if evt is not None:
|
|
||||||
evt.send(result)
|
|
||||||
if self._tracked_events is not None:
|
|
||||||
if self._next_event is None:
|
|
||||||
self._tracked_events.append(result)
|
|
||||||
else:
|
|
||||||
|
|
||||||
ne = self._next_event
|
|
||||||
self._next_event = None
|
|
||||||
ne.send(result)
|
|
||||||
except api.GreenletExit, e:
|
|
||||||
# we're printing this out to see if it ever happens
|
|
||||||
# in practice
|
|
||||||
print "GreenletExit raised in coroutine pool", e
|
|
||||||
if evt is not None:
|
|
||||||
evt.send(e) # sent as a return value, not an exception
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
raise # allow program to exit
|
|
||||||
except Exception, e:
|
|
||||||
traceback.print_exc()
|
|
||||||
if evt is not None:
|
|
||||||
evt.send(exc=e)
|
|
||||||
if self._tracked_events is not None:
|
|
||||||
if self._next_event is None:
|
|
||||||
self._tracked_events.append(ExceptionWrapper(e))
|
|
||||||
else:
|
|
||||||
ne = self._next_event
|
|
||||||
self._next_event = None
|
|
||||||
ne.send(exc=e)
|
|
||||||
|
|
||||||
def _execute(self, evt, func, args, kw):
|
|
||||||
""" Private implementation of the execute methods.
|
|
||||||
"""
|
|
||||||
# if reentering an empty pool, don't try to wait on a coroutine freeing
|
|
||||||
# itself -- instead, just execute in the current coroutine
|
|
||||||
if self.free() == 0 and api.getcurrent() in self._greenlets:
|
|
||||||
self._safe_apply(evt, func, args, kw)
|
|
||||||
else:
|
|
||||||
sender = self.get()
|
|
||||||
sender.send((evt, func, args, kw))
|
|
||||||
|
|
||||||
def create(self):
|
|
||||||
"""Private implementation of eventlet.pools.Pool
|
|
||||||
interface. Creates an event and spawns the
|
|
||||||
_main_loop coroutine, passing the event.
|
|
||||||
The event is used to send a callable into the
|
|
||||||
new coroutine, to be executed.
|
|
||||||
"""
|
|
||||||
sender = coros.event()
|
|
||||||
self._greenlets.add(api.spawn(self._main_loop, sender))
|
|
||||||
return sender
|
|
||||||
|
|
||||||
def get(self):
|
|
||||||
"""Override of eventlet.pools.Pool interface"""
|
|
||||||
# Track the number of requested CoroutinePool coroutines
|
|
||||||
self.requested.inc()
|
|
||||||
# forward call to base class
|
|
||||||
return super(CoroutinePool, self).get()
|
|
||||||
|
|
||||||
def put(self, item):
|
|
||||||
"""Override of eventlet.pools.Pool interface"""
|
|
||||||
# forward call to base class
|
|
||||||
super(CoroutinePool, self).put(item)
|
|
||||||
# Track the number of outstanding CoroutinePool coroutines
|
|
||||||
self.requested.dec()
|
|
||||||
|
|
||||||
def execute(self, func, *args, **kw):
|
|
||||||
"""Execute func in one of the coroutines maintained
|
|
||||||
by the pool, when one is free.
|
|
||||||
|
|
||||||
Immediately returns an eventlet.coros.event object which
|
|
||||||
func's result will be sent to when it is available.
|
|
||||||
|
|
||||||
>>> from eventlet import coros
|
|
||||||
>>> p = coros.CoroutinePool()
|
|
||||||
>>> evt = p.execute(lambda a: ('foo', a), 1)
|
|
||||||
>>> evt.wait()
|
|
||||||
('foo', 1)
|
|
||||||
"""
|
|
||||||
receiver = coros.event()
|
|
||||||
self._execute(receiver, func, args, kw)
|
|
||||||
return receiver
|
|
||||||
|
|
||||||
def execute_async(self, func, *args, **kw):
|
|
||||||
"""Execute func in one of the coroutines maintained
|
|
||||||
by the pool, when one is free.
|
|
||||||
|
|
||||||
No return value is provided.
|
|
||||||
>>> from eventlet import coros, api
|
|
||||||
>>> p = coros.CoroutinePool()
|
|
||||||
>>> def foo(a):
|
|
||||||
... print "foo", a
|
|
||||||
...
|
|
||||||
>>> p.execute_async(foo, 1)
|
|
||||||
>>> api.sleep(0)
|
|
||||||
foo 1
|
|
||||||
"""
|
|
||||||
self._execute(None, func, args, kw)
|
|
||||||
|
|
||||||
def wait(self):
|
|
||||||
"""Wait for the next execute in the pool to complete,
|
|
||||||
and return the result.
|
|
||||||
|
|
||||||
You must pass track_events=True to the CoroutinePool constructor
|
|
||||||
in order to use this method.
|
|
||||||
"""
|
|
||||||
assert self._tracked_events is not None, (
|
|
||||||
"Must pass track_events=True to the constructor to use CoroutinePool.wait()")
|
|
||||||
if self._next_event is not None:
|
|
||||||
return self._next_event.wait()
|
|
||||||
|
|
||||||
if not self._tracked_events:
|
|
||||||
self._next_event = coros.event()
|
|
||||||
return self._next_event.wait()
|
|
||||||
|
|
||||||
result = self._tracked_events.pop(0)
|
|
||||||
if isinstance(result, ExceptionWrapper):
|
|
||||||
raise result.e
|
|
||||||
|
|
||||||
if not self._tracked_events:
|
|
||||||
self._next_event = coros.event()
|
|
||||||
return result
|
|
||||||
|
|
||||||
def killall(self):
|
|
||||||
for g in self._greenlets:
|
|
||||||
api.kill(g)
|
|
||||||
|
|
||||||
def wait_all(self):
|
|
||||||
"""Wait until all coroutines started either by execute() or
|
|
||||||
execute_async() have completed. If you kept the event objects returned
|
|
||||||
by execute(), you can then call their individual wait() methods to
|
|
||||||
retrieve results with no further actual waiting.
|
|
||||||
|
|
||||||
>>> from eventlet import coros
|
|
||||||
>>> pool = coros.CoroutinePool()
|
|
||||||
>>> pool.wait_all()
|
|
||||||
>>> def hi(name):
|
|
||||||
... print "Hello, %s!" % name
|
|
||||||
... return name
|
|
||||||
...
|
|
||||||
>>> evt = pool.execute(hi, "world")
|
|
||||||
>>> pool.execute_async(hi, "darkness, my old friend")
|
|
||||||
>>> pool.wait_all()
|
|
||||||
Hello, world!
|
|
||||||
Hello, darkness, my old friend!
|
|
||||||
>>> evt.wait()
|
|
||||||
'world'
|
|
||||||
>>> pool.wait_all()
|
|
||||||
"""
|
|
||||||
self.requested.wait()
|
|
||||||
|
|
||||||
def launch_all(self, function, iterable):
|
|
||||||
"""For each tuple (sequence) in iterable, launch function(*tuple) in
|
|
||||||
its own coroutine -- like itertools.starmap(), but in parallel.
|
|
||||||
Discard values returned by function(). You should call wait_all() to
|
|
||||||
wait for all coroutines, newly-launched plus any previously-submitted
|
|
||||||
execute() or execute_async() calls, to complete.
|
|
||||||
|
|
||||||
>>> from eventlet import coros
|
|
||||||
>>> pool = coros.CoroutinePool()
|
|
||||||
>>> def saw(x):
|
|
||||||
... print "I saw %s!" % x
|
|
||||||
...
|
|
||||||
>>> pool.launch_all(saw, "ABC")
|
|
||||||
>>> pool.wait_all()
|
|
||||||
I saw A!
|
|
||||||
I saw B!
|
|
||||||
I saw C!
|
|
||||||
"""
|
|
||||||
for tup in iterable:
|
|
||||||
self.execute_async(function, *tup)
|
|
||||||
|
|
||||||
def process_all(self, function, iterable):
|
|
||||||
"""For each tuple (sequence) in iterable, launch function(*tuple) in
|
|
||||||
its own coroutine -- like itertools.starmap(), but in parallel.
|
|
||||||
Discard values returned by function(). Don't return until all
|
|
||||||
coroutines, newly-launched plus any previously-submitted execute() or
|
|
||||||
execute_async() calls, have completed.
|
|
||||||
|
|
||||||
>>> from eventlet import coros
|
|
||||||
>>> pool = coros.CoroutinePool()
|
|
||||||
>>> def saw(x): print "I saw %s!" % x
|
|
||||||
...
|
|
||||||
>>> pool.process_all(saw, "DEF")
|
|
||||||
I saw D!
|
|
||||||
I saw E!
|
|
||||||
I saw F!
|
|
||||||
"""
|
|
||||||
self.launch_all(function, iterable)
|
|
||||||
self.wait_all()
|
|
||||||
|
|
||||||
def generate_results(self, function, iterable, qsize=None):
|
|
||||||
"""For each tuple (sequence) in iterable, launch function(*tuple) in
|
|
||||||
its own coroutine -- like itertools.starmap(), but in parallel.
|
|
||||||
Yield each of the values returned by function(), in the order they're
|
|
||||||
completed rather than the order the coroutines were launched.
|
|
||||||
|
|
||||||
Iteration stops when we've yielded results for each arguments tuple in
|
|
||||||
iterable. Unlike wait_all() and process_all(), this function does not
|
|
||||||
wait for any previously-submitted execute() or execute_async() calls.
|
|
||||||
|
|
||||||
Results are temporarily buffered in a queue. If you pass qsize=, this
|
|
||||||
value is used to limit the max size of the queue: an attempt to buffer
|
|
||||||
too many results will suspend the completed CoroutinePool coroutine
|
|
||||||
until the requesting coroutine (the caller of generate_results()) has
|
|
||||||
retrieved one or more results by calling this generator-iterator's
|
|
||||||
next().
|
|
||||||
|
|
||||||
If any coroutine raises an uncaught exception, that exception will
|
|
||||||
propagate to the requesting coroutine via the corresponding next() call.
|
|
||||||
|
|
||||||
What I particularly want these tests to illustrate is that using this
|
|
||||||
generator function:
|
|
||||||
|
|
||||||
for result in generate_results(function, iterable):
|
|
||||||
# ... do something with result ...
|
|
||||||
|
|
||||||
executes coroutines at least as aggressively as the classic eventlet
|
|
||||||
idiom:
|
|
||||||
|
|
||||||
events = [pool.execute(function, *args) for args in iterable]
|
|
||||||
for event in events:
|
|
||||||
result = event.wait()
|
|
||||||
# ... do something with result ...
|
|
||||||
|
|
||||||
even without a distinct event object for every arg tuple in iterable,
|
|
||||||
and despite the funny flow control from interleaving launches of new
|
|
||||||
coroutines with yields of completed coroutines' results.
|
|
||||||
|
|
||||||
(The use case that makes this function preferable to the classic idiom
|
|
||||||
above is when the iterable, which may itself be a generator, produces
|
|
||||||
millions of items.)
|
|
||||||
|
|
||||||
>>> from eventlet import coros
|
|
||||||
>>> import string
|
|
||||||
>>> pool = coros.CoroutinePool(max_size=5)
|
|
||||||
>>> pausers = [coros.event() for x in xrange(2)]
|
|
||||||
>>> def longtask(evt, desc):
|
|
||||||
... print "%s woke up with %s" % (desc, evt.wait())
|
|
||||||
...
|
|
||||||
>>> pool.launch_all(longtask, zip(pausers, "AB"))
|
|
||||||
>>> def quicktask(desc):
|
|
||||||
... print "returning %s" % desc
|
|
||||||
... return desc
|
|
||||||
...
|
|
||||||
|
|
||||||
(Instead of using a for loop, step through generate_results()
|
|
||||||
items individually to illustrate timing)
|
|
||||||
|
|
||||||
>>> step = iter(pool.generate_results(quicktask, string.ascii_lowercase))
|
|
||||||
>>> print step.next()
|
|
||||||
returning a
|
|
||||||
returning b
|
|
||||||
returning c
|
|
||||||
a
|
|
||||||
>>> print step.next()
|
|
||||||
b
|
|
||||||
>>> print step.next()
|
|
||||||
c
|
|
||||||
>>> print step.next()
|
|
||||||
returning d
|
|
||||||
returning e
|
|
||||||
returning f
|
|
||||||
d
|
|
||||||
>>> pausers[0].send("A")
|
|
||||||
>>> print step.next()
|
|
||||||
e
|
|
||||||
>>> print step.next()
|
|
||||||
f
|
|
||||||
>>> print step.next()
|
|
||||||
A woke up with A
|
|
||||||
returning g
|
|
||||||
returning h
|
|
||||||
returning i
|
|
||||||
g
|
|
||||||
>>> print "".join([step.next() for x in xrange(3)])
|
|
||||||
returning j
|
|
||||||
returning k
|
|
||||||
returning l
|
|
||||||
returning m
|
|
||||||
hij
|
|
||||||
>>> pausers[1].send("B")
|
|
||||||
>>> print "".join([step.next() for x in xrange(4)])
|
|
||||||
B woke up with B
|
|
||||||
returning n
|
|
||||||
returning o
|
|
||||||
returning p
|
|
||||||
returning q
|
|
||||||
klmn
|
|
||||||
"""
|
|
||||||
# Get an iterator because of our funny nested loop below. Wrap the
|
|
||||||
# iterable in enumerate() so we count items that come through.
|
|
||||||
tuples = iter(enumerate(iterable))
|
|
||||||
# If the iterable is empty, this whole function is a no-op, and we can
|
|
||||||
# save ourselves some grief by just quitting out. In particular, once
|
|
||||||
# we enter the outer loop below, we're going to wait on the queue --
|
|
||||||
# but if we launched no coroutines with that queue as the destination,
|
|
||||||
# we could end up waiting a very long time.
|
|
||||||
try:
|
|
||||||
index, args = tuples.next()
|
|
||||||
except StopIteration:
|
|
||||||
return
|
|
||||||
# From this point forward, 'args' is the current arguments tuple and
|
|
||||||
# 'index+1' counts how many such tuples we've seen.
|
|
||||||
# This implementation relies on the fact that _execute() accepts an
|
|
||||||
# event-like object, and -- unless it's None -- the completed
|
|
||||||
# coroutine calls send(result). We slyly pass a queue rather than an
|
|
||||||
# event -- the same queue instance for all coroutines. This is why our
|
|
||||||
# queue interface intentionally resembles the event interface.
|
|
||||||
q = coros.queue(max_size=qsize)
|
|
||||||
# How many results have we yielded so far?
|
|
||||||
finished = 0
|
|
||||||
# This first loop is only until we've launched all the coroutines. Its
|
|
||||||
# complexity is because if iterable contains more args tuples than the
|
|
||||||
# size of our pool, attempting to _execute() the (poolsize+1)th
|
|
||||||
# coroutine would suspend until something completes and send()s its
|
|
||||||
# result to our queue. But to keep down queue overhead and to maximize
|
|
||||||
# responsiveness to our caller, we'd rather suspend on reading the
|
|
||||||
# queue. So we stuff the pool as full as we can, then wait for
|
|
||||||
# something to finish, then stuff more coroutines into the pool.
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
# Before each yield, start as many new coroutines as we can fit.
|
|
||||||
# (The self.free() test isn't 100% accurate: if we happen to be
|
|
||||||
# executing in one of the pool's coroutines, we could _execute()
|
|
||||||
# without waiting even if self.free() reports 0. See _execute().)
|
|
||||||
# The point is that we don't want to wait in the _execute() call,
|
|
||||||
# we want to wait in the q.wait() call.
|
|
||||||
# IMPORTANT: at start, and whenever we've caught up with all
|
|
||||||
# coroutines we've launched so far, we MUST iterate this inner
|
|
||||||
# loop at least once, regardless of self.free() -- otherwise the
|
|
||||||
# q.wait() call below will deadlock!
|
|
||||||
# Recall that index is the index of the NEXT args tuple that we
|
|
||||||
# haven't yet launched. Therefore it counts how many args tuples
|
|
||||||
# we've launched so far.
|
|
||||||
while self.free() > 0 or finished == index:
|
|
||||||
# Just like the implementation of execute_async(), save that
|
|
||||||
# we're passing our queue instead of None as the "event" to
|
|
||||||
# which to send() the result.
|
|
||||||
self._execute(q, function, args, {})
|
|
||||||
# We've consumed that args tuple, advance to next.
|
|
||||||
index, args = tuples.next()
|
|
||||||
# Okay, we've filled up the pool again, yield a result -- which
|
|
||||||
# will probably wait for a coroutine to complete. Although we do
|
|
||||||
# have q.ready(), so we could iterate without waiting, we avoid
|
|
||||||
# that because every yield could involve considerable real time.
|
|
||||||
# We don't know how long it takes to return from yield, so every
|
|
||||||
# time we do, take the opportunity to stuff more requests into the
|
|
||||||
# pool before yielding again.
|
|
||||||
yield q.wait()
|
|
||||||
# Be sure to count results so we know when to stop!
|
|
||||||
finished += 1
|
|
||||||
except StopIteration:
|
|
||||||
pass
|
|
||||||
# Here we've exhausted the input iterable. index+1 is the total number
|
|
||||||
# of coroutines we've launched. We probably haven't yielded that many
|
|
||||||
# results yet. Wait for the rest of the results, yielding them as they
|
|
||||||
# arrive.
|
|
||||||
while finished < index + 1:
|
|
||||||
yield q.wait()
|
|
||||||
finished += 1
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
@@ -683,6 +683,9 @@ class RunningProcSet(object):
|
|||||||
for p in self.args[0]:
|
for p in self.args[0]:
|
||||||
p.link(lambda p: self.procs.discard(p))
|
p.link(lambda p: self.procs.discard(p))
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.procs)
|
||||||
|
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
if isinstance(item, api.Greenlet):
|
if isinstance(item, api.Greenlet):
|
||||||
# special case for "api.getcurrent() in running_proc_set" to work
|
# special case for "api.getcurrent() in running_proc_set" to work
|
||||||
|
@@ -1,36 +1,30 @@
|
|||||||
"""\
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
@file processes.py
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# in the Software without restriction, including without limitation the rights
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
in the Software without restriction, including without limitation the rights
|
# furnished to do so, subject to the following conditions:
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
#
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
# The above copyright notice and this permission notice shall be included in
|
||||||
furnished to do so, subject to the following conditions:
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
The above copyright notice and this permission notice shall be included in
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
all copies or substantial portions of the Software.
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# THE SOFTWARE.
|
||||||
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 errno
|
import errno
|
||||||
import os
|
import os
|
||||||
import popen2
|
import popen2
|
||||||
import signal
|
import signal
|
||||||
import sys
|
|
||||||
|
|
||||||
from eventlet import coros
|
from eventlet import coros
|
||||||
from eventlet import pools
|
from eventlet import pools
|
||||||
from eventlet import greenio
|
from eventlet import greenio
|
||||||
from eventlet import util
|
|
||||||
|
|
||||||
|
|
||||||
class DeadProcess(RuntimeError):
|
class DeadProcess(RuntimeError):
|
||||||
|
@@ -1,29 +1,28 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file saranwrap.py
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
@author Phoenix
|
@author Phoenix
|
||||||
@date 2007-07-13
|
@date 2007-07-13
|
||||||
@brief A simple, pickle based rpc mechanism which reflects python
|
@brief A simple, pickle based rpc mechanism which reflects python objects and
|
||||||
objects and callables.
|
callables.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
This file provides classes and exceptions used for simple python level
|
This file provides classes and exceptions used for simple python level
|
||||||
remote procedure calls. This is achieved by intercepting the basic
|
remote procedure calls. This is achieved by intercepting the basic
|
||||||
@@ -91,12 +90,6 @@ import os
|
|||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
|
||||||
set = set
|
|
||||||
frozenset = frozenset
|
|
||||||
except NameError:
|
|
||||||
from sets import Set as set, ImmutableSet as frozenset
|
|
||||||
|
|
||||||
from eventlet.processes import Process, DeadProcess
|
from eventlet.processes import Process, DeadProcess
|
||||||
from eventlet import api, pools
|
from eventlet import api, pools
|
||||||
|
|
||||||
@@ -282,7 +275,7 @@ class ChildProcess(object):
|
|||||||
retval = _read_response(_id, attribute, self._in, self)
|
retval = _read_response(_id, attribute, self._in, self)
|
||||||
finally:
|
finally:
|
||||||
self._lock.put(t)
|
self._lock.put(t)
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
@@ -330,7 +323,7 @@ not supported, so you have to know what has been exported.
|
|||||||
_dead_list.remove(dead_object)
|
_dead_list.remove(dead_object)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Pass all public attributes across to find out if it is
|
# Pass all public attributes across to find out if it is
|
||||||
# callable or a simple attribute.
|
# callable or a simple attribute.
|
||||||
request = Request('getattr', {'id':my_id, 'attribute':attribute})
|
request = Request('getattr', {'id':my_id, 'attribute':attribute})
|
||||||
@@ -339,7 +332,7 @@ not supported, so you have to know what has been exported.
|
|||||||
def __setattr__(self, attribute, value):
|
def __setattr__(self, attribute, value):
|
||||||
#_prnt("Proxy::__setattr__: %s" % attribute)
|
#_prnt("Proxy::__setattr__: %s" % attribute)
|
||||||
if _is_local(attribute):
|
if _is_local(attribute):
|
||||||
# It must be local to this actual object, so we have to apply
|
# It must be local to this actual object, so we have to apply
|
||||||
# it to the dict in a roundabout way
|
# it to the dict in a roundabout way
|
||||||
attribute = _unmunge_attr_name(attribute)
|
attribute = _unmunge_attr_name(attribute)
|
||||||
super(Proxy, self).__getattribute__('__dict__')[attribute]=value
|
super(Proxy, self).__getattribute__('__dict__')[attribute]=value
|
||||||
@@ -377,7 +370,7 @@ not need to deal with this class directly."""
|
|||||||
my_id = self.__local_dict['_id']
|
my_id = self.__local_dict['_id']
|
||||||
request = Request('getitem', {'id':my_id, 'key':key})
|
request = Request('getitem', {'id':my_id, 'key':key})
|
||||||
return my_cp.make_request(request, attribute=key)
|
return my_cp.make_request(request, attribute=key)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
my_cp = self.__local_dict['_cp']
|
my_cp = self.__local_dict['_cp']
|
||||||
my_id = self.__local_dict['_id']
|
my_id = self.__local_dict['_id']
|
||||||
@@ -429,7 +422,7 @@ not need to deal with this class directly."""
|
|||||||
# since the remote object is being serialized whole anyway,
|
# since the remote object is being serialized whole anyway,
|
||||||
# there's no semantic difference between copy and deepcopy
|
# there's no semantic difference between copy and deepcopy
|
||||||
__copy__ = __deepcopy__
|
__copy__ = __deepcopy__
|
||||||
|
|
||||||
|
|
||||||
def proxied_type(self):
|
def proxied_type(self):
|
||||||
""" Returns the type of the object in the child process.
|
""" Returns the type of the object in the child process.
|
||||||
@@ -439,7 +432,7 @@ def proxied_type(self):
|
|||||||
'real' type value."""
|
'real' type value."""
|
||||||
if type(self) is not ObjectProxy:
|
if type(self) is not ObjectProxy:
|
||||||
return type(self)
|
return type(self)
|
||||||
|
|
||||||
my_cp = self.__local_dict['_cp']
|
my_cp = self.__local_dict['_cp']
|
||||||
my_id = self.__local_dict['_id']
|
my_id = self.__local_dict['_id']
|
||||||
request = Request('type', {'id':my_id})
|
request = Request('type', {'id':my_id})
|
||||||
@@ -506,7 +499,7 @@ when the id is None."""
|
|||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
#_log('getattr: %s' % str(response))
|
#_log('getattr: %s' % str(response))
|
||||||
|
|
||||||
def handle_setattr(self, obj, req):
|
def handle_setattr(self, obj, req):
|
||||||
try:
|
try:
|
||||||
return setattr(obj, req['attribute'], req['value'])
|
return setattr(obj, req['attribute'], req['value'])
|
||||||
@@ -541,7 +534,7 @@ when the id is None."""
|
|||||||
fn = obj[req['name']]
|
fn = obj[req['name']]
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
return fn(*req['args'],**req['kwargs'])
|
return fn(*req['args'],**req['kwargs'])
|
||||||
|
|
||||||
def handle_del(self, obj, req):
|
def handle_del(self, obj, req):
|
||||||
|
@@ -1,36 +1,30 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file support.pylib.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2005-2006, Donovan Preston
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Donovan Preston
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from py.magic import greenlet
|
from py.magic import greenlet
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
|
||||||
def emulate():
|
def emulate():
|
||||||
module = types.ModuleType('greenlet')
|
module = types.ModuleType('greenlet')
|
||||||
sys.modules['greenlet'] = module
|
sys.modules['greenlet'] = module
|
||||||
@@ -38,5 +32,3 @@ def emulate():
|
|||||||
module.getcurrent = greenlet.getcurrent
|
module.getcurrent = greenlet.getcurrent
|
||||||
module.GreenletExit = greenlet.GreenletExit
|
module.GreenletExit = greenlet.GreenletExit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,35 +1,29 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file stacklesspypysupport.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2008, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2008, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from stackless import greenlet
|
from stackless import greenlet
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
|
||||||
def emulate():
|
def emulate():
|
||||||
module = types.ModuleType('greenlet')
|
module = types.ModuleType('greenlet')
|
||||||
sys.modules['greenlet'] = module
|
sys.modules['greenlet'] = module
|
||||||
@@ -37,8 +31,3 @@ def emulate():
|
|||||||
module.getcurrent = greenlet.getcurrent
|
module.getcurrent = greenlet.getcurrent
|
||||||
module.GreenletExit = greenlet.GreenletExit
|
module.GreenletExit = greenlet.GreenletExit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,41 +1,34 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file __init__.py
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@brief Support for using stackless python. Broken and riddled with
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
print statements at the moment. Please fix it!
|
# 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.
|
||||||
|
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
"""
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Support for using stackless python. Broken and riddled with print statements
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
at the moment. Please fix it!
|
||||||
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 sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
import stackless
|
import stackless
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
caller = None
|
caller = None
|
||||||
|
|
||||||
|
|
||||||
coro_args = {}
|
coro_args = {}
|
||||||
|
|
||||||
|
|
||||||
tasklet_to_greenlet = {}
|
tasklet_to_greenlet = {}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,142 +0,0 @@
|
|||||||
"""\
|
|
||||||
@file support.twisted.py
|
|
||||||
@author Donovan Preston
|
|
||||||
|
|
||||||
Copyright (c) 2005-2006, Donovan Preston
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
from eventlet import api
|
|
||||||
from eventlet import timer
|
|
||||||
|
|
||||||
from twisted.internet import posixbase
|
|
||||||
from twisted.internet.interfaces import IReactorFDSet
|
|
||||||
|
|
||||||
try:
|
|
||||||
from zope.interface import implements
|
|
||||||
_working = True
|
|
||||||
except ImportError:
|
|
||||||
_working = False
|
|
||||||
def implements(*args, **kw):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TwistedTimer(object):
|
|
||||||
def __init__(self, timer):
|
|
||||||
self.timer = timer
|
|
||||||
|
|
||||||
def cancel(self):
|
|
||||||
self.timer.cancel()
|
|
||||||
|
|
||||||
def getTime(self):
|
|
||||||
return self.timer.scheduled_time
|
|
||||||
|
|
||||||
def delay(self, seconds):
|
|
||||||
hub = api.get_hub()
|
|
||||||
new_time = hub.clock() - self.timer_scheduled_time + seconds
|
|
||||||
self.timer.cancel()
|
|
||||||
cb, args, kw = self.timer.tpl
|
|
||||||
self.timer = hub.schedule_call(new_time, cb, *args, **kw)
|
|
||||||
|
|
||||||
def reset(self, new_time):
|
|
||||||
self.timer.cancel()
|
|
||||||
cb, args, kw = self.timer.tpl
|
|
||||||
self.timer = api.get_hub().schedule_call(new_time, cb, *args, **kw)
|
|
||||||
|
|
||||||
def active(self):
|
|
||||||
return not self.timer.called
|
|
||||||
|
|
||||||
|
|
||||||
class EventletReactor(posixbase.PosixReactorBase):
|
|
||||||
implements(IReactorFDSet)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kw):
|
|
||||||
self._readers = {}
|
|
||||||
self._writers = {}
|
|
||||||
posixbase.PosixReactorBase.__init__(self, *args, **kw)
|
|
||||||
|
|
||||||
def callLater(self, func, *args, **kw):
|
|
||||||
return TwistedTimer(api.call_after(func, *args, **kw))
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.running = True
|
|
||||||
self._stopper = api.call_after(sys.maxint / 1000.0, lambda: None)
|
|
||||||
## schedule a call way in the future, and cancel it in stop?
|
|
||||||
api.get_hub().run()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self._stopper.cancel()
|
|
||||||
posixbase.PosixReactorBase.stop(self)
|
|
||||||
api.get_hub().remove_descriptor(self._readers.keys()[0])
|
|
||||||
api.get_hub().abort()
|
|
||||||
|
|
||||||
def addReader(self, reader):
|
|
||||||
print "NEW READER", reader.fileno()
|
|
||||||
fileno = reader.fileno()
|
|
||||||
self._readers[fileno] = reader
|
|
||||||
api.get_hub().add_descriptor(fileno, read=self._got_read)
|
|
||||||
|
|
||||||
def _got_read(self, fileno):
|
|
||||||
print "got read on", fileno, self._readers[fileno]
|
|
||||||
api.get_hub().add_descriptor(fileno, read=self._got_read)
|
|
||||||
self._readers[fileno].doRead()
|
|
||||||
|
|
||||||
def addWriter(self, writer):
|
|
||||||
print "NEW WRITER", writer.fileno()
|
|
||||||
fileno = writer.fileno()
|
|
||||||
self._writers[fileno] = writer
|
|
||||||
api.get_hub().add_descriptor(fileno, write=self._got_write)
|
|
||||||
|
|
||||||
def _got_write(self, fileno):
|
|
||||||
print "got write on", fileno, self._writers[fileno]
|
|
||||||
api.get_hub().add_descriptor(fileno, write=self._got_write)
|
|
||||||
self._writers[fileno].doWrite()
|
|
||||||
|
|
||||||
def removeReader(self, reader):
|
|
||||||
print "removing reader", reader.fileno()
|
|
||||||
fileno = reader.fileno()
|
|
||||||
if fileno in self._readers:
|
|
||||||
self._readers.pop(fileno)
|
|
||||||
api.get_hub().remove_descriptor(fileno)
|
|
||||||
|
|
||||||
def removeWriter(self, writer):
|
|
||||||
print "removing writer", writer.fileno()
|
|
||||||
fileno = writer.fileno()
|
|
||||||
if fileno in self._writers:
|
|
||||||
self._writers.pop(fileno)
|
|
||||||
api.get_hub().remove_descriptor(fileno)
|
|
||||||
|
|
||||||
def removeAll(self):
|
|
||||||
return self._removeAll(self._readers.values(), self._writers.values())
|
|
||||||
|
|
||||||
|
|
||||||
def install():
|
|
||||||
if not _working:
|
|
||||||
raise RuntimeError, "Can't use support.twisted because zope.interface is not installed."
|
|
||||||
reactor = EventletReactor()
|
|
||||||
from twisted.internet.main import installReactor
|
|
||||||
installReactor(reactor)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['install']
|
|
||||||
|
|
@@ -1,27 +1,25 @@
|
|||||||
"""\
|
# @author Bob Ippolito
|
||||||
@file timer.py
|
#
|
||||||
@author Bob Ippolito
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
|
# 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.
|
||||||
|
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
from eventlet.api import get_hub, getcurrent
|
from eventlet.api import get_hub, getcurrent
|
||||||
|
|
||||||
""" If true, captures a stack trace for each timer when constructed. This is
|
""" If true, captures a stack trace for each timer when constructed. This is
|
||||||
@@ -95,7 +93,7 @@ class Timer(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class LocalTimer(Timer):
|
class LocalTimer(Timer):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.greenlet = getcurrent()
|
self.greenlet = getcurrent()
|
||||||
Timer.__init__(self, *args, **kwargs)
|
Timer.__init__(self, *args, **kwargs)
|
||||||
|
@@ -1,21 +1,17 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file tpool.py
|
# Copyright (c) 2007, IBM Corp.
|
||||||
|
#
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Copyright (c) 2007, IBM Corp.
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
#
|
||||||
you may not use this file except in compliance with the License.
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
You may obtain a copy of the License at
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
Unless required by applicable law or agreed to in writing, software
|
# See the License for the specific language governing permissions and
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
# limitations under the License.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
@@ -75,7 +71,7 @@ def tworker():
|
|||||||
except SYS_EXCS:
|
except SYS_EXCS:
|
||||||
raise
|
raise
|
||||||
except Exception,exn:
|
except Exception,exn:
|
||||||
import sys, traceback
|
import sys
|
||||||
(a,b,tb) = sys.exc_info()
|
(a,b,tb) = sys.exc_info()
|
||||||
rv = (exn,a,b,tb)
|
rv = (exn,a,b,tb)
|
||||||
_rspq.put((e,rv))
|
_rspq.put((e,rv))
|
||||||
@@ -86,7 +82,7 @@ def tworker():
|
|||||||
def erecv(e):
|
def erecv(e):
|
||||||
rv = e.wait()
|
rv = e.wait()
|
||||||
if isinstance(rv,tuple) and len(rv) == 4 and isinstance(rv[0],Exception):
|
if isinstance(rv,tuple) and len(rv) == 4 and isinstance(rv[0],Exception):
|
||||||
import sys, traceback
|
import traceback
|
||||||
(e,a,b,tb) = rv
|
(e,a,b,tb) = rv
|
||||||
if not QUIET:
|
if not QUIET:
|
||||||
traceback.print_exception(Exception,e,tb)
|
traceback.print_exception(Exception,e,tb)
|
||||||
|
@@ -1,32 +1,28 @@
|
|||||||
"""\
|
# @author Bob Ippolito
|
||||||
@file util.py
|
#
|
||||||
@author Bob Ippolito
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import select
|
import select
|
||||||
import socket
|
import socket
|
||||||
import sys
|
|
||||||
import errno
|
import errno
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -81,7 +77,7 @@ except AttributeError:
|
|||||||
|
|
||||||
def wrap_ssl(sock, certificate=None, private_key=None):
|
def wrap_ssl(sock, certificate=None, private_key=None):
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
from eventlet import greenio, util
|
from eventlet import greenio
|
||||||
context = SSL.Context(SSL.SSLv23_METHOD)
|
context = SSL.Context(SSL.SSLv23_METHOD)
|
||||||
if certificate is not None:
|
if certificate is not None:
|
||||||
context.use_certificate_file(certificate)
|
context.use_certificate_file(certificate)
|
||||||
@@ -174,7 +170,7 @@ def wrap_pipes_with_coroutine_pipes():
|
|||||||
return pid, evt.wait()
|
return pid, evt.wait()
|
||||||
return 0, 0
|
return 0, 0
|
||||||
elif options:
|
elif options:
|
||||||
return __original_waitpid__(pid, result)
|
return __original_waitpid__(pid, options)
|
||||||
return pid, evt.wait()
|
return pid, evt.wait()
|
||||||
os.fdopen = new_fdopen
|
os.fdopen = new_fdopen
|
||||||
os.read = new_read
|
os.read = new_read
|
||||||
@@ -238,7 +234,7 @@ def wrap_threading_local_with_coro_local():
|
|||||||
class local(object):
|
class local(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__dict__['__objs'] = {}
|
self.__dict__['__objs'] = {}
|
||||||
|
|
||||||
def __getattr__(self, attr, g=get_ident):
|
def __getattr__(self, attr, g=get_ident):
|
||||||
try:
|
try:
|
||||||
return self.__dict__['__objs'][g()][attr]
|
return self.__dict__['__objs'][g()][attr]
|
||||||
@@ -246,10 +242,10 @@ def wrap_threading_local_with_coro_local():
|
|||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
"No variable %s defined for the thread %s"
|
"No variable %s defined for the thread %s"
|
||||||
% (attr, g()))
|
% (attr, g()))
|
||||||
|
|
||||||
def __setattr__(self, attr, value, g=get_ident):
|
def __setattr__(self, attr, value, g=get_ident):
|
||||||
self.__dict__['__objs'].setdefault(g(), {})[attr] = value
|
self.__dict__['__objs'].setdefault(g(), {})[attr] = value
|
||||||
|
|
||||||
def __delattr__(self, attr, g=get_ident):
|
def __delattr__(self, attr, g=get_ident):
|
||||||
try:
|
try:
|
||||||
del self.__dict__['__objs'][g()][attr]
|
del self.__dict__['__objs'][g()][attr]
|
||||||
|
@@ -1,27 +1,24 @@
|
|||||||
"""\
|
# @author Bob Ippolito
|
||||||
@file wsgi.py
|
#
|
||||||
@author Bob Ippolito
|
# Copyright (c) 2005-2006, Bob Ippolito
|
||||||
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
Copyright (c) 2005-2006, Bob Ippolito
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
@@ -124,7 +121,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
if e[0] != errno.EBADF:
|
if e[0] != errno.EBADF:
|
||||||
raise
|
raise
|
||||||
self.raw_requestline = ''
|
self.raw_requestline = ''
|
||||||
|
|
||||||
if not self.raw_requestline:
|
if not self.raw_requestline:
|
||||||
self.close_connection = 1
|
self.close_connection = 1
|
||||||
return
|
return
|
||||||
@@ -254,7 +251,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
start_response("500 Internal Server Error", [('Content-type', 'text/plain')])
|
start_response("500 Internal Server Error", [('Content-type', 'text/plain')])
|
||||||
write(exc)
|
write(exc)
|
||||||
return
|
return
|
||||||
|
|
||||||
if towrite:
|
if towrite:
|
||||||
write(''.join(towrite))
|
write(''.join(towrite))
|
||||||
if not headers_sent:
|
if not headers_sent:
|
||||||
@@ -346,7 +343,7 @@ class Server(BaseHTTPServer.HTTPServer):
|
|||||||
self.log = sys.stderr
|
self.log = sys.stderr
|
||||||
self.app = app
|
self.app = app
|
||||||
self.environ = environ
|
self.environ = environ
|
||||||
self.max_http_version = max_http_version
|
self.max_http_version = max_http_version
|
||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
self.pid = os.getpid()
|
self.pid = os.getpid()
|
||||||
if minimum_chunk_size is not None:
|
if minimum_chunk_size is not None:
|
||||||
|
@@ -1,38 +1,32 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file api_test.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import socket
|
import os.path
|
||||||
|
|
||||||
from eventlet import api
|
from eventlet import api
|
||||||
from eventlet import greenio
|
from eventlet import greenio
|
||||||
from greentest import tests
|
from greentest import tests
|
||||||
from eventlet import util
|
from eventlet import util
|
||||||
|
|
||||||
import os.path
|
|
||||||
import socket
|
|
||||||
|
|
||||||
|
|
||||||
def check_hub():
|
def check_hub():
|
||||||
# Clear through the descriptor queue
|
# Clear through the descriptor queue
|
||||||
@@ -50,10 +44,10 @@ def check_hub():
|
|||||||
|
|
||||||
class TestApi(tests.TestCase):
|
class TestApi(tests.TestCase):
|
||||||
mode = 'static'
|
mode = 'static'
|
||||||
|
|
||||||
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
|
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')
|
private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
|
||||||
|
|
||||||
def test_tcp_listener(self):
|
def test_tcp_listener(self):
|
||||||
socket = api.tcp_listener(('0.0.0.0', 0))
|
socket = api.tcp_listener(('0.0.0.0', 0))
|
||||||
assert socket.getsockname()[0] == '0.0.0.0'
|
assert socket.getsockname()[0] == '0.0.0.0'
|
||||||
@@ -86,27 +80,27 @@ class TestApi(tests.TestCase):
|
|||||||
check_hub()
|
check_hub()
|
||||||
|
|
||||||
def test_connect_ssl(self):
|
def test_connect_ssl(self):
|
||||||
def accept_once(listenfd):
|
def accept_once(listenfd):
|
||||||
try:
|
try:
|
||||||
conn, addr = listenfd.accept()
|
conn, addr = listenfd.accept()
|
||||||
fl = conn.makeGreenFile('w')
|
fl = conn.makeGreenFile('w')
|
||||||
fl.write('hello\r\n')
|
fl.write('hello\r\n')
|
||||||
fl.close()
|
fl.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
finally:
|
finally:
|
||||||
listenfd.close()
|
listenfd.close()
|
||||||
|
|
||||||
server = api.ssl_listener(('0.0.0.0', 0),
|
server = api.ssl_listener(('0.0.0.0', 0),
|
||||||
self.certificate_file,
|
self.certificate_file,
|
||||||
self.private_key_file)
|
self.private_key_file)
|
||||||
api.spawn(accept_once, server)
|
api.spawn(accept_once, server)
|
||||||
|
|
||||||
client = util.wrap_ssl(
|
client = util.wrap_ssl(
|
||||||
api.connect_tcp(('127.0.0.1', server.getsockname()[1])))
|
api.connect_tcp(('127.0.0.1', server.getsockname()[1])))
|
||||||
client = client.makeGreenFile()
|
client = client.makeGreenFile()
|
||||||
|
|
||||||
assert client.readline() == 'hello\r\n'
|
assert client.readline() == 'hello\r\n'
|
||||||
assert client.read() == ''
|
assert client.read() == ''
|
||||||
client.close()
|
client.close()
|
||||||
|
|
||||||
def test_server(self):
|
def test_server(self):
|
||||||
|
@@ -1,32 +1,27 @@
|
|||||||
"""\
|
# @author Donovan Preston, Ryan Williams
|
||||||
@file coros_test.py
|
#
|
||||||
@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.
|
||||||
|
|
||||||
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 tests
|
from greentest import tests
|
||||||
from eventlet import timer
|
|
||||||
from eventlet import coros, api
|
from eventlet import coros, api
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
class TestEvent(tests.TestCase):
|
class TestEvent(tests.TestCase):
|
||||||
mode = 'static'
|
mode = 'static'
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -114,121 +109,6 @@ class TestEvent(tests.TestCase):
|
|||||||
self.assertRaises(api.TimeoutError, evt.wait)
|
self.assertRaises(api.TimeoutError, evt.wait)
|
||||||
|
|
||||||
|
|
||||||
class TestCoroutinePool(tests.TestCase):
|
|
||||||
mode = 'static'
|
|
||||||
def setUp(self):
|
|
||||||
# raise an exception if we're waiting forever
|
|
||||||
self._cancel_timeout = api.exc_after(1, api.TimeoutError)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self._cancel_timeout.cancel()
|
|
||||||
|
|
||||||
def test_execute_async(self):
|
|
||||||
done = coros.event()
|
|
||||||
def some_work():
|
|
||||||
done.send()
|
|
||||||
pool = coros.CoroutinePool(0, 2)
|
|
||||||
pool.execute_async(some_work)
|
|
||||||
done.wait()
|
|
||||||
|
|
||||||
def test_execute(self):
|
|
||||||
value = 'return value'
|
|
||||||
def some_work():
|
|
||||||
return value
|
|
||||||
pool = coros.CoroutinePool(0, 2)
|
|
||||||
worker = pool.execute(some_work)
|
|
||||||
self.assertEqual(value, worker.wait())
|
|
||||||
|
|
||||||
def test_multiple_coros(self):
|
|
||||||
evt = coros.event()
|
|
||||||
results = []
|
|
||||||
def producer():
|
|
||||||
results.append('prod')
|
|
||||||
evt.send()
|
|
||||||
|
|
||||||
def consumer():
|
|
||||||
results.append('cons1')
|
|
||||||
evt.wait()
|
|
||||||
results.append('cons2')
|
|
||||||
|
|
||||||
pool = coros.CoroutinePool(0, 2)
|
|
||||||
done = pool.execute(consumer)
|
|
||||||
pool.execute_async(producer)
|
|
||||||
done.wait()
|
|
||||||
self.assertEquals(['cons1', 'prod', 'cons2'], results)
|
|
||||||
|
|
||||||
# since CoroutinePool does not kill the greenlet, the following does not work
|
|
||||||
# def test_timer_cancel(self):
|
|
||||||
# def some_work():
|
|
||||||
# t = timer.LocalTimer(5, lambda: None)
|
|
||||||
# t.schedule()
|
|
||||||
# return t
|
|
||||||
# pool = coros.CoroutinePool(0, 2)
|
|
||||||
# worker = pool.execute(some_work)
|
|
||||||
# t = worker.wait()
|
|
||||||
# api.sleep(0)
|
|
||||||
# self.assertEquals(t.cancelled, True)
|
|
||||||
|
|
||||||
def test_reentrant(self):
|
|
||||||
pool = coros.CoroutinePool(0,1)
|
|
||||||
def reenter():
|
|
||||||
waiter = pool.execute(lambda a: a, 'reenter')
|
|
||||||
self.assertEqual('reenter', waiter.wait())
|
|
||||||
|
|
||||||
outer_waiter = pool.execute(reenter)
|
|
||||||
outer_waiter.wait()
|
|
||||||
|
|
||||||
evt = coros.event()
|
|
||||||
def reenter_async():
|
|
||||||
pool.execute_async(lambda a: a, 'reenter')
|
|
||||||
evt.send('done')
|
|
||||||
|
|
||||||
pool.execute_async(reenter_async)
|
|
||||||
evt.wait()
|
|
||||||
|
|
||||||
def test_horrible_main_loop_death(self):
|
|
||||||
# testing the case that causes the run_forever
|
|
||||||
# method to exit unwantedly
|
|
||||||
pool = coros.CoroutinePool(min_size=1, max_size=1)
|
|
||||||
def crash(*args, **kw):
|
|
||||||
raise RuntimeError("Whoa")
|
|
||||||
class FakeFile(object):
|
|
||||||
write = crash
|
|
||||||
|
|
||||||
# we're going to do this by causing the traceback.print_exc in
|
|
||||||
# safe_apply to raise an exception and thus exit _main_loop
|
|
||||||
normal_err = sys.stderr
|
|
||||||
try:
|
|
||||||
sys.stderr = FakeFile()
|
|
||||||
waiter = pool.execute(crash)
|
|
||||||
self.assertRaises(RuntimeError, waiter.wait)
|
|
||||||
# the pool should have something free at this point since the
|
|
||||||
# waiter returned
|
|
||||||
self.assertEqual(pool.free(), 1)
|
|
||||||
# shouldn't block when trying to get
|
|
||||||
t = api.exc_after(0.1, api.TimeoutError)
|
|
||||||
self.assert_(pool.get())
|
|
||||||
t.cancel()
|
|
||||||
finally:
|
|
||||||
sys.stderr = normal_err
|
|
||||||
|
|
||||||
def test_track_events(self):
|
|
||||||
pool = coros.CoroutinePool(track_events=True)
|
|
||||||
for x in range(6):
|
|
||||||
pool.execute(lambda n: n, x)
|
|
||||||
for y in range(6):
|
|
||||||
print "wait", y
|
|
||||||
pool.wait()
|
|
||||||
|
|
||||||
def test_track_slow_event(self):
|
|
||||||
pool = coros.CoroutinePool(track_events=True)
|
|
||||||
def slow():
|
|
||||||
api.sleep(0.1)
|
|
||||||
return 'ok'
|
|
||||||
pool.execute(slow)
|
|
||||||
self.assertEquals(pool.wait(), 'ok')
|
|
||||||
|
|
||||||
|
|
||||||
class IncrActor(coros.Actor):
|
class IncrActor(coros.Actor):
|
||||||
def received(self, evt):
|
def received(self, evt):
|
||||||
self.value = getattr(self, 'value', 0) + 1
|
self.value = getattr(self, 'value', 0) + 1
|
||||||
@@ -340,9 +220,11 @@ class TestActor(tests.TestCase):
|
|||||||
self.assertEqual(total[0], 2)
|
self.assertEqual(total[0], 2)
|
||||||
# both coroutines should have been used
|
# both coroutines should have been used
|
||||||
self.assertEqual(self.actor._pool.current_size, 2)
|
self.assertEqual(self.actor._pool.current_size, 2)
|
||||||
|
api.sleep(0)
|
||||||
self.assertEqual(self.actor._pool.free(), 1)
|
self.assertEqual(self.actor._pool.free(), 1)
|
||||||
evt.wait()
|
evt.wait()
|
||||||
self.assertEqual(total[0], 3)
|
self.assertEqual(total[0], 3)
|
||||||
|
api.sleep(0)
|
||||||
self.assertEqual(self.actor._pool.free(), 2)
|
self.assertEqual(self.actor._pool.free(), 2)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -22,8 +22,6 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
from eventlet import api, coros
|
from eventlet import api, coros
|
||||||
from greentest import tests
|
from greentest import tests
|
||||||
from eventlet import db_pool
|
from eventlet import db_pool
|
||||||
|
@@ -1,28 +1,24 @@
|
|||||||
"""\
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
@file greenio_test.py
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# in the Software without restriction, including without limitation the rights
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
in the Software without restriction, including without limitation the rights
|
# furnished to do so, subject to the following conditions:
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
#
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
# The above copyright notice and this permission notice shall be included in
|
||||||
furnished to do so, subject to the following conditions:
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
The above copyright notice and this permission notice shall be included in
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
all copies or substantial portions of the Software.
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# THE SOFTWARE.
|
||||||
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 tests
|
from greentest import tests
|
||||||
from eventlet import api, greenio, util
|
from eventlet import api
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
# TODO try and reuse unit tests from within Python itself
|
# TODO try and reuse unit tests from within Python itself
|
||||||
|
@@ -1,33 +1,28 @@
|
|||||||
"""\
|
# @author Bryan O'Sullivan
|
||||||
@file httpc_test.py
|
#
|
||||||
@author Bryan O'Sullivan
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cgi
|
import cgi
|
||||||
|
|
||||||
from eventlet import api
|
from eventlet import api
|
||||||
from eventlet import httpc
|
from eventlet import httpc
|
||||||
from eventlet import processes
|
|
||||||
from eventlet import util
|
|
||||||
from eventlet import wsgi
|
from eventlet import wsgi
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
@@ -1,27 +1,23 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file httpd_test.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
from eventlet import api
|
from eventlet import api
|
||||||
from eventlet import httpd
|
from eventlet import httpd
|
||||||
@@ -33,8 +29,6 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
from eventlet import greenio
|
|
||||||
|
|
||||||
|
|
||||||
util.wrap_socket_with_coroutine_socket()
|
util.wrap_socket_with_coroutine_socket()
|
||||||
|
|
||||||
@@ -106,7 +100,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
def test_001_server(self):
|
def test_001_server(self):
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
||||||
result = fd.read()
|
result = fd.read()
|
||||||
@@ -118,7 +112,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
def test_002_keepalive(self):
|
def test_002_keepalive(self):
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
read_http(sock)
|
read_http(sock)
|
||||||
@@ -130,7 +124,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
# This should go in greenio_test
|
# This should go in greenio_test
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
cancel = api.exc_after(1, RuntimeError)
|
cancel = api.exc_after(1, RuntimeError)
|
||||||
@@ -172,7 +166,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
status = result.split(' ')[1]
|
status = result.split(' ')[1]
|
||||||
self.assertEqual(status, '414')
|
self.assertEqual(status, '414')
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
def test_007_get_arg(self):
|
def test_007_get_arg(self):
|
||||||
# define a new handler that does a get_arg as well as a read_body
|
# define a new handler that does a get_arg as well as a read_body
|
||||||
def new_handle_request(req):
|
def new_handle_request(req):
|
||||||
@@ -180,28 +174,28 @@ class TestHttpd(tests.TestCase):
|
|||||||
body = req.read_body()
|
body = req.read_body()
|
||||||
req.write('a is %s, body is %s' % (a, body))
|
req.write('a is %s, body is %s' % (a, body))
|
||||||
self.site.handle_request = new_handle_request
|
self.site.handle_request = new_handle_request
|
||||||
|
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
request = '\r\n'.join((
|
request = '\r\n'.join((
|
||||||
'POST /%s HTTP/1.0',
|
'POST /%s HTTP/1.0',
|
||||||
'Host: localhost',
|
'Host: localhost',
|
||||||
'Content-Length: 3',
|
'Content-Length: 3',
|
||||||
'',
|
'',
|
||||||
'a=a'))
|
'a=a'))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write(request)
|
fd.write(request)
|
||||||
|
|
||||||
# send some junk after the actual request
|
# send some junk after the actual request
|
||||||
fd.write('01234567890123456789')
|
fd.write('01234567890123456789')
|
||||||
reqline, headers, body = read_http(sock)
|
reqline, headers, body = read_http(sock)
|
||||||
self.assertEqual(body, 'a is a, body is a=a')
|
self.assertEqual(body, 'a is a, body is a=a')
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
def test_008_correctresponse(self):
|
def test_008_correctresponse(self):
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
response_line_200,_,_ = read_http(sock)
|
response_line_200,_,_ = read_http(sock)
|
||||||
|
@@ -93,7 +93,6 @@ def main(db):
|
|||||||
'parsed_command_record.id=command_record.id)')
|
'parsed_command_record.id=command_record.id)')
|
||||||
for row in c.execute(SQL).fetchall():
|
for row in c.execute(SQL).fetchall():
|
||||||
id, command, stdout, exitcode = row
|
id, command, stdout, exitcode = row
|
||||||
stdout = stdout.encode()
|
|
||||||
try:
|
try:
|
||||||
testname, hub = parse_stdout(stdout)
|
testname, hub = parse_stdout(stdout)
|
||||||
if unittest_delim in stdout:
|
if unittest_delim in stdout:
|
||||||
|
@@ -1,35 +1,29 @@
|
|||||||
"""\
|
# @author Donovan Preston, Aaron Brashears
|
||||||
@file test_pools.py
|
#
|
||||||
@author Donovan Preston, Aaron Brashears
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from eventlet import api
|
from eventlet import api
|
||||||
from eventlet import channel
|
from eventlet import channel
|
||||||
from eventlet import coros
|
from eventlet import coros
|
||||||
from eventlet import pools
|
from eventlet import pools
|
||||||
from greentest import tests
|
from greentest import tests
|
||||||
from eventlet import timer
|
|
||||||
|
|
||||||
class IntPool(pools.Pool):
|
class IntPool(pools.Pool):
|
||||||
def create(self):
|
def create(self):
|
||||||
@@ -240,190 +234,6 @@ class TestFan(tests.TestCase):
|
|||||||
self.assertRaises(pools.SomeFailed, self.pool.fan, my_failing_callable, range(4))
|
self.assertRaises(pools.SomeFailed, self.pool.fan, my_failing_callable, range(4))
|
||||||
|
|
||||||
|
|
||||||
class TestCoroutinePool(tests.TestCase):
|
|
||||||
mode = 'static'
|
|
||||||
def setUp(self):
|
|
||||||
# raise an exception if we're waiting forever
|
|
||||||
self._cancel_timeout = api.exc_after(1, TestTookTooLong())
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self._cancel_timeout.cancel()
|
|
||||||
|
|
||||||
def test_execute_async(self):
|
|
||||||
done = coros.event()
|
|
||||||
def some_work():
|
|
||||||
done.send()
|
|
||||||
pool = pools.CoroutinePool(0, 2)
|
|
||||||
pool.execute_async(some_work)
|
|
||||||
done.wait()
|
|
||||||
|
|
||||||
def test_execute(self):
|
|
||||||
value = 'return value'
|
|
||||||
def some_work():
|
|
||||||
return value
|
|
||||||
pool = pools.CoroutinePool(0, 2)
|
|
||||||
worker = pool.execute(some_work)
|
|
||||||
self.assertEqual(value, worker.wait())
|
|
||||||
|
|
||||||
def test_multiple_coros(self):
|
|
||||||
evt = coros.event()
|
|
||||||
results = []
|
|
||||||
def producer():
|
|
||||||
results.append('prod')
|
|
||||||
evt.send()
|
|
||||||
|
|
||||||
def consumer():
|
|
||||||
results.append('cons1')
|
|
||||||
evt.wait()
|
|
||||||
results.append('cons2')
|
|
||||||
|
|
||||||
pool = pools.CoroutinePool(0, 2)
|
|
||||||
done = pool.execute(consumer)
|
|
||||||
pool.execute_async(producer)
|
|
||||||
done.wait()
|
|
||||||
self.assertEquals(['cons1', 'prod', 'cons2'], results)
|
|
||||||
|
|
||||||
def test_timer_cancel(self):
|
|
||||||
timer_fired = []
|
|
||||||
def fire_timer():
|
|
||||||
timer_fired.append(True)
|
|
||||||
def some_work():
|
|
||||||
api.get_hub().schedule_call_local(0, fire_timer)
|
|
||||||
pool = pools.CoroutinePool(0, 2)
|
|
||||||
worker = pool.execute(some_work)
|
|
||||||
worker.wait()
|
|
||||||
api.sleep(0)
|
|
||||||
self.assertEquals(timer_fired, [])
|
|
||||||
|
|
||||||
def test_reentrant(self):
|
|
||||||
pool = pools.CoroutinePool(0,1)
|
|
||||||
def reenter():
|
|
||||||
waiter = pool.execute(lambda a: a, 'reenter')
|
|
||||||
self.assertEqual('reenter', waiter.wait())
|
|
||||||
|
|
||||||
outer_waiter = pool.execute(reenter)
|
|
||||||
outer_waiter.wait()
|
|
||||||
|
|
||||||
evt = coros.event()
|
|
||||||
def reenter_async():
|
|
||||||
pool.execute_async(lambda a: a, 'reenter')
|
|
||||||
evt.send('done')
|
|
||||||
|
|
||||||
pool.execute_async(reenter_async)
|
|
||||||
evt.wait()
|
|
||||||
|
|
||||||
def test_horrible_main_loop_death(self):
|
|
||||||
# testing the case that causes the run_forever
|
|
||||||
# method to exit unwantedly
|
|
||||||
pool = pools.CoroutinePool(min_size=1, max_size=1)
|
|
||||||
def crash(*args, **kw):
|
|
||||||
raise RuntimeError("Whoa")
|
|
||||||
class FakeFile(object):
|
|
||||||
write = crash
|
|
||||||
|
|
||||||
# we're going to do this by causing the traceback.print_exc in
|
|
||||||
# safe_apply to raise an exception and thus exit _main_loop
|
|
||||||
normal_err = sys.stderr
|
|
||||||
try:
|
|
||||||
sys.stderr = FakeFile()
|
|
||||||
waiter = pool.execute(crash)
|
|
||||||
self.assertRaises(RuntimeError, waiter.wait)
|
|
||||||
# the pool should have something free at this point since the
|
|
||||||
# waiter returned
|
|
||||||
self.assertEqual(pool.free(), 1)
|
|
||||||
# shouldn't block when trying to get
|
|
||||||
t = api.exc_after(0.1, api.TimeoutError)
|
|
||||||
self.assert_(pool.get())
|
|
||||||
t.cancel()
|
|
||||||
finally:
|
|
||||||
sys.stderr = normal_err
|
|
||||||
|
|
||||||
def test_track_events(self):
|
|
||||||
pool = pools.CoroutinePool(track_events=True)
|
|
||||||
for x in range(6):
|
|
||||||
pool.execute(lambda n: n, x)
|
|
||||||
for y in range(6):
|
|
||||||
pool.wait()
|
|
||||||
|
|
||||||
def test_track_slow_event(self):
|
|
||||||
pool = pools.CoroutinePool(track_events=True)
|
|
||||||
def slow():
|
|
||||||
api.sleep(0.1)
|
|
||||||
return 'ok'
|
|
||||||
pool.execute(slow)
|
|
||||||
self.assertEquals(pool.wait(), 'ok')
|
|
||||||
|
|
||||||
def test_channel_smash(self):
|
|
||||||
# The premise is that the coroutine in the pool exhibits an
|
|
||||||
# interest in receiving data from the channel, but then times
|
|
||||||
# out and gets recycled, so it ceases to care about what gets
|
|
||||||
# sent over the channel. The pool should be able to tell the
|
|
||||||
# channel about the sudden change of heart, or else, when we
|
|
||||||
# eventually do send something into the channel it will catch
|
|
||||||
# the coroutine pool's coroutine in an awkward place, losing
|
|
||||||
# the data that we're sending.
|
|
||||||
from eventlet import pools
|
|
||||||
pool = pools.CoroutinePool(min_size=1, max_size=1)
|
|
||||||
tp = pools.TokenPool(max_size=1)
|
|
||||||
token = tp.get() # empty pool
|
|
||||||
def do_receive(tp):
|
|
||||||
api.exc_after(0, RuntimeError())
|
|
||||||
try:
|
|
||||||
t = tp.get()
|
|
||||||
self.fail("Shouldn't have recieved anything from the pool")
|
|
||||||
except RuntimeError:
|
|
||||||
return 'timed out'
|
|
||||||
|
|
||||||
# the execute makes the pool expect that coroutine, but then
|
|
||||||
# immediately cuts bait
|
|
||||||
e1 = pool.execute(do_receive, tp)
|
|
||||||
self.assertEquals(e1.wait(), 'timed out')
|
|
||||||
|
|
||||||
# the pool can get some random item back
|
|
||||||
def send_wakeup(tp):
|
|
||||||
tp.put('wakeup')
|
|
||||||
api.spawn(send_wakeup, tp)
|
|
||||||
|
|
||||||
# now we ask the pool to run something else, which should not
|
|
||||||
# be affected by the previous send at all
|
|
||||||
def resume():
|
|
||||||
return 'resumed'
|
|
||||||
e2 = pool.execute(resume)
|
|
||||||
self.assertEquals(e2.wait(), 'resumed')
|
|
||||||
|
|
||||||
# we should be able to get out the thing we put in there, too
|
|
||||||
self.assertEquals(tp.get(), 'wakeup')
|
|
||||||
|
|
||||||
def test_channel_death(self):
|
|
||||||
# In here, we have a coroutine trying to receive data from a
|
|
||||||
# channel, but timing out immediately and dying. The channel
|
|
||||||
# should be smart enough to not try to send data to a dead
|
|
||||||
# coroutine, because if it tries to, it'll lose the data.
|
|
||||||
from eventlet import pools
|
|
||||||
tp = pools.TokenPool(max_size=1)
|
|
||||||
token = tp.get()
|
|
||||||
e1 = coros.event()
|
|
||||||
def do_receive(evt, tp):
|
|
||||||
api.exc_after(0, RuntimeError())
|
|
||||||
try:
|
|
||||||
t = tp.get()
|
|
||||||
evt.send(t)
|
|
||||||
except RuntimeError:
|
|
||||||
evt.send('timed out')
|
|
||||||
|
|
||||||
# the execute gets the pool to add a waiter, but then kills
|
|
||||||
# itself off
|
|
||||||
api.spawn(do_receive, e1, tp)
|
|
||||||
self.assertEquals(e1.wait(), 'timed out')
|
|
||||||
|
|
||||||
def send_wakeup(tp):
|
|
||||||
tp.put('wakeup')
|
|
||||||
api.spawn(send_wakeup, tp)
|
|
||||||
|
|
||||||
# should be able to retrieve the message
|
|
||||||
self.assertEquals(tp.get(), 'wakeup')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
tests.main()
|
tests.main()
|
||||||
|
|
||||||
|
@@ -1,30 +1,27 @@
|
|||||||
"""\
|
# @author Donovan Preston, Aaron Brashears
|
||||||
@file processes_test.py
|
#
|
||||||
@author Donovan Preston, Aaron Brashears
|
# 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.
|
||||||
|
|
||||||
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 sys
|
import sys
|
||||||
|
|
||||||
from greentest import tests
|
from greentest import tests
|
||||||
from eventlet import api
|
|
||||||
from eventlet import processes
|
from eventlet import processes
|
||||||
|
|
||||||
class TestEchoPool(tests.TestCase):
|
class TestEchoPool(tests.TestCase):
|
||||||
|
@@ -26,6 +26,7 @@ Usage: %prog program [args]
|
|||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import codecs
|
||||||
try:
|
try:
|
||||||
import sqlite3
|
import sqlite3
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -63,7 +64,7 @@ def main():
|
|||||||
print arg
|
print arg
|
||||||
returncode = os.system(arg)>>8
|
returncode = os.system(arg)>>8
|
||||||
print arg, 'finished with code', returncode
|
print arg, 'finished with code', returncode
|
||||||
stdout = file(output_name).read()
|
stdout = codecs.open(output_name, mode='r', encoding='utf-8', errors='replace').read().replace('\x00', '?')
|
||||||
if not debug:
|
if not debug:
|
||||||
if returncode==1:
|
if returncode==1:
|
||||||
pass
|
pass
|
||||||
|
@@ -37,7 +37,7 @@ COMMAND = sys.executable + ' ./record_results.py ' + sys.executable + ' ./with_t
|
|||||||
PARSE_PERIOD = 10
|
PARSE_PERIOD = 10
|
||||||
|
|
||||||
# the following aren't in the default list unless --all option present
|
# the following aren't in the default list unless --all option present
|
||||||
NOT_HUBS = set(['nginx'])
|
NOT_HUBS = set()
|
||||||
NOT_REACTORS = set(['wxreactor', 'glib2reactor', 'gtk2reactor'])
|
NOT_REACTORS = set(['wxreactor', 'glib2reactor', 'gtk2reactor'])
|
||||||
NOT_TESTS = set()
|
NOT_TESTS = set()
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import sys
|
|
||||||
from eventlet import pool, coros, api
|
from eventlet import pool, coros, api
|
||||||
from greentest import LimitedTestCase
|
from greentest import LimitedTestCase
|
||||||
from unittest import main
|
from unittest import main
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from greentest import exit_unless_twisted, LimitedTestCase
|
from greentest import exit_unless_twisted
|
||||||
exit_unless_twisted()
|
exit_unless_twisted()
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
@@ -188,53 +188,6 @@ class TestGreenTransport_bufsize1(TestGreenTransport):
|
|||||||
# self.assertEqual('', self.conn.recv())
|
# self.assertEqual('', self.conn.recv())
|
||||||
#
|
#
|
||||||
|
|
||||||
# class TestHalfClose_TCP(LimitedTestCase):
|
|
||||||
#
|
|
||||||
# def _test_server(self, conn):
|
|
||||||
# conn.write('hello')
|
|
||||||
# conn.loseWriteConnection()
|
|
||||||
# self.assertRaises(pr.ConnectionDone, conn.write, 'hey')
|
|
||||||
# data = conn.read()
|
|
||||||
# self.assertEqual('bye', data)
|
|
||||||
# conn.loseConnection()
|
|
||||||
# self.assertRaises(ConnectionDone, conn._wait)
|
|
||||||
# self.check.append('server')
|
|
||||||
#
|
|
||||||
# def setUp(self):
|
|
||||||
# LimitedTestCase.setUp(self)
|
|
||||||
# self.factory = pr.SpawnFactory(self._test_server)
|
|
||||||
# self.port = reactor.listenTCP(0, self.factory)
|
|
||||||
# self.conn = pr.GreenClientCreator(reactor).connectTCP('localhost', self.port.getHost().port)
|
|
||||||
# self.port.stopListening()
|
|
||||||
# self.check = []
|
|
||||||
#
|
|
||||||
# def test(self):
|
|
||||||
# conn = self.conn
|
|
||||||
# data = conn.read()
|
|
||||||
# self.assertEqual('hello', data)
|
|
||||||
# conn.write('bye')
|
|
||||||
# conn.loseWriteConnection()
|
|
||||||
# self.assertRaises(pr.ConnectionDone, conn.write, 'hoy')
|
|
||||||
# self.factory.waitall()
|
|
||||||
# self.assertRaises(ConnectionDone, conn._wait)
|
|
||||||
# assert self.check == ['server']
|
|
||||||
#
|
|
||||||
# class TestHalfClose_TLS(TestHalfClose_TCP):
|
|
||||||
#
|
|
||||||
# def setUp(self):
|
|
||||||
# LimitedTestCase.setUp(self)
|
|
||||||
# from gnutls.crypto import X509PrivateKey, X509Certificate
|
|
||||||
# from gnutls.interfaces.twisted import X509Credentials
|
|
||||||
# cert = X509Certificate(open('gnutls_valid.crt').read())
|
|
||||||
# key = X509PrivateKey(open('gnutls_valid.key').read())
|
|
||||||
# server_credentials = X509Credentials(cert, key)
|
|
||||||
# self.factory = pr.SpawnFactory(self._test_server)
|
|
||||||
# self.port = reactor.listenTLS(0, self.factory, server_credentials)
|
|
||||||
# self.conn = pr.GreenClientCreator(reactor).connectTLS('localhost', self.port.getHost().port, X509Credentials())
|
|
||||||
# self.port.stopListening()
|
|
||||||
# self.check = []
|
|
||||||
#
|
|
||||||
|
|
||||||
if socket is not None:
|
if socket is not None:
|
||||||
|
|
||||||
class TestUnbufferedTransport_socketserver(TestUnbufferedTransport):
|
class TestUnbufferedTransport_socketserver(TestUnbufferedTransport):
|
||||||
@@ -275,7 +228,6 @@ try:
|
|||||||
import gnutls.interfaces.twisted
|
import gnutls.interfaces.twisted
|
||||||
except ImportError:
|
except ImportError:
|
||||||
del TestTLSError
|
del TestTLSError
|
||||||
del TestHalfClose_TLS
|
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@@ -1,27 +1,24 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file tests.py
|
# @brief Indirection layer for tests in case we want to fix unittest.
|
||||||
@author Donovan Preston
|
#
|
||||||
@brief Indirection layer for tests in case we want to fix unittest.
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
@@ -44,24 +41,24 @@ def find_command(command):
|
|||||||
if os.access(p, os.X_OK):
|
if os.access(p, os.X_OK):
|
||||||
return p
|
return p
|
||||||
raise IOError(errno.ENOENT, 'Command not found: %r' % command)
|
raise IOError(errno.ENOENT, 'Command not found: %r' % command)
|
||||||
|
|
||||||
def run_all_tests(test_files = doc_test_files):
|
def run_all_tests(test_files = doc_test_files):
|
||||||
""" Runs all the unit tests, returning immediately after the
|
""" Runs all the unit tests, returning immediately after the
|
||||||
first failed test.
|
first failed test.
|
||||||
|
|
||||||
Returns true if the tests all succeeded. This method is really much longer
|
Returns true if the tests all succeeded. This method is really much longer
|
||||||
than it ought to be.
|
than it ought to be.
|
||||||
"""
|
"""
|
||||||
eventlet_dir = os.path.realpath(os.path.dirname(__file__))
|
eventlet_dir = os.path.realpath(os.path.dirname(__file__))
|
||||||
if eventlet_dir not in sys.path:
|
if eventlet_dir not in sys.path:
|
||||||
sys.path.append(eventlet_dir)
|
sys.path.append(eventlet_dir)
|
||||||
|
|
||||||
# add all _test files as a policy
|
# add all _test files as a policy
|
||||||
import glob
|
import glob
|
||||||
test_files += [os.path.splitext(os.path.basename(x))[0]
|
test_files += [os.path.splitext(os.path.basename(x))[0]
|
||||||
for x in glob.glob(os.path.join(eventlet_dir, "*_test.py"))]
|
for x in glob.glob(os.path.join(eventlet_dir, "*_test.py"))]
|
||||||
test_files.sort()
|
test_files.sort()
|
||||||
|
|
||||||
for test_file in test_files:
|
for test_file in test_files:
|
||||||
print "-=", test_file, "=-"
|
print "-=", test_file, "=-"
|
||||||
try:
|
try:
|
||||||
@@ -69,21 +66,21 @@ def run_all_tests(test_files = doc_test_files):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
print "Unable to import %s, skipping" % test_file
|
print "Unable to import %s, skipping" % test_file
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if test_file.endswith('_test'):
|
if test_file.endswith('_test'):
|
||||||
# gawd, unittest, why you make it so difficult to just run some tests!
|
# gawd, unittest, why you make it so difficult to just run some tests!
|
||||||
suite = unittest.findTestCases(test_module)
|
suite = unittest.findTestCases(test_module)
|
||||||
result = unittest.TextTestRunner().run(suite)
|
result = unittest.TextTestRunner().run(suite)
|
||||||
if not result.wasSuccessful():
|
if not result.wasSuccessful():
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
failures, tests = doctest.testmod(test_module)
|
failures, tests = doctest.testmod(test_module)
|
||||||
if failures:
|
if failures:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
print "OK"
|
print "OK"
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
run_all_tests()
|
run_all_tests()
|
||||||
|
@@ -1,26 +1,23 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file timer_test.py
|
#
|
||||||
@author Donovan Preston
|
# Copyright (c) 2006-2007, Linden Research, Inc.
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
Copyright (c) 2006-2007, Linden Research, Inc.
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
# in the Software without restriction, including without limitation the rights
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
in the Software without restriction, including without limitation the rights
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# furnished to do so, subject to the following conditions:
|
||||||
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 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,
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# THE SOFTWARE.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@@ -1,27 +1,22 @@
|
|||||||
"""\
|
# Copyright (c) 2007, Linden Research, Inc.
|
||||||
@file tpool_test.py
|
# Copyright (c) 2007, IBM Corp.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
Copyright (c) 2007, Linden Research, Inc.
|
import time
|
||||||
Copyright (c) 2007, IBM Corp.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os, socket, time, threading
|
|
||||||
from eventlet import coros, api, tpool
|
from eventlet import coros, api, tpool
|
||||||
from greentest import tests
|
from greentest import tests
|
||||||
|
|
||||||
from eventlet.tpool import erpc
|
|
||||||
from sys import stdout
|
from sys import stdout
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
@@ -1,26 +1,24 @@
|
|||||||
"""\
|
# @author Donovan Preston
|
||||||
@file wsgi_test.py
|
#
|
||||||
@author Donovan Preston
|
# 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.
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cgi
|
import cgi
|
||||||
import os
|
import os
|
||||||
@@ -28,7 +26,6 @@ import os
|
|||||||
from eventlet import api
|
from eventlet import api
|
||||||
from eventlet import wsgi
|
from eventlet import wsgi
|
||||||
from eventlet import processes
|
from eventlet import processes
|
||||||
from eventlet import util
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
@@ -43,7 +40,7 @@ def hello_world(env, start_response):
|
|||||||
if env['PATH_INFO'] == 'notexist':
|
if env['PATH_INFO'] == 'notexist':
|
||||||
start_response('404 Not Found', [('Content-type', 'text/plain')])
|
start_response('404 Not Found', [('Content-type', 'text/plain')])
|
||||||
return ["not found"]
|
return ["not found"]
|
||||||
|
|
||||||
start_response('200 OK', [('Content-type', 'text/plain')])
|
start_response('200 OK', [('Content-type', 'text/plain')])
|
||||||
return ["hello world"]
|
return ["hello world"]
|
||||||
|
|
||||||
@@ -123,7 +120,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
def test_001_server(self):
|
def test_001_server(self):
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
||||||
result = fd.read()
|
result = fd.read()
|
||||||
@@ -135,7 +132,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
def test_002_keepalive(self):
|
def test_002_keepalive(self):
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
read_http(sock)
|
read_http(sock)
|
||||||
@@ -147,7 +144,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
# This should go in greenio_test
|
# This should go in greenio_test
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
cancel = api.exc_after(1, RuntimeError)
|
cancel = api.exc_after(1, RuntimeError)
|
||||||
@@ -189,7 +186,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
status = result.split(' ')[1]
|
status = result.split(' ')[1]
|
||||||
self.assertEqual(status, '414')
|
self.assertEqual(status, '414')
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
def test_007_get_arg(self):
|
def test_007_get_arg(self):
|
||||||
# define a new handler that does a get_arg as well as a read_body
|
# define a new handler that does a get_arg as well as a read_body
|
||||||
def new_app(env, start_response):
|
def new_app(env, start_response):
|
||||||
@@ -201,24 +198,24 @@ class TestHttpd(tests.TestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
request = '\r\n'.join((
|
request = '\r\n'.join((
|
||||||
'POST / HTTP/1.0',
|
'POST / HTTP/1.0',
|
||||||
'Host: localhost',
|
'Host: localhost',
|
||||||
'Content-Length: 3',
|
'Content-Length: 3',
|
||||||
'',
|
'',
|
||||||
'a=a'))
|
'a=a'))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write(request)
|
fd.write(request)
|
||||||
|
|
||||||
# send some junk after the actual request
|
# send some junk after the actual request
|
||||||
fd.write('01234567890123456789')
|
fd.write('01234567890123456789')
|
||||||
reqline, headers, body = read_http(sock)
|
reqline, headers, body = read_http(sock)
|
||||||
self.assertEqual(body, 'a is a, body is a=a')
|
self.assertEqual(body, 'a is a, body is a=a')
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
def test_008_correctresponse(self):
|
def test_008_correctresponse(self):
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
response_line_200,_,_ = read_http(sock)
|
response_line_200,_,_ = read_http(sock)
|
||||||
@@ -233,7 +230,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
self.site.application = chunked_app
|
self.site.application = chunked_app
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
self.assert_('Transfer-Encoding: chunked' in fd.read())
|
self.assert_('Transfer-Encoding: chunked' in fd.read())
|
||||||
@@ -242,7 +239,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
self.site.application = chunked_app
|
self.site.application = chunked_app
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
self.assert_('Transfer-Encoding: chunked' not in fd.read())
|
self.assert_('Transfer-Encoding: chunked' not in fd.read())
|
||||||
@@ -251,7 +248,7 @@ class TestHttpd(tests.TestCase):
|
|||||||
self.site.application = big_chunks
|
self.site.application = big_chunks
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('127.0.0.1', 12346))
|
('127.0.0.1', 12346))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makeGreenFile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
headers = fd.readuntil('\r\n\r\n')
|
headers = fd.readuntil('\r\n\r\n')
|
||||||
@@ -273,9 +270,9 @@ class TestHttpd(tests.TestCase):
|
|||||||
|
|
||||||
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
|
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')
|
private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
|
||||||
|
|
||||||
sock = api.ssl_listener(('', 4201), certificate_file, private_key_file)
|
sock = api.ssl_listener(('', 4201), certificate_file, private_key_file)
|
||||||
|
|
||||||
api.spawn(wsgi.server, sock, wsgi_app)
|
api.spawn(wsgi.server, sock, wsgi_app)
|
||||||
|
|
||||||
result = httpc.post("https://localhost:4201/foo", "abc")
|
result = httpc.post("https://localhost:4201/foo", "abc")
|
||||||
@@ -295,6 +292,20 @@ class TestHttpd(tests.TestCase):
|
|||||||
res = httpc.get("https://localhost:4202/foo")
|
res = httpc.get("https://localhost:4202/foo")
|
||||||
self.assertEquals(res, '')
|
self.assertEquals(res, '')
|
||||||
|
|
||||||
|
def test_013_empty_return(self):
|
||||||
|
from eventlet import httpc
|
||||||
|
def wsgi_app(environ, start_response):
|
||||||
|
start_response("200 OK", [])
|
||||||
|
return [""]
|
||||||
|
|
||||||
|
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')
|
||||||
|
sock = api.ssl_listener(('', 4202), certificate_file, private_key_file)
|
||||||
|
api.spawn(wsgi.server, sock, wsgi_app)
|
||||||
|
|
||||||
|
res = httpc.get("https://localhost:4202/foo")
|
||||||
|
self.assertEquals(res, '')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
tests.main()
|
tests.main()
|
||||||
|
Reference in New Issue
Block a user